A, descriptor Descriptors
- Descriptor of performance: use three magic methods: __ get __ (), __ set __ (), __ delete __ ()
Format: Object. __Get__ (Self, instance, owner) Object. __Set__ (Self, instance, value) Object. __Delete__ (Self, instance) Self refers to the current example, the caller; instance is owner example; owner is class belongs properties class A: DEF the __init__ (Self): self.a1 = ' A1 ' Print ( ' A.init ' ) class B: X = A () DEF the __init__ (Self): Print ( ' B.init ' ) Print( ' - ' * 20 is ) Print (Bxa1) Print ( ' = ' * 20 is ) B = B () Print (bxa1) can be seen that the above code execution: When loading classes, class variable needs to be generated, while class B x property is an instance of class a, class a so the initialized, first print A.init then executed to print Bxa1, then instantiates and initializes the instance b B, print bxa1, looks for the class attribute bx, pointing example a, the values returned a example of attributes a1
1, the following code is added __get__ method of performing change See
class A: def __init__(self): self.a1 = 'a1' print('A.init') def __get__(self,instance,owner): print("A.__get__{}{}{}".format(self,instance,owner)) return self #解决返回值None的问题 class B: x = A() def __init__(self): print('B.init') print(' - ' * 20 is ) Print (Bx) # Print (Bxa1) # thrown AttributeError Print ( ' = ' * 20 is ) B = B () Print (BX) # Print (bxa1) # thrown AttributeError perform output: A.init -------------------- A. __get__ < __main__ II.A AT 0x00000000049CB518 Object>, None, < class ' in __main __. B ' > None ==== ================ B.init A. __get__ < __main__Object AT 0x00000000049CB518 II.A>, < __main__ .B AT 0x00000000049CB630 Object>, < class ' in __main __. B ' > None because __get__ defined method of class A is a descriptor, x instance of class B or class B of read access to the property instance of the class known as the a, __get__ method is called class a are examples of self, owner of B are, instance description # None indicates no instance of class B, corresponding to the call Bx
Second, the descriptor defined
- python in a class implements __get __, __ set __, __ delete__ any three of a method descriptor is
- If only realized __get__, is the non-data descriptor
- While achieving __get __, __ set__ data descriptor is
- If a class attribute for the class descriptor, it is the main owner is called
1, the access order attribute
- Examples __dict__ precedence over non-data descriptor, the data is described in an example of the priority __dict__
class A: def __init__(self): print(111111111111111111) self.a1 = 'a1' print('A.init') def __get__(self,instance,owner): print(22222222222222222222) print("A.__get__{},{},{}".format(self,instance,owner)) return self #解决返回值None的问题 def __set__(self,instance,value): print(33333333333333333333333) Print ( ' A .__ set__ {}, {}, {} ' .format (Self, instance, value)) self.data = value class B: X = A () DEF the __init__ (Self): Print (4444444444444444444444 ) Print ( ' B.init ' ) self.x = ' BX ' # increase instance attribute X # Print ( '-' * 20 is) # Print (Bx) # Print (Bxa1) # thrown AttributeError Print ( '= ' * 20 is ) B = B () Print (BX) Print (bxa1) # thrown AttributeError using the set not used and the set seen, the original data descriptor is not high priority, but the properties of the instances from _ _dict__ removes, resulting in the property if it is the illusion of data descriptors priority access, in the final analysis, property access order never changed over
2, python of descriptor
- Described in the python is widely used, the methods are implemented as a non python data descriptor; Accordingly, examples of methods can be redefined and the cover, which allows a single instance of obtaining other instances of the same class different behavior
- property () function is implemented as a data descriptor, and therefore, can not cover the instance attribute behavior
class A: @classmethod DEF foo (CLS): # the non-data descriptor Pass @staticmethod # non-data descriptor DEF bar (): Pass @Property # data descriptor DEF Z (Self): return . 5 DEF getFoo (Self): # non-data descriptor return self.foo DEF the __init__ (Self): # the non-data descriptor self.foo = 100 self.bar = 200 is # self.z = 300 A = A () Print (A. the __dict__ ) foo, bar can be covered in the example, but not z # achieve StaticMethod decorator, functional staticmethod decorators # class staticmethod decorator class StaticMethod: DEF the __init__ (Self, Fn): self._fn = Fn DEF __get__ (Self, instance, owner): return self._fn class a: @StaticMethod DEF stmtd (): Print ( ' static Method ' ) A.stmtd () . a () stmtd () # A.clsmtd () mean is None (), certain error, how to modify from functools Import partial #类classmethod装饰器 class ClassMethod: def __init__(self,fn): self._fn = fn def __get__(self,instance,cls): ret = partial(self._fn,cls) return ret class A: @ClassMethod # ClassMethod(clsmtd) def clsmtd(cls): print(cls.__name__) print(A.__dict__) A.clsmtd A.clsmtd()
3, an example of data for verification
- Ideas: write function, first check in __init__, if unqualified, direct throw an exception; decorator, use the inspect module to complete
# class Person: # def __init__(self, name:str, age:int): # params = ((name,str),(age,int)) # print(params) # if not self.checkdata(params): # raise TypeEror() # self.name = name # self.age = age # def checkdata(self, params): # for p, t in params: # print(p,t) # if not isinstance(p,t): # return False # return True # p = Person('tom', 20) # Descriptor mode, the writing time to do checks instance attribute class the Typed: DEF the __init__ (Self, name, type): the self.name = name self.type = type DEF __get__ (Self, instance, owner): IF instance IS Not none: return instance. the __dict__ [the self.name] return Self DEF __set__ (Self, instance, value): IF Not the isinstance (value, self.type): The raise TypeError (value) instance.the __dict__ [the self.name] = value class the Person: name = the Typed ( ' name ' , STR) Age = the Typed ( ' Age ' , int) DEF the __init__ (Self, name: STR, Age: int): the self.name = name self.age = Age P = the Person ( ' Tom ' , 20 is ) # code that looks good, but there are hard coded, can directly obtain the parameter type inspect using the module # test as follows: Import inspect the params = inspect.signature(Person).parameters print(params) #使用inspect模块完成 import inspect class Typed: def __init__(self, name, age): self.name = name self.type = type def __get__(self, instance, owner): if instance is not None: return instance.__dict__[self.name] return self def __set__(self, instance, value): if not isinstance(value, self.type): raise TypeError(value) instance.__dict__[self.name] = value def typeassert(cls): params = inspect.signature(cls).parameters print(params) for name,param in params.items(): print(param.name, param.annotation) # 注入类属性 if param.annotation != param.empty: setattr(cls, name, Typed(name, param.annotation)) return cls @typeassert class Person: def __init__(self, name:str, age:int): self.name = name self.age = age def __repr__(self): return "{} is {}".format(self.name, self.age) #p = Person('tom','20') p = Person('tom', 20) print(p)