我只是试图简化我的一个类,并引入了一些与flyweight设计模式相同风格的功能。
然而,我有点困惑,为什么__init__总是在__new__之后被调用。我没想到会这样。有人能告诉我为什么会发生这种情况,我如何才能实现这个功能吗?(除了将实现放在__new__中,这感觉相当粗糙。)
这里有一个例子:
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
Why?
__new__是静态类方法,而__init__是实例方法。
__new__必须先创建实例,所以__init__可以初始化它。注意,__init__以self作为参数。在你创造实例之前,没有自我。
现在,我猜想,您正在尝试用Python实现单例模式。有几种方法可以做到这一点。
此外,从Python 2.6开始,您可以使用类装饰器。
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
参考这个文档:
在继承不可变内置类型(如数字和字符串)时,
偶尔在其他情况下,会出现静态方法__new__
派上了用场。__new__是实例构造的第一步,被调用
__init__之前。
__new__方法是用类来调用的
第一个参数;它的职责是返回该函数的一个新实例
类。
将其与__init__进行比较:__init__是通过实例调用的
作为它的第一个参数,它不返回任何东西;它的
职责是初始化实例。
有一些情况
在没有调用__init__(例如
当实例从pickle加载时)。没有办法去创造
一个不调用__new__的新实例(尽管在某些情况下可以
不需要调用基类的__new__)。
关于你想要达到的目标,还有关于单例模式的相同文档信息
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
您也可以使用PEP 318中的这个实现,使用装饰器
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
当__new__返回同一类的实例时,__init__随后在返回的对象上运行。也就是说,你不能使用__new__来阻止__init__被运行。即使你从__new__返回之前创建的对象,它也会被__init__一次又一次地初始化。
下面是单例模式的通用方法,它扩展了上面的vartec答案并修复了它:
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
完整的故事在这里。
另一种方法,实际上涉及__new__,是使用类方法:
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"
请注意,使用这种方法,你需要用@classmethod装饰你的所有方法,因为你永远不会使用MyClass的任何真实实例。