python通用添加了键入功能以扩展现有类型错误地键入
我有兴趣创建一个通用,以在Python中的不同类型中添加固定功能。我有一个半工作解决方案,但这是有问题的。
这是我正在尝试的简化版本:
from __future__ import annotations
from typing import Generic, Set, TypeVar, Type, Callable
def CreateTaggedType(base_type: type):
T = TypeVar("T")
class TaggedTypeGenerator(Generic[T]):
def __init__(self):
pass
def tag_provider(self, parent: Type[T]):
class Imp(parent):
def __init__(self, **args):
super().__init__(**args)
self.tags: Set[str] = set()
def add_tag(self, tag):
self.tags.add(tag)
def remove_tag(self, tag):
if tag in self.tags:
self.tags.remove(tag)
return True
return False
return Imp
return TaggedTypeGenerator[base_type]().tag_provider(parent=base_type)
class Counter:
def __init__(self, count=0):
self.count = count
def inc(self):
self.count += 1
return self.count
# Create an alias for a new type of tagged Counter
TaggedCounter = CreateTaggedType(Counter)
tc = TaggedCounter(count=2)
print(tc.inc()) # should print "3"
tc.add_tag("foo")
print(tc.remove_tag("bar")) # should print "False"
print(tc.remove_tag("foo")) # should print "True"
print(tc.inc()) # should print "4"
输出:
3
False
True
4
从技术上讲,这有效,但是类型未正确推断。 这会导致自动完成无法正常工作。我只获得添加功能的自动完成,而不是与基类相关的任何功能。
我该如何做才能正确?
我使用abc.abcmeta
尝试了这种变化,但无效:
from __future__ import annotations
import abc
from typing import Callable, Generic, Set, Type, TypeVar
T = TypeVar("T")
class TaggedTypeGenerator(Generic[T]):
def __init__(self, parent: Type[T]):
self.parent = parent
class _imp_(self.parent):
def __init__(self, **args):
super().__init__(**args)
self.tags: Set[str] = set()
def add_tag(self, tag):
self.tags.add(tag)
def remove_tag(self, tag):
if tag in self.tags:
self.tags.remove(tag)
return True
return False
self.Imp = _imp_
class Counter:
def __init__(self, count=0):
self.count = count
def inc(self):
self.count += 1
return self.count
def CreateTaggedTypeGenerator(base_type: T) -> TaggedTypeGenerator[T]:
return TaggedTypeGenerator[base_type](base_type)
# Create an alias for a new type of tagged Counter
TaggedCounterGererator = CreateTaggedTypeGenerator(Counter)
class counter_meta(metaclass=abc.ABCMeta):
pass
counter_meta.register(Counter)
@counter_meta.register
class TaggedCounter(TaggedCounterGererator.Imp):
pass
tc = TaggedCounter(count=2)
print(tc.inc()) # should print "3"
tc.add_tag("foo")
print(tc.remove_tag("bar")) # should print "False"
print(tc.remove_tag("foo")) # should print "True"
print(tc.inc()) # should print "4"
这也可以促进预期的输出。但是,这不仅不能解决打字问题,而且使情况变得更糟。这样,自动组件对于基类和添加功能不起作用。
任何建议都将受到欢迎。
注意:我的编辑是vs代码,我认为在这里没什么重要的,但是...
I am interested in creating a generic to add a fixed functionality to different types in python. I have a semi working solution, but it's tying is problematic.
Here's a simplified version of what I'm trying:
from __future__ import annotations
from typing import Generic, Set, TypeVar, Type, Callable
def CreateTaggedType(base_type: type):
T = TypeVar("T")
class TaggedTypeGenerator(Generic[T]):
def __init__(self):
pass
def tag_provider(self, parent: Type[T]):
class Imp(parent):
def __init__(self, **args):
super().__init__(**args)
self.tags: Set[str] = set()
def add_tag(self, tag):
self.tags.add(tag)
def remove_tag(self, tag):
if tag in self.tags:
self.tags.remove(tag)
return True
return False
return Imp
return TaggedTypeGenerator[base_type]().tag_provider(parent=base_type)
class Counter:
def __init__(self, count=0):
self.count = count
def inc(self):
self.count += 1
return self.count
# Create an alias for a new type of tagged Counter
TaggedCounter = CreateTaggedType(Counter)
tc = TaggedCounter(count=2)
print(tc.inc()) # should print "3"
tc.add_tag("foo")
print(tc.remove_tag("bar")) # should print "False"
print(tc.remove_tag("foo")) # should print "True"
print(tc.inc()) # should print "4"
The output:
3
False
True
4
Technically, this works, but the type isn't correctly inferred.
This causes auto-completion to not work properly. I only get aut-ocompletion for the added functionality, and not for anything related to the base class.
How can I make it so that the type is correct?
I tried this variation using abc.ABCMeta
with no effect:
from __future__ import annotations
import abc
from typing import Callable, Generic, Set, Type, TypeVar
T = TypeVar("T")
class TaggedTypeGenerator(Generic[T]):
def __init__(self, parent: Type[T]):
self.parent = parent
class _imp_(self.parent):
def __init__(self, **args):
super().__init__(**args)
self.tags: Set[str] = set()
def add_tag(self, tag):
self.tags.add(tag)
def remove_tag(self, tag):
if tag in self.tags:
self.tags.remove(tag)
return True
return False
self.Imp = _imp_
class Counter:
def __init__(self, count=0):
self.count = count
def inc(self):
self.count += 1
return self.count
def CreateTaggedTypeGenerator(base_type: T) -> TaggedTypeGenerator[T]:
return TaggedTypeGenerator[base_type](base_type)
# Create an alias for a new type of tagged Counter
TaggedCounterGererator = CreateTaggedTypeGenerator(Counter)
class counter_meta(metaclass=abc.ABCMeta):
pass
counter_meta.register(Counter)
@counter_meta.register
class TaggedCounter(TaggedCounterGererator.Imp):
pass
tc = TaggedCounter(count=2)
print(tc.inc()) # should print "3"
tc.add_tag("foo")
print(tc.remove_tag("bar")) # should print "False"
print(tc.remove_tag("foo")) # should print "True"
print(tc.inc()) # should print "4"
This also procudes the expected output. However, not only does this not solve the typing issue, it makes it worse. With this, auto-complete doesn't work for the base class and the added functions.
Any suggestions would are welcome.
NOTE: My editor is VS Code, I don't think it matters much here, but...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第一个解决方案将使自动完成几乎快乐:
现在这在运行时起作用,但是失败类型检查(因为
add_tag
和remove_tag
是动态添加的,并且对Checker不可见 - 但是所有其他方法可访问)。大概是自动完成的。类型您需要声明(这是
taggedMixin
和type [t]
)的亚型bretsection [taggedMixin,type [t]
>从打字理论的角度来看。关于交叉点的支持
类型的支持均未在mypy
中也没有实现,也没有在其他检查器中实现,例如pylance
(并且,更重要的是重要的是,不是由PEP添加到键入
,因此未批准Python本身)。相关的mypy问题
我不知道哪种类型的Checker可以使用VS代码(以及是否使用)它与自动完成有关)。看来他们有一个名为“ IntelliSense”的东西,它没有任何插件功能,因此这可能是关于自动完成和动态代码的故事的结尾。如果自动完成对您真的很重要(或者您不想玩
mypy
插件,并且只有几个具有该功能的课程),那么“现在总比没有好”,并且“明确的是比隐式更好。”:这既适用于自动完成和类型检查。另外,这几乎是干燥的:您只重复班级声明,这是相当合理的。我建议使用此实现也是最简单的,如果您没有数百个课程可以修改并且您的课程不是动态的。
请告诉我是否有理由在此处使用动态声明。另外,不要忘记
任何
,有时最好只是打破类型检查严格性以使代码更可读/有效。mypy
我可以详细说明:自定义插件。但是,这确实是特殊的事情,它主要用于第三方模块,这些模块可访问某些类型的类型,这些类型不可用“正常”打字表达 - 您可能不想使用插件删除,例如5类型错误:忽略它们(#类型:ignore
也是您的朋友!)将更简单更简单。只需发表评论,解释无知和文档类工厂即可明确提及动态属性。The first solution will make autocomplete almost happy:
Now this works at runtime, but fails type checking (because
add_tag
andremove_tag
are added dynamically and not visible to the checker - but all other methods are accessible). Probably autocomplete will think the same.Type you need to declare (which is subtype of both
TaggedMixin
andType[T]
) is calledIntersection[TaggedMixin, Type[T]]
from typing theory point of view. There was a large discussion around support forIntersection
type which is not implemented neither inmypy
nor in other checkers likepylance
(and, what's more important, is isn't added totyping
by PEP's, so is not approved for python itself).Related mypy issue
I don't know what type checker does VS Code use (and whether it is related to autocomplete). Looks like they have a thing called "IntelliSense" which doesn't have any plugin capabilities, so this is probably the end of the story about autocomplete and dynamic code together. If autocomplete is really important for you (or you don't want to play with
mypy
plugins and have just a couple of classes with that functionality), then "now is better than never" and "explicit is better than implicit":This will work both for autocomplete and type checking. Also this is almost DRY: you repeat only class declaration, which is fairly reasonable. I would recommend using this implementation is also the most simple, if you don't have hundreds of classes to modify and your classes are not dynamic.
Please tell me if there is a reason to use dynamic declarations here. Also, don't forget about
Any
, it is sometimes better just to break type checking strictness in order to make code more readable/efficient. There is (at least) one more solution formypy
I can elaborate on: custom plugin. However, it's really special thing, that is usable mostly for third-party modules that provide access to some types which are not expressible with "normal" typing - you probably don't want to use plugin to remove, say, 5 type errors: ignoring them (# type: ignore
is your friend too!) will be much simpler. Just leave a comment explaining ignorance and document class factory to explicitly mention dynamic attributes.