采用以下示例脚本:
class A(object):
@classmethod
def one(cls):
print("I am class")
@staticmethod
def two():
print("I am static")
class B(object):
one = A.one
two = A.two
B.one()
B.two()
Run Code Online (Sandbox Code Playgroud)
当我使用Python 2.7.11运行此脚本时,我得到:
I am class
Traceback (most recent call last):
File "test.py", line 17, in <module>
B.two()
TypeError: unbound method two() must be called with B instance as first argument (got nothing instead)
Run Code Online (Sandbox Code Playgroud)
似乎@classmethod装饰器在类中保留,但@staticmethod不是.
Python 3.4的行为符合预期:
I am class
I am static
Run Code Online (Sandbox Code Playgroud)
为什么Python2不能保留@staticmethod,是否有解决方法?
编辑:从课堂上取两个(并保留@staticmethod)似乎有效,但这对我来说似乎仍然很奇怪.
python static-methods class-method python-2.7 python-descriptors
@classmethod在 Python 3.9 中,我们获得了链接和@property合理创建类属性的能力。
class Foo:\n @property\n def instance_property(self):\n return "A regular property"\n\n @classmethod\n @property\n def class_property(cls):\n return "A class property"\nRun Code Online (Sandbox Code Playgroud)\n这是通过与描述符协议进行适当的交互来实现的@classmethod,这意味着一个人的前景不仅限于@property阳光下的任何描述符。一切都很好,直到发现该实现导致了“许多下游问题”,并在 Python 3.11 中弃用。
我已经阅读了一些关于弃用的GitHub 讨论,并且不会在这里抱怨我所说的仓促撤回仓促设计。事实上,类属性是人们想要的合理的东西,并且可以在 Python 3.9/3.10 中使用,但现在不能。发行说明建议如下:
\n\n\n要 \xe2\x80\x9cpass-through\xe2\x80\x9d 类方法,请考虑使用 Python 3.10 中添加的 __wrapped__ 属性。
\n
如果说这样的句子本身极其无益,那就不会引起争议。描述符协议不是普通用户需要或想要遇到的东西,因此@classmethod通过自定义实现与它们链接肯定是那些了解情况的人可以并且会花时间弄清楚如何在 3.11+ 中正确执行的操作。
但是对于那些不知道@property除了允许他们删除括号的东西之外还有什么的人来说,如何在 Python 3.11+ 中定义类属性,特别是如何做得好?
python properties python-3.x python-decorators python-descriptors
我经常发现我需要临时分配一些成员变量,例如
old_x = c.x
old_y = c.y
# keep c.z unchanged
c.x = new_x
c.y = new_y
do_something(c)
c.x = old_x
c.y = old_y
Run Code Online (Sandbox Code Playgroud)
但我希望我能简单地写一下
with c.x = new_x; c.y = new_y:
do_something(c)
Run Code Online (Sandbox Code Playgroud)
甚至
do_something(c with x = new_x; y = new_y)
Run Code Online (Sandbox Code Playgroud)
Python的装饰器或其他语言功能能够实现这种模式吗?(我可以c根据需要修改课程)
根据Python的文档,
带有
__set__()和__get__()定义的数据描述符总是覆盖实例字典中的重定义.
我理解这句话没有问题,但是有人可以为我澄清为什么会有这样的规则吗?毕竟,如果我想覆盖实例字典中的属性,我已经需要明确地执行(inst.__dict__["attr"] = val),因为天真inst.attr = val会调用描述符的__set__方法,这通常会覆盖实例字典中的属性.
编辑:为了说清楚,我理解发生了什么,我的问题是为什么这样的规则到位.
我经常看到这个:
def __get__(self, instance, owner=None):
Run Code Online (Sandbox Code Playgroud)
为什么有些人使用的默认值None的的owner参数?
这甚至可以在Python文档中完成:
descr.__get__(self, obj, type=None) --> value
Run Code Online (Sandbox Code Playgroud) 简单再现:
class VocalDescriptor(object):
def __get__(self, obj, objtype):
print('__get__, obj={}, objtype={}'.format(obj, objtype))
def __set__(self, obj, val):
print('__set__')
class B(object):
v = VocalDescriptor()
B.v # prints "__get__, obj=None, objtype=<class '__main__.B'>"
B.v = 3 # does not print "__set__", evidently does not trigger descriptor
B.v # does not print anything, we overwrote the descriptor
Run Code Online (Sandbox Code Playgroud)
这个问题有一个有效的重复项,但是没有回答重复项,作为学习练习,我对CPython源码进行了更多研究。警告:我进入了杂草。我真希望我能从知道这些水域的船长那里得到帮助。为了我自己的未来利益和未来读者的利益,我试图尽可能明确地追踪正在寻找的电话。
我已经看到很多墨水溅到了__getattribute__应用于描述符的行为上,例如查找优先级。Python的片断在“援引描述符”下方For classes, the machinery is in type.__getattribute__()...大致在我的脑海里同意我认为是相应的CPython的源中type_getattro,我找到了通过看“tp_slots”然后tp_getattro填充其中。B.v …
描述符协议工作正常但我仍然有一个问题我想解决.
我有一个描述符:
class Field(object):
def __init__(self, type_, name, value=None, required=False):
self.type = type_
self.name = "_" + name
self.required = required
self._value = value
def __get__(self, instance, owner):
return getattr(instance, self.name, self.value)
def __set__(self, instance, value):
if value:
self._check(value)
setattr(instance, self.name, value)
else:
setattr(instance, self.name, None)
def __delete__(self, instance):
raise AttributeError("Can't delete attribute")
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = value if value else self.type()
@property
def _types(self):
raise NotImplementedError
def _check(self, value):
if not isinstance(value, …Run Code Online (Sandbox Code Playgroud) 在Python 3中
class A(object):
attr = SomeDescriptor()
...
def somewhere(self):
# need to check is type of self.attr is SomeDescriptor()
desc = self.__class__.__dict__[attr_name]
return isinstance(desc, SomeDescriptor)
Run Code Online (Sandbox Code Playgroud)
有更好的方法吗?我不喜欢这个self.__class__.__dict__东西
在这个拉取请求中,似乎添加了对描述符的类型提示支持。
但是,似乎从未发布过最终的“正确”使用示例,也似乎从未将任何文档添加到typing模块或Mypy 中。
它看起来像的正确用法是像这样:
from typing import TypeVar
T = TypeVar('T')
V = TypeVar('V')
class classproperty():
def __init__(self, getter: Callable[[Type[T]], V]) -> None:
self.getter = getter
def __get__(self, instance: Optional[T], owner: Type[T]) -> V:
return self.getter(owner)
def forty_two(cls: Type) -> int:
return 42
class C:
forty_two: int = classproperty(forty_two)
Run Code Online (Sandbox Code Playgroud)
这似乎合乎逻辑,但我不知道这是否真的是正确的做事方式。
有没有这方面的文件?或者实际适用于合并版本的完整示例?
我可以在 Python 中以支持/尊重/理解其所有者的继承层次结构的方式实现通用描述符吗?
在代码中应该更清楚:
from typing import (
Generic, Optional, TYPE_CHECKING,
Type, TypeVar, Union, overload,
)
T = TypeVar("T", bound="A") # noqa
class Descr(Generic[T]):
@overload
def __get__(self: "Descr[T]", instance: None, owner: Type[T]) -> "Descr[T]": ...
@overload
def __get__(self: "Descr[T]", instance: T, owner: Type[T]) -> T: ...
def __get__(self: "Descr[T]", instance: Optional[T], owner: Type[T]) -> Union["Descr[T]", T]:
if instance is None:
return self
return instance
class A:
attr: int = 123
descr = Descr[T]() # I want to bind T here, …Run Code Online (Sandbox Code Playgroud) python ×10
descriptor ×4
python-3.x ×4
mypy ×2
python-2.7 ×2
type-hinting ×2
class-method ×1
cpython ×1
properties ×1