@classmethod 在 Python 中的类之外做什么?

问题描述 投票:0回答:1

在下面的代码中,如果存在

@classmethod
注释,则允许内部 def
new()
代替目标的
__new__()
——但该类会传递两次。如果
@classmethod
被删除,那么我们会收到类似“”的错误。
@classmethod
在这里做什么?有没有办法不用它? (我的动机是清晰:我不理解的代码看起来像是等待发生的事故。)

"""Namedtuple annotation.

Creates a namedtuple out of a class, based on the signature of that class's
__init__ function. Defaults are respected. After namedtuple's initializer is
run, the original __init__ is run as well, allowing one to assign synthetic
parameters and internal book-keeping variables.

The class must not have varargs or keyword args.
"""     
import collections
import inspect


def namedtuple(cls):
    argspec = inspect.getargspec(cls.__init__)
    assert argspec.varargs is None
    assert argspec.keywords is None 
    non_self_args = argspec.args[1:]

    # Now we can create the new class definition, based on a namedtuple.
    bases = (collections.namedtuple(cls.__name__, non_self_args), cls)
    namespace = {'__doc__': cls.__doc__}
    newcls = type(cls.__name__, bases, namespace)

    # Here we set up the new class's __new__, which hands off to namedtuple's
    # after setting defaults.
    @classmethod
    def new(*args, **kwargs):
        kls, _kls_again = args[:2]              # The class is passed twice...?
        # Resolve default assignments with this utility from inspect.
        values = inspect.getcallargs(cls.__init__, None, *args[2:], **kwargs)
        values = [values[_] for _ in non_self_args]
        obj = super(newcls, kls).__new__(kls, *values)
        cls.__init__(obj, *values)              # Allow initialization to occur
        return obj
    # The @classmethod annotation is necessary because otherwise we get an
    # error like "unbound method new takes a class instance".

    newcls.__new__ = new

    return newcls
python python-decorators class-method
1个回答
2
投票

__new__
被视为 static 方法,而不是类方法,并且在由 Python 调用时直接在类上查找。 Python 显式地传入类对象作为第一个参数。请参阅文档

__new__()
是一个静态方法(特殊情况,因此您不需要这样声明),它将请求实例的类作为其第一个参数

通过使其成为类方法,该方法将绑定到类,并且除了显式类之外,还会自动传入该类,这就是为什么您会获得两次。 classmethod

 对象是一个 
descriptorstaticmethod
function
property
 对象也是如此),它是触发绑定行为的类或实例的查找。 

您不应该使用

classmethod

。 Python 在创建类时将其设为静态方法,因此如果您要使用

def new(*args, **kwargs): # ... namespace = {'__doc__': cls.__doc__, '__new__': new} newcls = type(cls.__name__, bases, namespace)

而不是事后将其设置在类上,然后省略

@classmethod

 装饰器就足够了:

def new(*args, **kwargs): kls = args[0] # Resolve default assignments with this utility from inspect. values = inspect.getcallargs(cls.__init__, None, *args[1:], **kwargs) values = [values[_] for _ in non_self_args] obj = super(newcls, kls).__new__(kls, *values) cls.__init__(obj, *values) # Allow initialization to occur return obj

或者,手动将其设为

staticmethod

@staticmethod def new(*args, **kwargs): # ... newcls.__new__ = new

考虑到

namedtuple

 生成的类是 
immutable,因此如果影子类 __init__
 方法尝试使用与 
__init__
 参数相同的名称设置参数,您将得到 
AttributeError
 异常.

© www.soinside.com 2019 - 2024. All rights reserved.