>  기사  >  백엔드 개발  >  Python의 새로운 클래스 메서드, init 인스턴스 메서드 및 싱글톤 모드 소개(예제 포함)

Python의 새로운 클래스 메서드, init 인스턴스 메서드 및 싱글톤 모드 소개(예제 포함)

不言
不言앞으로
2019-01-28 11:18:552210검색

이 글은 Python의 새로운 클래스 메소드, init 인스턴스 메소드 및 싱글톤 모드(예제 포함)를 소개합니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

"모든 클래스가 Python 싱글턴 모드인가요?" 어느 날 동료가 이런 질문을 했습니다. 이것은 이상한 질문입니다. 아마도 당신도 그렇게 생각할 것입니다. 여기에서는 설명을 생략하고 먼저 __new__ 및 __init__ 메서드를 살펴보겠습니다.

new 및 init

__new__ 메소드는 새 스타일 클래스에 속합니다. 즉, 객체 클래스에 속합니다. 이는 정적 메서드이지만 첫 번째 매개 변수는 클래스(cls)여야 하며 이는 클래스 메서드와 약간 비슷합니다. 이 특수 메서드가 호출되면 클래스(cls)의 새 인스턴스가 생성되고 반환됩니다. 인스턴스가 생성된 후 인터프리터는 인스턴스와 기타 매개변수를 인스턴스의 초기화 함수 __init__에 전달하여 인스턴스를 초기화합니다.

그래서 __new__ 메서드는 인스턴스를 생성하는 데 사용되는 클래스 메서드이고, __init__ 메서드는 인스턴스를 초기화하는 데 사용되는 인스턴스 메서드입니다.

__new__ 메서드는 클래스를 인스턴스화할 때 호출됩니다. 이 메서드를 재정의하는 방법은 다음과 같습니다.

class A(object):

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

__new__ 메서드가 cls 인스턴스를 반환하지 않으면 new 인스턴스의 __init__ 메서드는 호출되지 않습니다. Python 3.3 이후에는 새 메서드가 더 이상 추가 매개변수를 받지 않습니다. 그렇지 않으면 TypeError: object()가 매개변수를 사용하지 않는다는 예외가 발생합니다.

__init__ 메서드는 인스턴스가 생성된 후에 호출됩니다. 이 메서드는 __new__ 메서드로 생성된 인스턴스에 대해 일부 초기화 작업만 수행합니다. 새 메소드가 인스턴스를 반환하는 경우 init 메소드는 항상 호출된다는 점에 유의하세요(싱글톤을 구현하기 위해 새 메소드를 사용할 때 특히 주의해야 합니다)

몇 가지 확인을 수행할 수 있습니다. # 🎜🎜#

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
출력 결과:

__new__ is called
__init__ is called
Foo(m=1, n=2)
그래서 결론을 내릴 수 있습니다.

1은 클래스 수준 메서드가 아니더라도 마찬가지입니다. 클래스 메소드로 장식되어 프로세스 생성을 결정합니다.

2. __init__은 속성 추가, 초기화 매개변수 판단 및 변환 등 인스턴스 초기화 프로세스를 결정하는 인스턴스 수준 메서드입니다.

다시 작성된 __new__ 메소드와 __init__ 메소드의 매개변수는 일관되어야 하며, 그렇지 않으면 TypeError가 발생한다는 점에 유의해야 합니다. object.__new__()를 직접 호출하면 Python 3.3 이상 버전에서 들어오는 매개변수가 더 이상 지원되지 않습니다. 이 참조는 https://stackoverflow.com/questions/34777773/typeerror...

#입니다. 🎜🎜#__init__ 메소드는 일반적으로 클래스를 정의할 때 포함되며, 흔히 사용되는 메소드이기도 합니다. __new__ 메소드는 거의 사용되지 않습니다. 그렇다면 그 용도는 무엇입니까?

new 메소드 함수

__new__ 메소드에서 더 일반적으로 사용되는 함수는 다음과 같습니다.

1. int, str , tuple로), 사용자 정의 인스턴스화 프로세스를 제공합니다. __init__ 메서드에서 모든 쓰기 작업을 수행하면 유효하지 않을 수 있기 때문입니다. 예:

class CustomInt(int):

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

print CustomInt(-1)

# 输出:-1

이는 원하는 효과를 얻지 못할 수도 있습니다. 하지만 이는 __new__ 메소드를 재정의하여 달성할 수 있습니다:

class CustomInt(int):

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

print CustomInt(-1)

# 输出:1
  • 2. ). 메타클래스는 클래스를 생성하는 방법을 정의하는 데 사용됩니다. 해당 개념은 약간 복잡할 수 있으므로 여기서는 자세히 설명하지 않습니다. __new__ 方法来实现:

    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()  # 断言成功
    • 2、 实现自定义的元类(metaclass)。元类就是用来定义如何创建类,它的概念可能稍微复杂些,这里不做详细讨论。

    • 3、 实现单例。由于类产生实例的过程是通过 __new__ 方法来控制的,因此重写该方法来单例模式是非常方便的:

    print Singleton(), Singleton()

    所谓单例模式就是每次初始化都返回同一个实例,所以两次初始化得到的对象的内存地址应该是一样的:

    <__main__.Singleton object at 0x10d698650> <__main__.Singleton object at 0x10d698650>

    结果应该是显而易见的:

    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

    装饰器实现单例

    说到单例模式,除了用 __new__ 方法实现外,还有一些其他的方式,如装饰器、元类等。不同方式的实现有不同的作用,元类属于 Python 中更为高级的特性,本文不做讨论,我们来看一下用装饰器实现单例的方法。

    装饰器(decorator)可以动态地修改一个类或函数的功能,即类也可以被装饰器装饰。因此可以使用装饰器来装饰某个类,使其被初始化时只生成一个实例:

    >>> 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>

    需要注意的是,使用装饰器实现单例时,类已经变成了一个函数,而不再是类。 如上用上例中 MyClass 初始化实例时,实际上调用的是被装饰后返回的 getinstance 函数。

    __new__ 实现单例和用装饰实现单例的区别是,前者前者都是会调用 __init__

  • 3. 싱글턴을 구현합니다. 클래스의 인스턴스 생성 프로세스는 __new__ 메서드를 통해 제어되므로 싱글톤 모드를 사용하도록 이 메서드를 다시 작성하는 것이 매우 편리합니다. #🎜🎜#
>>> A() is A()
False
#🎜 🎜#소위 싱글턴 모드는 초기화될 때마다 동일한 인스턴스를 반환하는 것이므로 두 번의 초기화로 얻은 객체의 메모리 주소는 동일해야 합니다. #🎜🎜#
>>> 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
#🎜🎜#결과 명확해야 합니다: #🎜🎜# rrreee#🎜🎜#Decorator는 싱글톤을 구현합니다#🎜🎜##🎜🎜#싱글톤 모드에 대해 말하면 __new__ 메서드를 사용하는 것 외에도 몇 가지 다른 방법이 있습니다. 데코레이터, 요소 클래스 등과 같은 구현 방법에 따라 효과도 달라집니다. 메타클래스는 Python의 고급 기능이므로 이 문서에서는 데코레이터를 사용하여 싱글톤을 구현하는 방법을 살펴보겠습니다. #🎜🎜##🎜🎜#데코레이터는 클래스나 함수의 기능을 동적으로 수정할 수 있습니다. 즉, 클래스도 데코레이터에 의해 데코레이트될 수 있습니다. 따라서 데코레이터를 사용하여 클래스가 초기화될 때 하나의 인스턴스만 생성되도록 클래스를 장식할 수 있습니다. #🎜🎜#rrreee#🎜🎜#데코레이터를 사용하여 싱글톤을 구현할 때 클래스는 다음과 같이 됩니다. 클래스 대신 함수. 위의 예에서 MyClass를 사용하여 인스턴스를 초기화할 때 실제로 호출되는 것은 데코레이션된 후 반환되는 getinstance 함수입니다. #🎜🎜##🎜🎜#__new__를 사용하여 싱글톤을 구현하는 것과 데코레이션을 사용하여 싱글톤을 구현하는 것의 차이점은 전자가 __init__ 메서드를 호출한다는 것입니다. 각 초기화 중에 서로 다른 매개변수가 사용됩니다. 반환된 인스턴스는 동일하지만 인스턴스의 속성은 재설정되며, 후자는 나중에 다르게 전달되더라도 항상 첫 번째 초기화 중에 설정된 예제를 반환합니다. 매개변수. #🎜🎜#

奇怪现象

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

>>> 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 改为函数,提供了丰富的参数来控制输出的样式;对编码的调整等等。

위 내용은 Python의 새로운 클래스 메서드, init 인스턴스 메서드 및 싱글톤 모드 소개(예제 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제