In the learning Python3 process found that Metaclass's usefulness is more extensive, more can view PEP 3115. In the learning process need to do some serialization operations (such as CSV conversion), access to data discovery, the use of the Meta class can easily automatically record the order of the properties and methods defined in a class, and then the operation of serialization.
First, introduce the new syntax rules for Metaclass:
1. There is a prepare function:
def prepare_class (name, *bases, Metaclass=none, **kwargs):
If Metaclass is None:
metaclass = Compute_default_ Metaclass (bases)
prepare = GetAttr (Metaclass, ' __prepare__ ', None)
if prepare isn't none: return
Prepare ( Name, bases, **kwargs)
else: return
dict ()
Parameter resolution:
' Name '-the name of the class that will be created;
' Bases '--base class list;
Since it is usually invoked before the Metaclass instance is created, __prepare__ () is generally implemented as a class function. The last returned Dict () is a custom Dictionary object. http://write.blog.csdn.net/postedit/54095727
2. __new__ (CLS, name, bases, clsdict)
Take a look at the __new__ (*args, **kwargs) knowledge in Python. __NEW__ has at least one CLS parameter that represents the class to instantiate, which is provided automatically by the Python compiler. In addition, you must have a return value that returns an instantiated instance. In order to better understand and prevent the confusion of later learning, this simple analysis of the difference between __new__ and __init__.
__INIT__ has a self parameter that represents the instance returned by __new__ and does not need to return a value. In short, __init__ calls __init__ () only if __new__ correctly returns the current class instance. Here is a minimalist example to explore the principles.
In [1]: Class A (object):
...: def __init__ (self):
...: Print (' init ... ')
...: def __new__ (CLS, *args, **kwargs):
...: print (CLS)
...: Return object.__new__ (CLS, *args, **kwargs)
In [2]: A ()
<class ' __main__. A ' >
Init...
OUT[4]: <__main__. A at 0x7fd08daf6f28>
This is the correct call;
In [3]: Class C (object):
..: Pass
...:
In [4]: Class A (C):
...: def __init__ (self):
...: Print (' init ... ')
...: def __new__ (CLS, *args, **kwargs):
...: print (CLS)
...: Return object.__new__ (C, *args, **kwargs)
...:
In [m]: A ()
<class ' __main__. A ' >
OUT[20]: <__main__. C at 0x7fd08d28f5f8>
Discovery __init__ was not invoked because __new__ () provided c instead of the CLS representing the current class instance, so __new__ did not return the current class instance, but instead returned an instance of C.
Having said so much, let's get back to the point. Continue to discuss the use of __new__ in Metaclass. I cite the example in Pep 3115 to illustrate this problem. Create a list of all class members with Metaclass, in the order in which they are declared.
# Customizing the dictionary # The custom dictionary
Class Member_table (Dict):
def __init__ (self):
Self.member_names = []
def __setitem__ (self, Key, value):
# If the key isn't already defined, add to the
# List of keys.
If key not in self:
Self.member_names.append (Key)
# Call Superclass
Dict.__setitem__ (self, key, value)
# The Metaclass
Class Orderedclass (Type):
# The Prepare function
@classmethod
def __prepare__ (METACLS, name, bases): # No keywords in the case
Return member_table ()
# The Metaclass invocation
Def __new__ (CLS, name, bases, classdict):
# that we replace the classdict with a regular
# dict before passing it to the superclass
# don ' t continue to record member names after the class
# has been created.
result = type.__new__ (CLS, name, bases, Dict (classdict))
Result.member_names = Classdict.member_names
return result
Class MyClass (Metaclass=orderedclass):
# method1 goes in array element 0
def method1 (self):
Pass
# METHOD2 goes in array element 1
def method2 (self):
Pass
In this pattern, we can easily write Python classes that meet our requirements, reference Python3-cookbook.
From collections Import Ordereddict # A set of descriptors for various types class Typed: _expected_type = Type (None) def __init__ (self, name=none): self._name = name def __set__ (self, instance, value): If not Isin Stance (value, Self._expected_type): Raise TypeError (' expected ' + str (self._expected_type)) instance._ _dict__[self._name] = value class Integer (Typed): _expected_type = int class Float (Typed): _expected_type = Floa T class String (Typed): _expected_type = str # metaclass that uses a ordereddict for class body class Orderedmeta (Ty PE): Def __new__ (CLS, clsname, Bases, clsdict): D = dict (clsdict) Order = [] for name, value I n Clsdict.items (): If Isinstance (value, Typed): Value._name = name Order.appen d (name) d[' _order ' = Order return type.__new__ (CLS, clsname, bases, D) @classmethod def __prepar E__ (CLS, clsname, bases): Return Ordereddict ()
Use:
Class Structure (Metaclass=orderedmeta):
def as_csv (self): return
', '. Join (Str (GETATTR (self,name)) for name In Self._order)
# Example Use
class-Stock (Structure):
name = String ()
shares = Integer () Price
= Float ()
def __init__ (self, name, shares, Price):
self.name = name
self.shares = shares Self.price
= Price
>>> s = Stock (' XZ ', 100, 20.3)
>>> S.name
' XZ '
>>> S.as_csv ()
' xz,100,20.3 '
>>>
This gives you the code to convert the CSV data.