Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么总是在新的之后调用初始化?_Python_Design Patterns_Class Design - Fatal编程技术网

Python 为什么总是在新的之后调用初始化?

Python 为什么总是在新的之后调用初始化?,python,design-patterns,class-design,Python,Design Patterns,Class Design,我只是试图简化我的一个类,并引入了一些与 然而,我有点困惑,为什么\uuuu init\uuuu总是在\uu new\uuuu之后调用。我没想到会这样。有谁能告诉我为什么会发生这种情况,以及我如何实现这种功能?(除了将实现放在感觉相当粗糙的\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu中。) 下面是一个例子: class A(object): _dict = dict() def __new__(cl

我只是试图简化我的一个类,并引入了一些与

然而,我有点困惑,为什么
\uuuu init\uuuu
总是在
\uu new\uuuu
之后调用。我没想到会这样。有谁能告诉我为什么会发生这种情况,以及我如何实现这种功能?(除了将实现放在感觉相当粗糙的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
中。)

下面是一个例子:

class A(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in A._dict:
            print "EXISTS"
            return A._dict['key']
        else:
            print "NEW"
            return super(A, cls).__new__(cls)

    def __init__(self):
        print "INIT"
        A._dict['key'] = self
        print ""

a1 = A()
a2 = A()
a3 = A()
产出:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

为什么?

是静态类方法,而
是实例方法。
\uuuuu new\uuuuu
必须首先创建实例,因此
\uuuuuu init\uuuuuuuuu可以对其进行初始化。请注意,
\uuuu init\uuu
self
作为参数。在创建实例之前,没有任何
自我

现在,我想,您正试图用Python实现它。有几种方法可以做到这一点

另外,在Python2.6中,您可以使用类

当您需要控制时,请使用
\uuuuu new\uuuu
创建一个新实例

使用
\uuuu init\uuuu
当您需要控制新实例的初始化时


\uuuuu new\uuuuu
是创建实例的第一步。它叫first,而且是 负责退回新的 您的类的实例

相比之下,
\uuuu init\uuuu
不返回任何内容;它只负责初始化 实例创建之后

一般来说,你不需要这样做 除非您 子类化不可变类型,如 str、int、unicode或tuple

2008年4月发布:在mail.python.org上

你应该考虑一下你想做的事情通常是用A做的,这是最好的方法。使用<强> >代码> NeXy< 并不是一个好的干净解决方案,所以请考虑工厂的使用。这里有一个很好的例子:

然而,我有点困惑,为什么
\uuuu init\uuuu
总是在
\uu new\uuuu
之后调用

没有太多的原因,除了它只是这样做
\uuuuuuuuuuuuuuu new\uuuuuuuu
没有初始化类的责任,其他一些方法有此责任(
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu调用,可能——我不确定

我没想到会这样。有人能告诉我为什么会发生这种情况,以及我如何实现这种功能吗?(除了将实现放在感觉相当粗糙的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
中之外)


如果已经初始化,您可以让
\uuuuu init\uuuuuu
什么都不做,或者您可以使用新的
\uuuu调用
编写一个新的元类,该元类只在新实例上调用
\uuuu init\uuuuuuuuuu
,否则只返回
\uuuu new\uuuuuuuuuu(…)

\uuuuu new\uuuu>应该返回一个新的类的新的空白实例__然后调用init_u初始化该实例。在“新”的情况下,你不是在叫“新”,所以是在叫你。调用
\uuuuu new\uuuuu
的代码不会跟踪是否在特定实例上调用了uuu init\uuuu,也不应该这样做,因为您在这里做了一些非常不寻常的事情

您可以在_init__函数中向对象添加一个属性,以指示该对象已初始化。检查该属性是否存在,这是uu init_uuu中的第一件事,如果已经存在,请不要再继续操作。

引用以下内容:

典型的实现通过调用 使用“super(currentclass, cls)。_unew__u(cls[,…]),带有适当的参数,然后 在返回新创建的实例之前,根据需要修改它

如果uuuuuuuuuuuuuuuuuuuu new()未返回cls实例,则新 将不会调用实例的uuu init_uuuu()方法

__新的u z()主要用于允许immutable的子类 类型(如int、str或tuple)来自定义实例创建


在大多数著名的OO语言中,像
SomeClass(arg1,arg2)
这样的表达式将分配一个新实例,初始化实例的属性,然后返回它


在大多数著名的OO语言中,“初始化实例属性”部分可以通过定义构造函数来为每个类定制,它基本上只是一块代码,在新实例上操作(使用提供给构造函数表达式的参数),以设置所需的任何初始条件。在Python中,这对应于类“
\uuuu init\uu
方法

Python的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
与“分配一个新实例”部分的每类定制类似。当然,这允许您执行不寻常的操作,例如返回现有实例,而不是分配新实例。所以在Python中,我们不应该认为这一部分必然涉及分配;我们所需要的只是
\uuuuu new\uuuu
从某个地方找到一个合适的实例

但它仍然只是作业的一半,Python系统无法知道有时您希望在之后运行作业的另一半(
\uuuuuu init\uuuuu
),而有时您不想。如果你想要这种行为,你必须明确地说出来

通常,您可以重构以便只需要
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
,或者不需要
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。但是如果您真的想这样做,Python实际上允许您重新定义“作业”,这样
SomeClass(arg1,arg2)
就不必调用
\uuuuuuu new\uuuu
,然后再调用
\uuu init\uuuu
。为此,您需要创建一个元类,并定义其
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...
class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance
class Agent(object):
    _agents = dict()

    def __new__(cls, *p):
        number = p[0]
        if not number in cls._agents:
            cls._agents[number] = object.__new__(cls)
        return cls._agents[number]

    def __init__(self, number):
        self.number = number

    def __eq__(self, rhs):
        return self.number == rhs.number

Agent("a") is Agent("a") == True
class Singleton(object):
        def __new__(cls, *args, **kwds):
            it = cls.__dict__.get("__it__")
            if it is not None:
                return it
            cls.__it__ = it = object.__new__(cls)
            it.init(*args, **kwds)
            return it
        def init(self, *args, **kwds):
            pass
def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
...
def SingletonClass(cls):
    class Single(cls):
        __doc__ = cls.__doc__
        _initialized = False
        _instance = None

        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
            return cls._instance

        def __init__(self, *args, **kwargs):
            if self._initialized:
                return
            super(Single, self).__init__(*args, **kwargs)
            self.__class__._initialized = True  # Its crucial to set this variable on the class!
    return Single
class Singleton(object):
    __initialized = False

    def __new__(cls, *args, **kwargs):
        if not cls.__initialized:
            cls.__init__(*args, **kwargs)
            cls.__initialized = True
        return cls


class MyClass(Singleton):
    @classmethod
    def __init__(cls, x, y):
        print "init is here"

    @classmethod
    def do(cls):
        print "doing stuff"
class M(type):
    _dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print 'EXISTS'
            return cls._dict[key]
        else:
            print 'NEW'
            instance = super(M, cls).__call__(key)
            cls._dict[key] = instance
            return instance

class A(object):
    __metaclass__ = M

    def __init__(self, key):
        print 'INIT'
        self.key = key
        print

a1 = A('aaa')
a2 = A('bbb')
a3 = A('aaa')
NEW
INIT

NEW
INIT

EXISTS
class MetaQuasiSingleton(type):
    def __init__(cls, name, bases, attibutes):
        cls._dict = {}

    def __call__(cls, key):
        if key in cls._dict:
            print('EXISTS')
            instance = cls._dict[key]
        else:
            print('NEW')
            instance = super().__call__(key)
            cls._dict[key] = instance
        return instance

class A(metaclass=MetaQuasiSingleton):
    def __init__(self, key):
        print 'INIT'
        self.key = key
        print()
def _alt(func):
    import functools
    @functools.wraps(func)
    def init(self, *p, **k):
        if hasattr(self, "parent_initialized"):
            return
        else:
            self.parent_initialized = True
            func(self, *p, **k)

    return init


class Parent:
    # Empty dictionary, shouldn't ever be filled with anything else
    parent_cache = {}

    def __new__(cls, n, *args, **kwargs):

        # Checks if object with this ID (n) has been created
        if n in cls.parent_cache:

            # It was, return it
            return cls.parent_cache[n]

        else:

            # Check if it was modified by this function
            if not hasattr(cls, "parent_modified"):
                # Add the attribute
                cls.parent_modified = True
                cls.parent_cache = {}

                # Apply it
                cls.__init__ = _alt(cls.__init__)

            # Get the instance
            obj = super().__new__(cls)

            # Push it to cache
            cls.parent_cache[n] = obj

            # Return it
            return obj
class A(Parent):

    def __init__(self, n):
        print("A.__init__", n)


class B(Parent):

    def __init__(self, n):
        print("B.__init__", n)
>>> A(1)
A.__init__ 1  # First A(1) initialized 
<__main__.A object at 0x000001A73A4A2E48>
>>> A(1)      # Returned previous A(1)
<__main__.A object at 0x000001A73A4A2E48>
>>> A(2)
A.__init__ 2  # First A(2) initialized
<__main__.A object at 0x000001A7395D9C88>
>>> B(2)
B.__init__ 2  # B class doesn't collide with A, thanks to separate cache
<__main__.B object at 0x000001A73951B080>