The path to Python (27th) object-oriented advanced: Built-in methods, descriptors

Source: Internet
Author: User

First, __call__

object is appended with parentheses, triggering the method below the execution class __call__ .

When an object is created, the object = Class name (), and the execution of the __call__ method is triggered by parentheses after the object, that is: Object () or Class () ( )

  Class Foo:  ?      def __call__ (self, *args, **kwargs):          print ("I'm doing it")  ?  f = Foo ()  f ()  #对象加括号调用执行类下的__call__方法  

  

Second, __next__ and __iter__ implement the iterator protocol

An iterator protocol is an object that must provide a next method that either returns the next item in the iteration, or causes a Stopiteration exception to terminate the iteration (only backward cannot go forward)

The result of an iterative object execution obj.__iter__() is an iterator object.

In a class, if there are __iter__ and __next__ built-in methods, then the iterator is formed.

Example

  
  Class Foo:  ?      def __init__ (self,n):          SELF.N = n  ?      def __iter__:  return self #实例本身就是迭代对象, so go back to yourself  ?      def __next__ (self):          if SELF.N >10:              raise stopiteration   #如果超过10就报StopIteration error          SELF.N = SELF.N + 1          return SELF.N  ?  f = Foo (7) for  I in F:  #for循环自动调用__next__方法, implements the iteration value      print (i)  

  

Example 2

Fibonacci Cinapo sequence in output 100

  
  Class F:  ?      def __init__ (self):          self.a = 0          self.b = 1  ?      def __iter__ (self):          return to self  ?      def __next__ (self):          self.a, self.b = self.b, SELF.A + self.b          if SELF.A >:              raise Stopiteration          Return SELF.A  ?  f = f () for  I in F:      

  

Third, descriptor ( __get__,__set__,__delete__ )

Descriptor (descriptor):

1. Descriptor Nature

is a new class, in this new class, at least, the __get__() __set__() __delete__() One, which is also known as the Descriptor protocol. : Trigger When an attribute is invoked: When a property is __get__() __set__() assigned a value, __delete__() It is triggered when a property is deleted with Del

2, the role of descriptors

is a property that is used to proxy another class (the descriptor must be defined as a class property of the class and cannot be defined in the constructor)

Descriptors are defined in the class properties of another class, and descriptors are in the class property __dict__ dictionary of a class

Example 1

  Class Foo:  ?      def __get__ (self, instance, owner):          print ("performed __get__")  ?      def __set__ (self, instance, value):          print ("__set__ executed")  ?      def __delete__ (self, Instance):          print ("performed __delete__")  ?  ?  Class Bar:      x = Foo ()  ?      def __init__ (self,name):          self.name = name  ?  ?  b = Bar ("Nick")  b.x     #调用执行描述符里的__get__方法  print (b.x)  #  b.x = 1  # Call the __set__ method that performs the description character  print (b.__dict__)  del b.x  #调用执行描述符里的__delete__方法  print (b.__dict__)

  

Output results

  Executed __get__ executed  __get__  None  executed __set__  {' name ': ' Nick '}  executed __delete__  {' name ': ' Nick '}

  

Example 2

 #描述符Str class Str:def __get__ (self, instance, owner): print (' St      R call ') def __set__ (self, instance, value): Print (' str set ... ')  def __delete__ (self, Instance): Print (' str delete ... ')  ? #描述符Int class Int:def __get__ (self, instance, owner): print (' Int call ') def __set__ (self, instance, Valu  E): print (' int set ... ') def __delete__ (self, Instance): print (' int delete ... ')? Class People:name=str () Age=int () def __init__ (self,name,age): #name被Str类代理, age is represented by Int class, Self.name  =name self.age=age? #何地?  : A class attribute defined as another class? #何时?  : And see the following demos?  P1=people (' Alex ', 18)?  #描述符Str的使用 p1.name p1.name= ' Egon ' del p1.name?  #描述符Int的使用 p1.age p1.age=18 del p1.age?  #我们来瞅瞅到底发生了什么 print ("__p1.__dict__", p1.__dict__) print (people.__dict__)? #补充 print (Type (p1) = = people) #type (obj) is actually the print (type (p1) that looks at what class obj is instantiated from. __dict__ = = people.__dict__) 

  

Output results

    STR Settings ...  int set ...  STR calls  str settings  ... STR delete ...  int calls  int setting  ... int delete ...  __p1.__dict__ {}  {' __module__ ': ' __main__ ', ' name ': <__main__. Str object at 0x021c6850>, ' age ': <__main__. Int object at 0x021c6870>, ' __init__ ': <function people.__init__ at 0x021c5db0>, ' __dict__ ': <attribute ' __di Ct__ ' of ' people ' objects>, ' __weakref__ ': <attribute ' __weakref__ ' of ' people ' objects>, ' __doc__ ': None}  True  

  

3, two types of descriptors

(1) Data descriptor: At least implemented __get__() and __set__()

  ?  Class Foo:      def __set__ (self, instance, value):          print (' Set ')      def __get__ (self, instance, owner):          Print (' Get ')

  

(2) Non-data descriptor: not implemented__set__()

    Class Foo:      def __get__ (self, instance, owner):          print (' Get ')

  

Note: Non-data descriptors are generally only __get__, and if reserved __delete__ execution will be an error.

4. Precautions:

(1) The descriptor itself should be defined as a new class, and the class being represented should also be a new class (All of the new classes in Python3)

(2) A descriptor must be defined as a class property of another class and cannot be defined in a constructor.

(3) To strictly follow this priority, priority from high to the end is

A. Class properties B. Data descriptor c. Instance properties D. Non-data descriptor E. Property triggering __getattr__() not found

Example 1

  
  Class Foo:  ?      def __get__ (self, instance, owner):          print ("performed __get__")  ?      def __set__ (self, instance, value):          print ("__set__ executed")  ?      def __delete__ (self, Instance):          print ("performed __delete__")  ?  class people:  ?      Name = Foo ()  ?      def __init__ (self,name):          self.name = name  ?  ?  p = People ("Nick")  people.name  = "Nick"  #调用执行了描述符的__set__方法, this step class attribute is defined by the previous descriptor as another string,  # So the following call again will not be able to use the descriptor again  people.name     ?  #可以得出结论, the precedence of class properties is greater than the data descriptor

  

Example 2

  
  Class Foo:  ?      def __get__ (self, instance, owner):          print ("performed __get__")  ?      def __set__ (self, instance, value):          print ("__set__ executed")  ?      def __delete__ (self, Instance):          print ("performed __delete__")  ?  class people:  ?      Name = Foo ()  ?      def __init__ (self,name):          self.name = name  ?  ?  p = People ("Nick")  #实例化对象, call the __set__ of the data descriptor,  # But since the __set__ of the descriptor just performs the print operation, nothing is done, so the __dict__  of the P object is nothing P.name = "Nicholas"  print (p.__dict__) #输出的结果为空  ?  #因此可以得出结论, the precedence of the data descriptor is greater than the instance property (dictionary operation)

  

Example 3

  Class Foo (object):      def __init__ (self):          pass  ?      def __get__ (self, instance, owner):          print ("performed __get__")  ?  class people (object):  ?      Name = Foo ("x")  ?      def __init__ (self,name,age):          self.name = name          Self.age = Age  ?  ?  ? p = People ("Nick")  #实例化对象, here because the non-data descriptor, the priority is lower than the instance property,  # So the instance property is set directly here, but no longer called the Descriptor  Print (p.name)  # Print Direct output Instance properties print  (p.__dict__)  #输出的结果: {' name ': ' Nick ', ' Age ': *}  ?  #因此可以得出结论, the precedence of instance properties is greater than non-data descriptors

  

Example 4

    Class Foo (object):      def __init__ (self,name2):          self.name2 = name2  ?      def __get__ (self, instance, owner):          print ("performed __get__")  ?  ?  class people (object):  ?      Name = Foo ("x")  ?      def __init__ (self,name,age):          self.name = name          Self.age = Age  ?      def __getattr__ (self, item):          print ("__getattr__")  ?  ?  p = People ("Nick")  #实例化对象, here because the non-data descriptor, the priority is lower than the instance property,  # So the instance property is set directly here, but no longer called the Descriptor  Print (p.name)  Print (p.sex)  #调用不存在的属性执行了__getattr__  Print (p.__dict__)  #输出的结果: {' name ': ' Nick ', ' age ': 18}

  

5, the application of descriptors

Example 1

  
  Class Type:?      def __init__ (self,key,expect_type): Self.key = key Self.expect_type = Expect_type?          def __get__ (self, instance, owner): Print ("Execute __get__ Method") print (self) #这里的self就是type类的对象 Print (instance) #这里的instance就是传入的People类的对象 print ("Execute __get__ Method") return Instance.__d      Ict__[self.key] #通过instance的字典获取对象的属性值? def __set__ (self, instance, value): Print ("Execute __set__ Method") Instance.__dict__[self.key] = value #instance      Is the object of another class, where do you want to set the object's Dictionary of properties?  def __delete__ (self, Instance): Print ("Execute __delete__ Method") Instance.__dict__.pop (Self.key) #删除对象的属性?      Class People:name = Type ("name", str) age = Type ("Age", int)?  def __init__ (self,name,age): self.name = name Self.age = age? P1 = People ("Nick") #调用2次描述符, set the dictionary for the object Print (p1.name) #通过数据描述符获取对象的属性值 print (p1.__dict__) p1.age = #调用描述符对对象进 Line Set Print (p1.__dict__) 

  

Output results

  
  Execute the __set__ method to execute the  __set__ method to  Execute the __get__ method  <__main__. Type object at 0x004cb4f0>  <__main__. People object at 0x02106df0>  execution __get__ method  Nick  {' name ': ' Nick ', ' age ': '  execute __set__ method  {' Name ': ' Nick ', ' Age ': 20}

  


?

Example 2

  
  Class Type:?      def __init__ (self,key,expect_type): Self.key = key Self.expect_type = Expect_type?          def __get__ (self, instance, owner): Print ("Execute __get__ Method") print (self) #这里的self就是type类的对象 Print (instance) #这里的instance就是传入的People类的对象 print ("Execute __get__ Method") return Instance.__d      Ict__[self.key] #通过instance的字典获取对象的属性值?              def __set__ (self, instance, value): Print ("Execute __set__ Method") if not Isinstance (Value,self.expect_type):  Print ("%s you entered is not%s"% (Self.key,self.expect_type)) raise TypeError Instance.__dict__[self.key]      = value #instance是另一个类的对象, where do you want to set the property dictionary for the object?  def __delete__ (self, Instance): Print ("Execute __delete__ Method") Instance.__dict__.pop (Self.key) #删除对象的属性?      Class People:name = Type ("name", str) age = Type ("Age", int)?  def __init__ (self,name,age): self.name = name Self.age = age? P1 = People ("Nick") #调用2次描述符, set the dictionary of the object to print (P1.name) #通过数据描述符获取对象的属性值 print (p1.__dict__) p1.age = #调用描述符对对象进行设  Print (p1.__dict__) # p1.name = one #通过描述符的if not isinstance (value,self.expect_type) determine the type of the property? # P2 = people (88,18) #通过描述符的if not isinstance (value,self.expect_type) determine the type of the property

  

iv. __enter__ and __exit__

The open file operation is operated with the with Open () as F, which is called the context Management Protocol, the WITH statement, in order for an object to be compatible with the WITH statement, __enter__ and __exit__ methods must be declared in the class of the object.

__enter__(self): Triggers the operation of this method when with starts running

__exit__(self, exc_type, exc_val, exc_tb): The run of this method is triggered when the with run ends

Exc_type If an exception is thrown, this gets the type of the exception

Exc_val If an exception is thrown, the exception content is displayed here

EXC_TB If an exception is thrown, this shows where

Use or Benefits:

1. The purpose of using the WITH statement is to put the code block in with, and with the end, the cleanup work is done automatically without manual intervention

2. In a programming environment where you need to manage resources such as files, network connections, and locks, __exit__ You can customize the mechanism for automatically releasing resources, and you don't have to deal with the problem.

Example

Class OPEN:    def __init__ (self,name):        self.name = name    def __enter__ (self):        print ("Execute __enter__")        return self    def __exit__ (self, exc_type, Exc_val, EXC_TB):        print ("Execute __exit__")        print (Exc_type)        print (exc_val) print (        exc_tb)        print ("Execute __exit__2222") with OPEN ("A.txt") as F:    print (f)  # Performs a print __enter__ built-in method, while printing the results returned by the built-in method #with the execution of the __exit__ method at the end of the statement, prints none without errors, prints the wrong message print ("Context Management Protocol")

  

The path to Python (27th) object-oriented advanced: Built-in methods, descriptors

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.