[英]Python - descriptor on class to *set* attributes
I've been attempting to get __get__
__set__
and __delete__
magic method working with decorators put onto the class's method (not the instance). 我一直在尝试将
__get__
__set__
和__delete__
魔术方法与装饰器一起使用,将其放入类的方法(而不是实例)中。 I am entirely unable to get anything other than __get__
to work / be called. 除了
__get__
,我完全无法工作/被打电话。 I have tried about every combination / arrangement of code but the most recent looks like this: 我已经尝试过代码的每种组合/排列,但是最近的样子是这样的:
def my_decorator5(func: Callable[..., R]) -> R:
""" Decorate func while preserving the signature. """
print(f"{'*'*40} my_decorator main")
class Wrap(object):
def __init__(self, clsmethod) -> None:
print(f"{'*'*40} is __init__")
self.value = None
self.func = func
self.clsmethod = clsmethod
self.func_name = func.__name__
def __get__(self, obj, cls) -> R:
print(f"{'*'*40} {cls} is getting")
owner = cls
self.value = func(cls)
return cast(R, self.value)
def __set__(self, cls, newval) -> None:
print(f"{'*'*40} {cls} is setting")
self.value = newval
def __set_name__(self, cls, newval) -> None:
print(f"{'*'*40} {self} is __set_name__")
print(f"{'*'*40} {cls} is __set_name__")
print(f"{'*'*40} {newval} is __set_name__")
def __delete__(self, cls) -> None:
print(f"{'*'*40} {cls} is deleting")
delattr(self, "value")
def __delattr__(self, key) -> None:
print(f"{'*'*40} {self} is __delattr__")
I have test code : 我有测试代码:
class foo3:
@my_decorator5
def foo3_str(self) -> str:
return "Original foo3 str"
print(f"\n{'*'*80}\n{'*'*35} STARTING {'*'*35}\n{'*'*80}\n")
print(f"\n--{dir(foo3.foo3_str)}--\n")
print(f"\n--{foo3.foo3_str.__class__}--\n")
print(f"\n--{dir(foo3.__dict__['foo3_str'])}--\n")
print(f"\n--\tatrr: {foo3.foo3_str.__class__}\n\t__dict__{foo3.__dict__['foo3_str'].__class__}\n\t{foo3.__dict__['foo3_str'].__set__(1,2)}--\n")
print(">>>> getting >>>>")
print(f"foo3_str ==> {foo3.foo3_str}")
print(f"<<<< got foo3_str <<<<")
print("\n")
print(f"\n--\tatrr: {foo3.foo3_str.__class__}\n\t__dict__{foo3.__dict__['foo3_str'].__class__}--\n")
print(">>>> settting >>>>")
foo3.foo3_str = "Set foo3 str"
print("<<<< set foo3_str <<<<")
print(f"\n--\tatrr: {foo3.foo3_str.__class__}\n\t__dict__{foo3.__dict__['foo3_str'].__class__}--\n")
print("\n")
print(f"foo3_str ==> {foo3.foo3_str}")
print("\n")
print(f">>>> deleting foo3_str")
del foo3.foo3_str
print(f"<<<< deleted foo3_str <<<<")
print("\n")
print(">>>> getting")
try:
print(f"foo3_str ==> {foo3.foo3_str}")
foo3.foo3_str = "Eric"
except AttributeError:
print("...foo3.foo3_str AttributeError")
print(" <<<< getting foo3_str")
My output with this is: 我的输出是:
**************************************** my_decorator main
**************************************** is __init__
**************************************** <__main__.my_decorator5.<locals>.Wrap object at 0x000002D185BA6470> is __set_name__
**************************************** <class '__main__.foo3'> is __set_name__
**************************************** foo3_str is __set_name__
********************************************************************************
*********************************** STARTING ***********************************
********************************************************************************
**************************************** <class '__main__.foo3'> is getting
--['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']--
**************************************** <class '__main__.foo3'> is getting
--<class 'str'>--
--['__class__', '__delattr__', '__delete__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__set__', '__set_name__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'clsmethod', 'func', 'func_name', 'value']--
**************************************** <class '__main__.foo3'> is getting
**************************************** 1 is setting
-- atrr: <class 'str'>
__dict__<class '__main__.my_decorator5.<locals>.Wrap'>
None--
>>>> getting >>>>
**************************************** <class '__main__.foo3'> is getting
foo3_str ==> Original foo3 str
<<<< got foo3_str <<<<
**************************************** <class '__main__.foo3'> is getting
-- atrr: <class 'str'>
__dict__<class '__main__.my_decorator5.<locals>.Wrap'>--
>>>> settting >>>>
<<<< set foo3_str <<<<
-- atrr: <class 'str'>
__dict__<class 'str'>--
foo3_str ==> Set foo3 str
>>>> deleting foo3_str
<<<< deleted foo3_str <<<<
>>>> getting
...foo3.foo3_str AttributeError
>> getting foo3_str
**************************************** my_decorator main
When the line 当行
foo3.foo3_str = "Set foo3 str"
I would have expected to see 我本来希望看到
**************************************** ... is setting
But instead the __set__
function is entirely ignored and the class's dict is set to an actual str
type. 但是相反,
__set__
函数被完全忽略,并且该类的dict被设置为实际的str
类型。
Is it possible to have get , set , delete on a decorator for a class property , or without an instance will only the __get__
and never the __set__
and __detele__
be run? 是否有可能在针对类属性的装饰器上进行get,set,delete,或者没有实例将仅运行
__get__
而永远不会运行__set__
和__detele__
?
A descriptor's __set__
method is only called if you assign to its name in an instance. 仅当在实例中为其指定描述符名称时,才调用该描述符的
__set__
方法。 If you assign to the class directly, you'll overwrite the descriptor (without __set__
being called). 如果直接分配给该类,
__set__
覆盖描述符(不__set__
)。 In contrast, the __get__
method gets called for lookups on either the class or an instance. 相反,在类或实例上都将使用
__get__
方法进行查找。 Some descriptors (such as property
) are programmed to to return themselves when called on the class, so it may not be as evident that their __get__
method did in fact run. 某些描述符(例如
property
)被编程为在类上调用时返回自身,因此它们的__get__
方法实际上并未运行可能并不那么明显。
If you want to use descriptors to control access to a class variable, you need to put your descriptor in a metaclass (the class of the class object). 如果要使用描述符来控制对类变量的访问,则需要将描述符放入元类(类对象的类)中。 Here's a basic example, using a
property
to control a class variable named foo
: 这是一个基本示例,使用
property
控制名为foo
的类变量:
class Meta(type):
_foo = "original foo value"
@property
def foo(cls):
print("getting foo")
return cls._foo
@foo.setter
def foo(cls, value):
print("setting foo")
cls._foo = value
class Klass(metaclass=Meta):
pass
# this invokes the property methods
print(Klass.foo)
Klass.foo = "new foo value"
print(Klass.foo)
# this won't work, the property is not accessible via an instance of Klass
obj = Klass()
obj.foo # raises an AttributeError
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.