In Python__ new__,__ init__ And metaclass

Posted by Karl33to on Sun, 23 Jan 2022 21:39:38 +0100

In Python's object-oriented programming, you must first create an instance object, and then initialize the instance object__ new__ Responsible for creating instance objects__ init__ Responsible for initializing objects, which is introduced in this paper__ new__ And__ init__ And metaclasses in Python.

__ new__ And__ init__

__ new__ And__ init__ The main differences are as follows:

  • __ new__ It is called before the instance is created. It is used to create an instance and then return the instance object. It is a static method__ new__ There must be a return value, that is, to return the instantiated instance.
  • __ new__ The return value (instance) of will be passed to__ init__ Method, and then__ init__ Set some parameters for this instance.
  • __ new__ There must be at least one parameter cls representing the current class
  • __ init__ It is called after the instance object is created, and then set some initial values of object properties. It is usually used to initialize a class instance. It is an instance method.
  • __ init__ The parameter self is__ new__ Returned instance__ init__ In__ new__ Other initialization actions can be completed on the basis of__ init__ The return value (_init_ () should return none) is not required.

Create a class:

class Person(object):
    def __new__(cls, *args, **kwargs):
        print("__new__ is called")
        return object.__new__(cls)

    def __init__(self, x, y):
        print("__init__ is called")
        self.name = x
        self.height = y

if __name__ == '__main__':
    p1 = Person("zhangsan",180)        

Execution results:

__new__ is called
__init__ is called

python implements singleton mode

Singleton mode is that a class can only instantiate one object, and the class must create its own unique instance.

In general, a class can instantiate multiple objects:

p1 = Person("zhangsan",180)
print(p1)
print(p1.name)
p2 = Person("lishi",175)
print(p2)
print(p2.name)

Execution results:

__new__ is called
__init__ is called
<__main__.Person object at 0x000001939679BC88>
zhangsan
__new__ is called
__init__ is called
<__main__.Person object at 0x000001939679BC48>
lishi

It is found that the memory addresses of the two instantiated objects are different. The single instance mode is written as follows:

class Singleton(object):
    # Singleton mode
    _instance = None
    def __new__(cls, *args, **kwargs):
        print("__new__ is called")
        if cls._instance is None:
            cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self,x, y):
        print("__init__ is called")
        self.name = x
        self.height = y

Singleton mode rewrites__ new__ Method to ensure that there is only one instantiated object.

Execution:

p1 = Singleton("zhangsan",180)
print(p1)
print(p1.name)
p2 = Singleton("lishi", 175)
print(p2)
print(p2.name)
print(p1.name)

Output results:

__new__ is called
__init__ is called
<__main__.Singleton object at 0x00000243DD386E48>
zhangsan
__new__ is called
__init__ is called
<__main__.Singleton object at 0x00000243DD386E48>
lishi
lishi

Two instantiated objects point to the same memory address. The singleton mode can ensure that there is only one instance of a class in the system. If you want only one object of a class to exist, using the singleton mode can save memory.

python MetaClass metaclass

__ new__ Method is also used to customize MetaClass. Let's introduce the concept of MetaClass first.

What is MetaClass

Metaclass is defined as the class of a class. Meta originates from the Greek word meta and has the meaning of "transcendence" and "change", so metaclass includes the meaning of "transcendence" and "deformation".

Let's take an example:

>>> class MyClass(object): data = 6
...
>>> myobject = MyClass()
>>> print(myobject.__class__)
<class '__main__.MyClass'>
>>> print(MyClass.__class__)
<class 'type'>
>>>

In the above example, the class of myobject object object is MyClass, and the class of MyClass is type, that is, myobject is a MyClass object, and MyClass is a type object.

Type is a metaclass. It is the most commonly used metaclass. It is the default metaclass of all classes in Python. All Python user-defined classes are instances of type.

Metaclasses are used to construct classes (just as classes are used to construct objects). The creation process of Python class is as follows:

  1. When defining a class, Python collects attributes into a dictionary
  2. After the class definition is completed, determine the metaclass Meta of the class and execute Meta(name, bases, dct) for instantiation.
    • Meta is a metaclass
    • Name: the name of the class__ name__ attribute
    • Bases: base class tuple of the class__ bases__ attribute
    • dct: map attribute names to objects and list all attributes of the class__ dict__ attribute

You can create classes directly using type:

>>> myobject = type('MyClass', (), {'data': 6})
>>> print(myobject.__class__)
<class 'type'>

>>> print(myobject.__name__)
MyClass
>>> print(myobject.__bases__)
(<class 'object'>,)
>>> print(myobject.data)
6
>>> print(myobject.__dict__)
{'data': 6, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}

That is, when defining the MyClass class, the actual execution is the class = type(name, bases, dct) statement,

If a class or one of its base classes has__ metaclass__ Property, it is treated as a metaclass. Otherwise, type is a metaclass. To customize the metaclass, you need to use__ new__ And__ init__ Method, and then introduce the definition of metaclass.

Define metaclass

Metaclasses can be used to dynamically modify the properties or methods defined in the class when creating a class__ new__ Method to modify class properties.

The following example uses metaclasses to add attribute methods:

class MyMetaClass(type):
    def __new__(meta, name, bases, attrs):
        print(meta, "__new__ is called")
        # Add attributes dynamically
        attrs['name'] = "zhangsan"
        attrs['talk'] = lambda self: print("hello")
        return super(MyMetaClass, meta).__new__(meta, name, bases, attrs)

    @classmethod
    def __prepare__(metacls, name, bases, **kwargs):
        print(metacls, "__prepare__ is called")
        return super().__prepare__(name, bases, **kwargs)

    def __init__(cls, name, bases, attrs, **kwargs):
        print(cls, "__init__ is called")
        super().__init__(name, bases, attrs)

    def __call__(cls, *args, **kwargs):
        print(cls, "__call__ is called")
        return super().__call__(*args, **kwargs)


class Myclass(metaclass=MyMetaClass):
    pass


if __name__ == '__main__':
    cla = Myclass()
    print(cla.name)
    cla.talk()
    print(cla.__dir__())

Execution results:

<class '__main__.MyMetaClass'> __prepare__ is called
<class '__main__.MyMetaClass'> __new__ is called
<class '__main__.Myclass'> __init__ is called
<class '__main__.Myclass'> __call__ is called
zhangsan
hello
['__module__', 'name', 'talk', '__dict__', '__weakref__', '__doc__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']

You can see the of the metaclass MyMetaClass__ new__ The () method dynamically adds the name attribute and the talk() method to the Myclass class.

In the creation of metaclasses, you can modify name, bases and attrs to achieve the functions we want. You can use Python reflection functions such as getattr(), setattr(). You can refer to the introduction of Python reflection mechanism Introduction to Python reflection.

Serialization and deserialization of PyYAML

In practical application, Python YAML realizes serialization & deserialization by using the beyond deformation feature of metaclass.

serialization and deserialization

  • Serialization: the process of converting structured data into a storable or transportable format, that is, the process of converting objects into byte sequences.

  • Deserialization: the process of restoring a sequence of bytes to an object.

The advantage of serialization is to realize the persistence of data, and the data can be permanently saved to the hard disk; In addition, remote data transmission is realized by serialization, and the byte sequence of the object is transmitted on the network.

PyYAML usage

In the following example, yaml. XML is used Load() deserializes the Person object in the text, using yaml Dump() to serialize the created Person class.

data.yaml file content:

!Person
height: 180
name: zhangsan
import yaml

class Person(yaml.YAMLObject):
  yaml_tag = u'!Person'
  def __init__(self, name, height):
    self.name = name
    self.height = height

  def __repr__(self):
    return f"{self.name}'s height is {self.height}cm"

with open("data.yaml", encoding="utf-8") as f:
    p1 = yaml.load(f)
    print(p1)

p2 = Person(name='lishi', height=175)
print(p2)
print(yaml.dump(p2))
# with open("data.yaml", "w", encoding="utf-8") as f:
#     yaml.dump(p2,f)

Execution results:

zhangsan's height is 180cm
lishi's height is 175cm
!Person
height: 175
name: lishi

yaml.load() loads the yaml sequence into a Python Object; yaml.dump() serializes YAMLObject subclasses. We don't need to know any type of information in advance, which realizes super dynamic configuration programming.

summary

This article provides a brief introduction to Python__ new__ And__ init__ Method__ new__ Invoke and return the instance object before instance creation. init__ It is called after the instance object is created. It is used to initialize a class instance. It is an instance method.

Python metaclasses are complex and difficult to understand. They are generally used in Python framework development. Be careful when using them. In addition to the serialization and deserialization of YAML, the object relational mapping (ORM) framework also uses metaclasses, such as Django's models.

Metaclasses can implement functions similar to decorators, if you don't want to add @ decorator in front of methods_ Func, which can be implemented using metaclasses.

--THE END--

Welcome to the official account: "Test Development Notes", and receive the latest technical articles in time.

Topics: Python