我正在尝试使用类装饰器来实现单例模式,如下所示:
python3.6+
def single_class(cls):
cls._instance = None
origin_new = cls.__new__
# @staticmethod
# why staticmethod decorator is not needed here?
def new_(cls, *args, **kwargs):
if cls._instance:
return cls._instance
cls._instance = cv = origin_new(cls)
return cv
cls.__new__ = new_
return cls
@single_class
class A():
...
a = A()
b = A()
print(a is b ) # True
单例模式似乎运行良好,但我想知道为什么我的代码中的函数 new_
之上不需要 @staticmethod
,因为我知道cls.__new__
是一个静态方法。
class object:
""" The most base type """
...
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass
...
Update test with
python2.7+
@staticmethod
似乎在 py2
中需要,而在 py3
中不需要
def single_class(cls):
cls._instance = None
origin_new = cls.__new__
# @staticmethod
# without @staticmethod there will be a TypeError
# and work fine with @staticmethod adding
def new_(cls, *args, **kwargs):
if cls._instance:
return cls._instance
cls._instance = cv = origin_new(cls)
return cv
cls.__new__ = new_
return cls
@single_class
class A(object):
pass
a = A()
b = A()
print(a is b )
# TypeError: unbound method new_() must be called with A instance as the first argument (got type instance instead)
最佳答案
__new__
显式地将类实例作为其第一个参数。正如其他答案中提到的, __new__
是一种特殊情况,它成为静态方法的可能原因是允许使用 new 创建其他类:
super(CurrentClass, cls).__new__(otherCls, *args, **kwargs)
您的代码在没有 @staticmethod
装饰器的情况下在 Python 3 中工作但在 Python 2 中不起作用的原因是 Python 2 和 Python 3 允许类方法访问的方式不同。
Python 3 中没有无限方法 [ 2 ]。当你尝试访问 Python 3 上的类方法时,你会得到一个函数,而在 Python 2 中你会得到无界方法。如果您这样做,您可以看到这一点:
# Python 2
>>> A.__new__
<unbound method A.new_>
# Python 3
>>> A.__new__
<function __main__.single_class.<locals>.new_(cls, *args, **kwargs)>
在Python 2中,你的装饰器等于single_class.__new__(A)
,但由于__new__
是一个未绑定(bind)的方法,你不能用类本身来调用它。您需要一个类实例,但为此,您需要创建您的类(catch-22),这就是需要 staticmethod 的原因。错误消息表明同样的事情必须使用 A 实例作为第一个参数来调用未绑定(bind)方法 new_()
。
而在 Python 3 中,__new__
被视为一个函数,您可以使用 A 类本身来调用它。因此,single_class.__new__(A)
可以工作。
关于python - 为什么不需要静态方法装饰器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59729444/