python - 为什么不需要静态方法装饰器?

标签 python python-3.x

我正在尝试使用类装饰器来实现单例模式,如下所示:

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/

相关文章:

python - 如何使用 django 显示无效电子邮件地址的错误消息

python - 如何从 Python 中的字符串中删除空行?

Python - 需要类似字节的对象,而不是 'str'

python - 类型错误: 'range' 对象在没有明显原因的情况下不可调用

python - 如何使用 `json` 将任意 `CustomJS` 数据从 python 传递到 bokeh

python - MAC地址到二进制位的转换

python - Eclipse 控制台中的 Pydev 源文件超链接

python - 正则表达式匹配内部 '.'

python - 如何定期更改 tkinter 图像?

python - 尝试仅使用 while 循环来计算字母出现的次数