簡體   English   中英

Python-類的描述符以* set *屬性

[英]Python - descriptor on class to *set* attributes

我一直在嘗試將__get__ __set____delete__魔術方法與裝飾器一起使用,將其放入類的方法(而不是實例)中。 除了__get__ ,我完全無法工作/被打電話。 我已經嘗試過代碼的每種組合/排列,但是最近的樣子是這樣的:

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__")

我有測試代碼:

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_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

當行

foo3.foo3_str = "Set foo3 str"

我本來希望看到

**************************************** ... is setting

但是相反, __set__函數被完全忽略,並且該類的dict被設置為實際的str類型。

是否有可能在針對類屬性的裝飾器上進行get,set,delete,或者沒有實例將僅運行__get__而永遠不會運行__set____detele__

僅當在實例中為其指定描述符名稱時,才調用該描述符的__set__方法。 如果直接分配給該類, __set__覆蓋描述符(不__set__ )。 相反,在類或實例上都將使用__get__方法進行查找。 某些描述符(例如property )被編程為在類上調用時返回自身,因此它們的__get__方法實際上並未運行可能並不那么明顯。

如果要使用描述符來控制對類變量的訪問,則需要將描述符放入元類(類對象的類)中。 這是一個基本示例,使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM