Why is __init__() always called after __new__()?
我只是在尝试简化我的一个类,并以与flyweight设计模式相同的风格引入了一些功能。
不过,我有点困惑,为什么
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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() |
输出:
1 2 3 4 5 6 7 8 | NEW INIT EXISTS INIT EXISTS INIT |
为什么?
Use __new__ when you need to control
the creation of a new instance. Use
__init__ when you need to control initialization of a new instance.__new__ is the first step of instance creation. It's called first, and is
responsible for returning a new
instance of your class. In contrast,
__init__ doesn't return anything; it's only responsible for initializing the
instance after it's been created.In general, you shouldn't need to
override __new__ unless you're
subclassing an immutable type like
str, int, unicode or tuple.
发件人:http://mail.python.org/pipermail/tutor/2008-april/061426.html
你应该考虑一下,你想做的事情通常都是在工厂里完成的,这是最好的方法。使用"新"不是一个好的清洁解决方案,因此请考虑使用工厂。这里有一个很好的工厂例子。
现在,我了解到,您正试图在Python中实现单例模式。有几种方法可以做到这一点。
另外,从Python2.6开始,您可以使用类修饰符。
1 2 3 4 5 6 7 8 9 10 11 | def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... |
在大多数著名的OO语言中,像
在大多数著名的OO语言中,"初始化实例的属性"部分可以通过定义一个构造函数为每个类定制,它基本上只是一个代码块,在新实例上操作(使用提供给构造函数表达式的参数),以设置所需的任何初始条件。在python中,这对应于类'
python的
但它仍然只是作业的一半,而且Python系统无法知道,有时您希望在之后运行作业的另一半(
通常,您可以重构,这样您只需要
元类只是类的一个类。类"EDOCX1"〔11〕方法控制调用该类的实例时会发生什么。因此,元类"EDOCX1"(11)方法控制调用类时会发生什么;即,它允许您从头到尾重新定义实例创建机制。这是您可以最优雅地实现完全非标准实例创建过程(如单例模式)的级别。事实上,如果代码行少于10行,您就可以实现一个
1 2 3 4 5 6 7 8 | 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 |
然而,这可能是更深的魔法比真正保证这种情况!
引用文档:
Typical implementations create a new instance of the class by invoking
the superclass's __new__() method using"super(currentclass,
cls).__new__(cls[, ...])"with appropriate arguments and then
modifying the newly-created instance as necessary before returning it....
If __new__() does not return an instance of cls, then the new
instance's __init__() method will not be invoked.__new__() is intended mainly to allow subclasses of immutable
types (like int, str, or tuple) to customize instance creation.
我知道这个问题很古老,但我也有类似的问题。以下是我想要的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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 |
我将此页面用作资源http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html
我认为这个问题的简单答案是,如果
当
下面是对singleton模式的通用方法,它扩展了上面的vartec答案并修复了它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 |
完整的故事就在这里。
实际上涉及
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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" |
请注意,使用这种方法,您需要用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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 a1 = A('aaa') a2 = A('bbb') a3 = A('aaa') |
输出:
1 2 3 4 5 6 7 | NEW INIT NEW INIT EXISTS |
注意,作为副作用,
如果更新@antonyhatchkins的答案,您可能需要为元类型的每个类提供一个单独的实例字典,这意味着您应该在元类中有一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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() |
我已经使用
不管怎样,这里重要的一点是,如果找到了键,类初始值设定项(
_ new_uuu应返回类的新的空白实例。_然后调用init_uuu初始化该实例。在"新"的"新"案例中,你不会打电话给"初始",所以它是为你打电话的。调用
您可以在uu in it_uuu函数中向对象添加一个属性,以指示它已经初始化。检查该属性是否存在,作为uu in it_uuu中的第一件事,如果存在,则不要继续。
我们应该将
现在,对于python,
再深入一点!
cpython中一个泛型类的类型是
这里有趣的部分是,
此时,对象在内存中创建,然后调用
然后,
参考本文件:
When subclassing immutable built-in types like numbers and strings,
and occasionally in other situations, the static method new comes
in handy. new is the first step in instance construction, invoked
before init.The new method is called with the class as its
first argument; its responsibility is to return a new instance of that
class.Compare this to init: init is called with an instance
as its first argument, and it doesn't return anything; its
responsibility is to initialize the instance.There are situations
where a new instance is created without calling init (for example
when the instance is loaded from a pickle). There is no way to create
a new instance without calling new (although in some cases you can
get away with calling a base class's new).
关于您希望实现的目标,在同一个文档中也有关于singleton模式的信息
1 2 3 4 5 6 7 8 9 10 | 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中的这个实现,使用一个修饰器
1 2 3 4 5 6 7 8 9 10 11 | def singleton(cls): instances = {} def getinstance(): if cls not in instances: instances[cls] = cls() return instances[cls] return getinstance @singleton class MyClass: ... |
However, I'm a bit confused as to why init is always called after new.
< /块引用>
我认为C++类比在这里是有用的:(A)new只是为对象分配内存。对象的实例变量需要内存来保存它,这就是新步骤要做的。(B)init将对象的内部变量初始化为特定值(可以是默认值)。
在
__new__ 之后调用__init__ ,这样当您在子类中重写它时,您添加的代码仍然会被调用。如果您试图对已经有一个
__new__ 的类进行子类划分,那么不知道这一点的人可能会首先修改__init__ ,并将调用转发给__init__ 子类。在__new__ 之后打电话给__init__ 的公约有助于实现预期的效果。
__init__ 仍然需要考虑超类__new__ 所需的任何参数,但如果不这样做,通常会造成明显的运行时错误。而__new__ 应该明确允许*args 和‘**kw’,以明确扩展是可以的。通常情况下,由于原始海报描述的行为,将
__new__ 和__init__ 都放在同一类中,处于同一继承级别,这是不好的形式。简单的原因是新的用于创建实例,而init用于初始化实例。在初始化之前,应该先创建实例。这就是为什么在init之前应该调用new。
However, I'm a bit confused as to why
__init__ is always called after__new__ .除此之外,没有什么别的原因是这样做的。
__new__ 不负责初始化类,其他一些方法负责初始化(__call__ 可能——我不确定)。I wasn't expecting this. Can anyone tell me why this is happening and how I implement this functionality otherwise? (apart from putting the implementation into the
__new__ which feels quite hacky).如果已经初始化了
__init__ 就可以不做任何事情,或者可以用一个新的__call__ 编写一个新的元类,只在新实例上调用__init__ ,否则只返回__new__(...) 。现在我也遇到了同样的问题,出于某些原因,我决定避免使用装饰器、工厂和元类。我是这样做的:
主文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 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示例类
1
2
3
4
5
6
7
8
9
10 class A(Parent):
def __init__(self, n):
print("A.__init__", n)
class B(Parent):
def __init__(self, n):
print("B.__init__", n)在使用中
1
2
3
4
5
6
7
8
9
10
11 >>> 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>
- 警告:您不应该初始化父级,它将与其他类冲突-除非您在每个子级中定义了单独的缓存,否则这不是我们想要的。
- 警告:这似乎是一个家长作为祖父母的班级行为怪异。[未经证实]
尝试在线!