我正在尝试使用类装饰器来实现单例模式,如下所示:
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
单例模式似乎运行良好,但是我想知道为什么在我的代码中@staticmethod
不需要在函数上方new_
,因为我知道这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
...
使用更新测试
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__
是一个未绑定的方法,因此您不能使用类本身来调用它。您需要一个类实例,但是为此,您需要创建您的类(catch-22),这就是为什么需要staticmethod的原因。错误消息说的是同样的话unbound method new_() must be called with A instance as first argument
。
在Python 3 __new__
中,您可以使用A类本身来调用它。因此,single_class.__new__(A)
将工作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句