python magic process (descriptor)

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)  

 

Guess you like

Origin www.cnblogs.com/jiangzuofenghua/p/11448848.html