Home >Backend Development >Python Tutorial >Introduction to new class method, init instance method and singleton mode in Python (with examples)

Introduction to new class method, init instance method and singleton mode in Python (with examples)

不言
不言forward
2019-01-28 11:18:552279browse

This article brings you an introduction to the new class method, init instance method and singleton mode in Python (with examples). It has certain reference value. Friends in need can refer to it. I hope it will help You helped.

"Are all classes in Python singleton mode?" One day, a colleague asked me such a question. This is a strange question, maybe you think so too. Without explanation here, let’s take a look at the __new__ and __init__ methods first. The

new and init

__new__ methods belong to the new-style class, that is, they belong to the object class. It is a static method, but its first parameter must be a class (cls), which is a bit like a classmethod. In fact, it can also be regarded as a class method. When this special method is called, a new instance of the class (cls) will be created and returned. After the instance is created, the interpreter will pass the instance and other parameters to the instance's initialization function __init__ to initialize the instance.

So, the __new__ method is a class method, used to create an instance, and the __init__ method is an instance method, used to initialize an instance.

__new__ method is called when instantiating a class. Overriding this method should look like the following:

class A(object):

    def __new__(cls, *args, **kwargs)
        return super(A, cls).__new__(cls, *args, **kwargs)

If the __new__ method does not return an instance of cls, then the new instance's __init__ The method will not be called. It should be noted that after Python 3.3, the new method no longer receives additional parameters, otherwise there will be an exception TypeError: object() takes no parameters.

__init__ method is called after the instance is created. This method only performs some initialization operations on the instance created by the __new__ method. Note that if the new method returns an instance, the init method will always be called (this should be paid special attention to when using the new method to implement a singleton)

You can do some verification:

class Foo(object):

    def __new__(cls, m, n):
        print "__new__ is called"
        return super(Foo, cls).__new__(cls, m, n)

    def __init__(self, m, n):
        print "__init__ is called"
        self.m = m
        self.n = n

    def __repr__(self):
        return "Foo(m={self.m}, n={self.n})".format(self=self)

    def __str__(self):
        return self.__repr__()


if __name__ == "__main__":
    f = Foo(1, 2)
    print f

Output result:

__new__ is called
__init__ is called
Foo(m=1, n=2)

So we can draw the conclusion:

1. __new__ is a class-level method. Even if it is not decorated by classmethod, it determines the process of generating instances.

2. __init__ is an instance-level method that determines the instance initialization process, such as adding attributes, judging and converting initialization parameters, etc.

It should be noted that the parameters of the rewritten __new__ method and the __init__ method should be consistent, otherwise TypeError will occur. If you call object.__new__() directly, incoming parameters are no longer supported in Python 3.3 and later versions. This reference is from: https://stackoverflow.com/questions/34777773/typeerror...

## The #__init__ method is generally involved when defining a class and is also commonly used. The __new__ method is rarely used, so what is its use?

New method function

#__new__ The more commonly used functions of the method are probably:

1. When inheriting built-in immutable types (such as int, str, tuple), provide self- Define the instantiation process. Because if you do all the write operations in the __init__ method, it may be invalid. For example:

class CustomInt(int):

    def __init__(self, v):
        super(CustomInt, self).__init__(self, abs(v))

print CustomInt(-1)

# 输出:-1
This may not have the desired effect. But it can be achieved by overriding the

__new__ method:

class CustomInt(int):

    def __new__(cls, v):
        return super(CustomInt, cls).__new__(cls, abs(v))

print CustomInt(-1)

# 输出:1
  • 2. Implement a custom metaclass. Metaclass is used to define how to create a class. Its concept may be slightly complicated and will not be discussed in detail here.

  • 3. Implement singleton. Since the process of generating instances of a class is controlled through the

    __new__ method, it is very convenient to rewrite this method to use the singleton mode:

class Singleton(object):

    def __new__(cls):
        if not hasattr(cls, "_instance"):
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

assert Singleton() is Singleton()  # 断言成功
The so-called singleton The mode is to return the same instance every time it is initialized, so the memory address of the object obtained by the two initializations should be the same:

print Singleton(), Singleton()
The result should be obvious:

<__main__.Singleton object at 0x10d698650> <__main__.Singleton object at 0x10d698650>
Decorator implementation single Example

Speaking of singleton mode, in addition to using the

__new__ method, there are some other ways, such as decorators, metaclasses, etc. Different ways of implementation have different effects. Metaclasses are more advanced features in Python and will not be discussed in this article. Let’s take a look at how to use decorators to implement singletons.

A decorator can dynamically modify the functionality of a class or function, that is, a class can also be decorated by a decorator. Therefore, you can use a decorator to decorate a class so that only one instance is generated when it is initialized:

from functools import wraps

def singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return getinstance

@singleton
class MyClass(object):

    def __init__(self):
        pass
It should be noted that

When using a decorator to implement a singleton, the class has become a Functions, not classes anymore. When initializing the instance using MyClass in the above example, what is actually called is the getinstance function returned after being decorated.

The difference between using

__new__ to implement a singleton and using decoration to implement a singleton is that the former will call the __init__ method, which means that every time it is initialized With different parameters, although the returned instance is the same, the properties of the instance have been reset; and the latter always returns the example created and the properties set during the first initialization, even if different parameters are passed in later.

奇怪现象

接着,我们再来看一个 “奇怪” 的现象:

>>> class A(object):
...     pass
...
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>
>>> print A(), A()
<__main__.A object at 0x104765450> <__main__.A object at 0x104765450>

是不是感觉有些难以置信,print 语句后两次创建的对象应该是不一样的,而他们却莫名奇妙的一样。这就是我讨论本文内容的原因。

一次同事问我,Python 中的类都是单例模式?我当时一脸懵逼,听了他的描述,我自己也试了下,果然存在如上所示的“奇怪”现象。于是我就去了解了 Python 单例模式的实现,在了解到 __new__ 的实现方式时,就想对 __new____init__ 有一个更加深入的了解。于是就有了本文所讨论的内容。

然后,我想着用 is 来判断下他们是否真的是同一个实例:

>>> A() is A()
False

我没有对 CPython 的源码进行过全面的阅读,所以对其很多内部的实现机制不是太了解。我猜 Python 解释器在内部可能做了优化,像 print A(), A() 这样的语句,解释器认为没有必要创建不同的对象,直接返回同一个实例的引用得了。是不是觉得解释器有些自作聪明!而当 A() is A() 这样的表达式出现时,解释器想,我不能再自作聪明,那样可能会误导别人。可是,在 print 语句那样的用法时,就已经误导我了,我都差点开始怀疑人生了!

从语法来看,大家应该知道,我在测试时使用的 Python 2。我后来也试了下 Python 3:

>>> class A():
...     pass
...
>>> print(A(), A())
<__console__.A object at 0x10fe7afd0> <__console__.A object at 0x10fed79e8>
>>> print(A(), A())
<__console__.A object at 0x10fec0cc0> <__console__.A object at 0x10feda160>
>>> print(A(), A())
<__console__.A object at 0x10fe7afd0> <__console__.A object at 0x10fed7940>
>>> A() is A()
False

我想,这样的结果才是不会让人困惑的。可能是 Python 社区意识到了这个问题并在 Python3 中进行了修正。这样的修正是好的,否则对于像我同事那样初次使用 Python 的人来说是很困惑的。

个人认为,Python3 对过去的一些“错误”的修正是好的。例如将 print 改为函数,提供了丰富的参数来控制输出的样式;对编码的调整等等。

The above is the detailed content of Introduction to new class method, init instance method and singleton mode in Python (with examples). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete