@class 方法在 Python 中的 class 之外做了什么?
What's @classmethod do outside of a class in Python?
在下面的代码中,如果存在 @classmethod
注释,则允许内部 def new()
代表目标的 __new__()
-- 但 class 被传递了两次。如果 @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
__new__
被视为 static 方法,而不是 class 方法,调用时直接在 class 上查找通过 Python。 Python 明确地将 class 对象作为第一个参数传入。见 documentation:
__new__()
is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument
通过将其设为 class 方法,该方法绑定到 class 并且 class 除了显式 [=] 外还自动传入 50=],这就是你得到两次的原因。 classmethod
对象是 descriptor(staticmethod
、function
和 property
对象也是如此)并且它是对 class 或实例的查找触发绑定行为。
你不应该使用 classmethod
。 Python 在创建 class 时使其成为静态方法,因此如果您要使用
def new(*args, **kwargs):
# ...
namespace = {'__doc__': cls.__doc__, '__new__': new}
newcls = type(cls.__name__, bases, namespace)
而不是事后将其设置在 class 上,然后省略 @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
生成的 class 是 不可变的 ,因此如果隐藏 class __init__
方法尝试使用与 __init__
参数相同的名称设置参数,你会得到一个 AttributeError
异常。
在下面的代码中,如果存在 @classmethod
注释,则允许内部 def new()
代表目标的 __new__()
-- 但 class 被传递了两次。如果 @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
__new__
被视为 static 方法,而不是 class 方法,调用时直接在 class 上查找通过 Python。 Python 明确地将 class 对象作为第一个参数传入。见 documentation:
__new__()
is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument
通过将其设为 class 方法,该方法绑定到 class 并且 class 除了显式 [=] 外还自动传入 50=],这就是你得到两次的原因。 classmethod
对象是 descriptor(staticmethod
、function
和 property
对象也是如此)并且它是对 class 或实例的查找触发绑定行为。
你不应该使用 classmethod
。 Python 在创建 class 时使其成为静态方法,因此如果您要使用
def new(*args, **kwargs):
# ...
namespace = {'__doc__': cls.__doc__, '__new__': new}
newcls = type(cls.__name__, bases, namespace)
而不是事后将其设置在 class 上,然后省略 @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
生成的 class 是 不可变的 ,因此如果隐藏 class __init__
方法尝试使用与 __init__
参数相同的名称设置参数,你会得到一个 AttributeError
异常。