【发布时间】:2016-11-26 17:04:37
【问题描述】:
在 Python 3 中,如果返回的任何值不是 cls 的实例,则永远不会调用 __init__ 方法。例如,我可以这样做:
class Foo:
@staticmethod
def bar(n):
return n * 5
def __new__(cls, n):
return Foo.bar(n)
print(Foo(3)) # => 15
我的印象是订单是__call__(如果是实例)-> __new__ -> __init__。
但是,在 Python 2 中,由于缺少 __init__,这似乎引发了 TypeError: this constructor takes no arguments。我可以通过继承object 来解决这个问题。所以,运行这个:
class Foo:
def __new__(cls, *args, **kwargs):
print("new called")
def __init__(self, *args, **kwargs):
print("init called")
Foo()
"""
Python2: "init called"
Python3: "new called"
"""
在 Python 2 中,我什至搞砸了元类。
Meta = type("Meta", (type,), dict(__call__=lambda self, x: x * 5))
class Foo(object):
__metaclass__ = Meta
print(Foo(4)) # => 20
但这在 Python3 中不起作用,因为 init/new 方法似乎被颠倒了。
是否有任何兼容 Python2/3 的方式来执行此操作?
解决方案:
我就是这样做的。我不喜欢它,但它有效:
class Foo(object):
@staticmethod
def __call__(i):
return i * 5
def __new__(cls, i):
return Foo.__call__(i)
当然有一种更 Pythonic 的方式来做到这一点。
【问题讨论】:
标签: python python-2.7 python-3.x metaclass