英文:
What are some similar alternatives to using classmethod and property decorators together?
问题
有哪些类似的替代方法可以替代同时使用classmethod和property装饰器?
在Python 3.11及更高版本中,不再支持将它们结合使用,详情请参考:https://docs.python.org/3.11/library/functions.html#classmethod
我有如下的代码:
class Bike:
@classmethod
@property
def tire_type(cls) -> tire_type.Road:
return tire_type.Road
from . import tire_type
tire_type导入必须放在最后,因为它与当前模块存在循环依赖关系。
有哪些选项可以为Bike类提供tire属性,而不将这两个装饰器组合在一起?
我还希望在VSCode中正确显示tire_type的类型提示。
英文:
What are some similar alternatives to using classmethod and property decorators together?
In python 3.11 and later, combining them is no longer supported per: https://docs.python.org/3.11/library/functions.html#classmethod
I have code like so:
class Bike:
@classmethod
@property
def tire_type(cls) -> tire_type.Road:
return tire_type.Road
from . import tire_type
tire_type import must be last because it has a cyclic dependency on the current module.
What are some options for providing the tire property in the Bike class that does not combine the two decorators?
I also want the tire_type type hint to show up correctly in vscode.
答案1
得分: 2
你可以随时实现自己的描述符。这是一个简单的描述符,假设你要装饰的方法是一个“getter”:
class classproperty:
def __init__(self, method):
self.method = method
def __get__(self, obj, cls=None):
if cls is None:
cls = type(obj)
return self.method(cls)
class Foo:
bar = 42
@classproperty
def baz(cls):
return cls.bar * 2
class FooSpecial(Foo):
bar = 11
Foo.baz
84
FooSpecial.baz
22
classmethod
和property
都是作为描述符实现的。你可以阅读有关描述符协议如何工作的更多信息在描述符指南中。该指南实际上展示了property
和classmethod
的纯Python实现,如果需要进一步了解,可以参考这些内容。
英文:
You can always implement your own descriptor. Here is a bare-bones one that assumes the method you are decorating is a "getter":
>>> class classproperty:
... def __init__(self, method):
... self.method = method
... def __get__(self, obj, cls=None):
... if cls is None:
... cls = type(obj)
... return self.method(cls)
...
>>> class Foo:
... bar = 42
... @classproperty
... def baz(cls):
... return cls.bar * 2
...
>>> class FooSpecial(Foo):
... bar = 11
...
>>> Foo.baz
84
>>> FooSpecial.baz
22
Both classmethod
and property
are implemented as descriptors. You can read more about how the descriptor protocol works in the Descriptor HowTo which actually shows pure python implementations of property
and classmethod
which you can consult if you need to elaborate on the above.
答案2
得分: 0
以下是翻译好的部分:
- 编写一个自定义描述符,使用泛型来返回包装的类型
- 使方法成为类方法,这保持了类访问,但需要使用
()
- 将其设置为静态方法,但需要使用
()
- 将类设置为数据类,并使用 default_factory 返回所需的类
首选选项是1或4,因为它们不需要 ()
并且允许对属性进行类型描述以及在访问 Bike 或实例化它时延迟评估属性。
英文:
Some options are
- Write a custom descriptor that uses a generic to return the wrapped type
T = typing.TypeVar('T')
class classprop(typing.Generic[T]):
def __init__(self, method: typing.Callable[..., T]):
self.method = method
functools.update_wrapper(self, method) # type: ignore
def __get__(self, obj, cls=None) -> T:
if cls is None:
cls = type(obj)
return self.method(cls)
class Bike:
@classprop
def tire_type(cls) -> typing.Type[tire_type.Road]:
return tire_type.Road
print(Bike.tire_type)
- Make the method classmethod only, this keeps class access but
()
are required - Make it staticmethod but
()
are required - Make the class a dataclass and use default_factory to return the desired class
@dataclasses.dataclass
class Bike
tire_type: typing.Type[tire_type.Road] = dataclasses.field(
default_factory=lambda: tire_type.Road
)
print(Bike().tire_type)
Option 1 or 4 is preferred because it does not need ()
and it allows a type discriptions of the property and delayed evaluation of the property later when accessing Bike or instantiating it
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论