实用:python中描述器实现并在装饰器中加入描述器

描述器实现:

class A:
    def __init__(self,data):
        print('A.init')
        self.a1 = data

    def __get__(self,instance,owner):
        print('A.__get__',self,instance,owner)
        return self

    def __set__(self, instance, value):
        print('A.__set__',self,instance,value)

class B:
    x = A('abc')

    def __init__(self):
        print('B.init')
        self.x= A(123)
b = B()
print('===========================')
print(B.x.a1)
print('===========================')
print(b.x.a1)
print('===========================')
b.x=A(345)
print(B.x.a1)
print('===========================')
print(b.__dict__)
print(B.__dict__)
print('===========================')

运行结果:

A.init
B.init
A.init
A.__set__ <__main__.A object at 0x7ffbf44fb390> <__main__.B object at 0x7ffbf2fbe160> <__main__.A object at 0x7ffbf2fbe2e8>
===========================
A.__get__ <__main__.A object at 0x7ffbf44fb390> None <class '__main__.B'>
abc
===========================
A.__get__ <__main__.A object at 0x7ffbf44fb390> <__main__.B object at 0x7ffbf2fbe160> <class '__main__.B'>
abc
===========================
A.init
A.__set__ <__main__.A object at 0x7ffbf44fb390> <__main__.B object at 0x7ffbf2fbe160> <__main__.A object at 0x7ffbf2fbe2e8>
A.__get__ <__main__.A object at 0x7ffbf44fb390> None <class '__main__.B'>
abc
===========================
{}
{'__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__init__': <function B.__init__ at 0x7ffbf44eabf8>, 'x': <__main__.A object at 0x7ffbf44fb390>, '__doc__': None, '__module__': '__main__'}
==========================

改造成staticmethod和classmethod装饰器:(非数据描述器):

from functools import partial

class StaticMethod:
    def __init__(self, fn):
        print(1,fn)
        self.fn = fn

    def __get__(self, instance, owner):
        print(self,instance,owner)
        return self.fn

class ClassMethod:
    def __init__(self, fn):
        print(fn)
        self.fn = fn

    def __get__(self, instance, owner):
        print(self,instance,owner)
        #return self.fn(owner)
        return partial(self.fn,owner)

class A:
    @StaticMethod
    def foo():
        print('static')

    @ClassMethod
    def bar(cls):
        print(cls.__name__)
f1 = A.foo
print(2,f1)
f1()
print('==================================')
f2 = A.bar
print(3,f2)
f2()

运行结果:

1 <function A.foo at 0x7fb10a77d2f0>
<function A.bar at 0x7fb10a77d378>
<__main__.StaticMethod object at 0x7fb10bd090f0> None <class '__main__.A'>
2 <function A.foo at 0x7fb10a77d2f0>
static
==================================
<__main__.ClassMethod object at 0x7fb10bd09390> None <class '__main__.A'>
3 functools.partial(<function A.bar at 0x7fb10a77d378>, <class '__main__.A'>)
A

描述器+装饰器+反射的综合案例:

class A:
    def __init__(self,name):
        self.name = name

    def __get__(self, instance, owner):
        print('__get__')
        return instance.__dict__['name']


    def __set__(self, instance, value):
        print('__set__')
        instance.__dict__['name'] = value

class C:
    def __init__(self,cls):
        self.cls = cls

    def __call__(self, name):
        setattr(self.cls,'name',A(name))
        return self.cls(name)

@C
class B:
    # name = A('tom')
    def __init__(self,name):
        self.name = name

b = B('kangkang')
print('=============================')
print(b.name)
print('=============================')
b.name = 'jerry'
print('=============================')
print(b.name)
print('=============================')
print(b.__dict__)

运行结果:

__set__
=============================
__get__
kangkang
=============================
__set__
=============================
__get__
jerry
=============================
{'name': 'jerry'}

改进:(为传参进行检查是否符合注解类型)---------解决python是强类型语言传参的问题

class Typed:
    def __init__(self,key,type):
        self.type = type
        self.key = key

    def __get__(self, instance, owner):
        return instance.__dict__[self.key]

    def __set__(self, instance, value):
        if not isinstance(value,self.type):
            raise ValueError(value)

        instance.__dict__[self.key] = value

import inspect
class TypeAssert:
    def __init__(self,cls):
        self.cls = cls

    def __call__(self, name, age):
        params =  inspect.signature(self.cls).parameters
        for key,param in params.items():
            if param.annotation != param.empty:
                setattr(self.cls, key, Typed(key,param.annotation))
        return self.cls(name,age)

@TypeAssert
class Person:    #Person = TypeAssert(Person)
    def __init__(self,name:str,age:int):
        self.name = name
        self.age = age



p1 = Person('tom',19)  #TypeAssert(Person)('tom',18)
print(p1.name)
print(p1.age)
print('============================================')
p1 = Person('Jerry','20')

运行结果:

tom
19
============================================
  File "/home/yzx/PycharmProjects/python/t58.py", line 38, in <module>
    p1 = Person('Jerry','20')
  File "/home/yzx/PycharmProjects/python/t58.py", line 25, in __call__
    return self.cls(name,age)
  File "/home/yzx/PycharmProjects/python/t58.py", line 31, in __init__
    self.age = age
  File "/home/yzx/PycharmProjects/python/t58.py", line 11, in __set__
    raise ValueError(value)
ValueError: 20

自我实现property属性装饰器

class Property:
    def __init__(self, fget, fset=None):
        self.fget = fget
        self.fset = fset

    def __get__(self, instance, owner):
        if instance is not None:
            return self.fget(instance)
        return self

    def __set__(self, instance, value):
        if callable(self.fset):
            self.fset(instance, value)
        else:
            raise AttributeError()

    def setter(self, fset):
        self.fset = fset
        return self

class A:
    def __init__(self, data):
        self._data = data

    @Property
    def data(self):
        return self._data

    @data.setter
    def data(self, value):
        self._data = value

a = A(100)
print(a.data)
a.data = 200
print(a.data)

运行结果:

100
200
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值