Describes some of the advanced topics about classes, which are optional and are not often encountered in Python applications.
==========================================================================
Slots Instances
Assigns a string property name order to a special __slots__ class property. Can limit the set of legitimate attributes that an instance of a class will have.
This particular property is usually set by assigning the string name order to the variable __slots__ in the top level of the class statement: only those variable names within the __slots__ list can be assigned to instance properties. The instance property name must be assigned before the reference, even if it is listed in __slots__. See the following example:
>>> class Limiter (object): __slots__ = [' Age ', ' name ', ' job ']>>> x = Limiter () >>> X.agetraceback (most recent): File "<pyshell#4>", line 1, in <module> x.ageattributeerror : age>>> x.age = 40>>> x.age40>>> x.ape = 1000Traceback (most recent call last): File "< Pyshell#7> ", line 1, inch <module> x.ape = 1000AttributeError: ' Limiter ' object has no attribute ' ape '
Suppose you create a very many instance and only a few properties are required. Assigning a namespace dictionary to each instance object can be costly in terms of memory. To save space and speed, the slot properties can be stored sequentially for high-speed lookups instead of assigning a dictionary to each instance.
--------------------------------------------------------------------------------------------------------------- ----------------------
Slots and common code
As a matter of fact. Some instances with slots may not have a __dict__ attribute dictionary at all. So in some programs you use more storage-neutral tools than __dict__, such as GetAttr, SetAttr, and dir built-in functions.
>>> class c:__slots__ = [' A ', ' B ']>>> X = C () >>> x.a = 1>>> x.a1>>> x.__dict__ Traceback (most recent): File "<pyshell#6>", line 1, in <module> x.__dict__attributeerror : ' C ' object has no attribute ' __dict__ ' >>> getattr (x, ' a ') 1>>> setattr (x, ' B ', 2) >>> x.b2>& Gt;> ' A ' in Dir (x) true>>> ' B ' in Dir (x) True
Without a property namespace dictionary, it is not possible to assign a new name to an instance that is not a name in the slots list, however, by including the __dict__ in __slots__, you can still accommodate additional attributes, taking into account the need for an attribute space dictionary. In this example. Both mechanisms are used, but GetAttr's generic tool agrees that we treat them as a separate set of attributes:
>>> class d:__slots__ = [' A ', ' B ', ' __dict__ ']c = 3def __init__ (self): SELF.D = 4>>> x = D () >>> x. d4>>> x.__dict__{' d ': 4}>>> x.__slots__[' A ', ' B ', ' __dict__ ']>>> x.c3>>> X.atraceback (most recent): File "<pyshell#24>", line 1, in <module> x.aattributeerror:a& gt;>> x.a = 1>>> getattr (x, ' a '), GetAttr (x, ' C '), GetAttr (x, ' d ') (1, 3, 4)
==========================================================================
class Attributes
There is a mechanism called attributes that provides a way for a class to define its own method of invocation to read or assign instance properties.
"Features and slots are all based on a new concept of attribute-descriptive narrator."
In short, an attribute is an object that assigns a value to a class property name. The attribute is generated by three methods (the processor that obtains, sets, and deletes the operation), and the built-in function property is called through the document string. Assume that no matter what the parameters are passed or omitted in none. This operation is not supported.
Attributes are typically assigned at the top of the class statement "for example, Name = Property (...). 】。 When you assign this value. Read the Class property itself (for example,. Obj.name), it will voluntarily pass a read method to the property. For example, the following example:
>>> class new ():d EF getage (self): return 40age = Property (Getage,none,none,none) # get,set,del,docs> >> x = new () >>> x.age40>>> X.nametraceback (most recent call last): File "<pyshell#34> ", line 1, in <module> x.nameattributeerror: ' New ' object has no attribute ' name '
Performance is faster than traditional technology.
For example, when we add a property assignment operation support, the feature becomes more attractive: fewer code is entered, and no additional method calls occur when an assignment operation is performed on a property that we do not want to dynamically evaluate.
>>> class new ():d EF getage (self): return 40def setage (self,value):p rint (' Set Age: ', value) self._age = Valueage = Property (Getage,setage,none,none) >>> x = new () >>> x.age40>>> x.age = 42set age:42>> > x.age40>>> x._age42>>> x.job = ' trainer ' >>> x.job ' trainer '
==========================================================================
__getattribute__ and descriptive narrative characters
__GETATTRIBUTE__ enables a class to intercept references to all properties. Not limited to references that are not defined (assuming __getattr__).
In addition to the attribute and operator overloading methods, Python supports the concept of attribute descriptive descriptors-classes with __get__ and __set__ methods, assigned to class attributes and inherited by instances, which intercepts read and write access to specific attributes. Descriptive descriptors are, in a sense, a more general form of character.
High-level topics on features, __getattribute__ and descriptive descriptors will be introduced in a gradual step.
==========================================================================
Static methods
A class method typically passes an instance object in its first parameter. To act as an implicit principal for a method call. Sometimes. The program needs to handle the data associated with the class rather than the instance, i.e. we need a method in a class that not only passes and does not expect a self instance parameter.
Python supports this goal through the concept of "static methods"-simple functions that are nested within a class without self-parameters.
Like what. If we want to use class properties to calculate how many instances are produced from a class. We are able to store a counter as a class property. Each time a new instance is created. The constructor will add 1 to the counter. Also, there is a way to display the counter value. "Remember, class properties are shared by all instances":
>>> class spam:numinstances = 0def __init__ (self): spam.numinstances + = 1def printnuminstances ():p rint (' number of instances created: ', spam.numinstances)
The Printnuminstances method is designed to handle class data rather than instance data-it's about all instances, not a particular instance. Therefore, we want to be able to invoke it without passing an instance.
In fact, we don't want to generate an instance to get the number of instances. Since this in itself will change the number of instances we want to get.
In other words: We want a static method with no self.
We can look at the results of the test:
>>> a = Spam () >>> B = Spam () >>> C = Spam () >>> spam.printnuminstances () Number of Instan CES created:3>>> a.printnuminstances () Traceback (most recent): File ' <pyshell#66> ', line 1 , in <module> a.printnuminstances () typeerror:printnuminstances () takes 0 positional arguments but 1 is given
We can see that we have succeeded by calling the no self method through the class. There is an error in calling the No self method through the instance because the parameter is incorrect. Invokes a method through an instance. This instance takes its own initiative to pass to the first parameter of the method, but the no self method does not have a parameter to receive it.
Suppose you can persist only by calling the no self method through the class. So, in fact, you already have a static method. However, assuming that you still want to invoke the instance, you need to take other designs or mark the scheme as special.
--------------------------------------------------------------------------------------------------------------- ----------------------
Using static methods
To mark this no self method as a static method. You need to call the built-in function Staticmethod. For example, the following:
>>> class spam:numinstances = 0def __init__ (self): spam.numinstances + = 1def printnuminstances ():p rint (' number of instances created: ', spam.numinstances) printnuminstances = Staticmethod (printnuminstances) # staticmethod> >> a = Spam () >>> B = Spam () >>> C = Spam () >>> a.printnuminstances () Number of instances CRE Ated:3
Static methods are a better way to handle data that is local to a class.
==========================================================================
Decorators and meta-classes: First knowledge
The staticmethod mentioned above may be rather strange. So a new feature has been added to make this operation simple. The function decorator provides a way to understand a particular mode of operation for a function. That is, the function is wrapped in a layer, in the logic of a function is also implemented.
The function adorner has become a common tool: In addition to static method use methods. It can also be used to add a variety of logic functions. For example, it can be used to record information about function calls and to check the type of incoming parameters in case of an error.
Python provides a built-in function decorator to do some arithmetic, such as. Identify static methods, but we can also write our own casual adorners. Although not limited to the use of classes, user-defined function adorners are often written as classes, using primitive functions and other data as state information.
--------------------------------------------------------------------------------------------------------------- ----------------------
Function Adorner Basics
Syntactically speaking, a function adorner is a declaration of the execution of a function behind it.
A function adorner is written in a row, before defining a function or method's DEF statement, and consists of the @ symbol followed by the so-called meta function: that is, a function that manages a function.
For example, today's static methods can be written in the following adorner syntax:
Class C: @staticmethoddef printnuminstances (): ...
This syntax has the same effect as the following:
Class C:def Meth (): ... meth = staticmethod (Meth)
The result is the name of the calling method function. is actually triggering the result of its staticmethod adorner.
--------------------------------------------------------------------------------------------------------------- ----------------------
Adorner example
As previously described, the __CALL__ operator overload method implements a function call interface for a class instance.
The following program defines a class in such a way. Stores the decorated function in the instance and captures the call to the original variable name.
Class Tracer: def __init__ (self,func): self.calls = 0 Self.func = func def __call__ (Self,*args): Self.calls + = 1 print (' Call%s to%s '% (self.calls,self.func.__name__)) Self.func (*args) @tracerdef Spam (a,b,c): print (a,b,c) spam (+/-) spam (' A ', ' B ', ' C ') spam (4,5,6)
Because the spam function is run through the tracer adorner, when the initial variable name spam is called. What actually triggers is the __call__ method in the class, which computes and records the call and then entrusts the function to the original package.
Therefore, this adorner can be used to wrap any function that carries a random number of parameters.
The result is a new layer of logic to the original spam function. The execution results are as follows: The first line comes from the Tracer class, and the second line comes from the spam function.
Call 1 to spam1 2 3call 2 to Spama b ccall 3 to SPAM4 5 6
Here is just a preliminary understanding. Perhaps we will introduce a variety of methods to write function adorners.
--------------------------------------------------------------------------------------------------------------- ----------------------
Class decorators and Meta classes
The class adorner is similar to a function adorner, but. They execute at the end of a class statement and bind a class name to a callable object again, the same way they can be used to manage the class, or insert a wrapper logic layer to manage the instance when the instance is subsequently created. The code structure is as follows:
def decorator (AClass): ... @decoratorclass C: ...
is mapped to the following equivalent code:
def decorator (AClass): ... class C: ... c = Decorator (c)
A meta-class is a similar class-based advanced tool. Its use is often coincident with the class adorner.
They provide an optional mode. Directs the creation of a class object to a subclass of the top-level type class.
The content of adorners and meta-classes will be described more specifically later.
Advanced Topics for the python--class