我有一堂课,其中有多种方法。我想使用其中一种方法作为其他方法的装饰器。为此,我使用以下语法:
@self.action
def execute(self,req):
其中 action 是我班级中的其他方法。但它不起作用并抛出异常
name 'self' is not defined
定义类时不能使用该类的方法;班级内没有
self
,班级也没有“烘焙”到可以访问任何班级。
您可以将方法视为函数来用作装饰器:
class SomeClass():
def action(func):
# decorate
return wrapper
@action
def execute(self, req):
# something
如果
action
是在基类上定义的,那么您必须通过基类引用该名称:
class Base():
@staticmethod
def action(func):
# decorate
return wrapper
class Derived(Base):
@Base.action
def execute(self, req):
# something
对于 Python 2,您必须在此处将
action
设置为静态方法,否则您会得到一个未绑定的方法,该方法会抱怨您无法在没有实例作为第一个参数的情况下调用它。在 Python 3 中,您可以省略 @staticmethod
装饰器,至少对于装饰器而言是如此。
但请注意,
action
不能直接用作方法;也许那时它根本不应该成为班级的一部分。这里它不是最终用户 API 的一部分,大概这些类的实例的使用者不使用装饰器。
需要注意的是,装饰器和被装饰函数都是未绑定方法,因此只能访问装饰器内部作用域中的 self(或者类方法的 cls),并且必须手动将装饰方法绑定到内部绑定的实例装饰器。
class A:
x = 5
y = 6
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
@decorate
def func(self):
return self.y
A().func() # 30!!
仍在尝试了解装饰器如何被继承和覆盖。
请注意,要使装饰器正常工作,它不能绑定到实例。那就是:没有办法让这个工作
a = A()
@a.decorate
def func(*args):
return 1
尽管这种模式比这里所要求的更常见。
此时提出了一个问题:它到底是一种方法还是只是您碰巧隐藏在类中的代码?
防止装饰器被错误绑定的唯一方法是将其声明为静态方法,但它必须位于先前的超类中,因为要使用它必须绑定到尚未定义的静态类引用,只需作为自己。
class A:
x = 1
@staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
class B(A):
@A.decorate
def func(self):
return 1
class C():
x = 2
@B.decorate
def func(self):
return 1
a = A()
class D():
x = 3
@a.decorate
def func(self):
return 1
B().func() # 1
C().func() # 2
D().func() # 3
但是正如你所看到的,装饰器没有办法使用自己类的状态。最后一个示例中的
class A
恰好是一个具有默认 x
变量和“不相关”静态装饰器的 mixin。
那么,这还是一种方法吗?
要克服所有这些问题,您可以将同一类中的静态方法绑定到任意类型。也就是说,内置的
type
就可以了。
class A:
x = 1
@staticmethod
def decorate(unbound):
def _decorator(self):
bound = unbound.__get__(self)
return bound() * self.x
return _decorator
@decorate.__get__(type)
def func(self):
return 1
class B:
x = 2
@A.decorate
def func(self):
return 1
class C:
x = 3
@(A().decorate) # Only for Python 3.9+, see PEP-614
def func(self):
return 1
A().func() # 1
B().func() # 2
C().func() # 3
但这对我来说太神奇了。但仍然不是我的直觉的方法。
在Python中,“self”作为参数传递给实例方法(第一个),“self”只是一个约定,可以将其称为“foobarbaz”(当然这很愚蠢)……重点是,从外部“self”没有定义(因为它的范围是方法)...你不能用其他类方法来装饰类方法,而是必须编写一个单独的类!
你可以这样做。
采用@N1ngu给出的答案的第一部分。您不需要
unbound.__get__(self)
。
装饰器只是一个静态方法,内部函数将 self 作为参数(或使用 *args 和 arg[0] 代表 self)。
您可以对内部函数中使用的参数使用两个选项之一:(1) 使用
(self, *args, **kwargs)
或 (2) 使用 (*args, **kwargs)
并使用 args[0] 作为 self。
所以这个例子将变成:
class A:
x = 5
y = 6
def decorate_with_self(func):
# You don't actually need `*args, **kwargs`
# But they make the function behave correctly in the general case
def _decorator(self, *args, **kwargs):
return func(self, *args, **kwargs) * self.x
return _decorator
def decorate_without_self(func):
# You don't actually need `**kwargs`
# But it makes the function behave correctly in the general case
def _decorator(*args, **kwargs):
# Use args[0] as self
return func(*args, **kwargs) * args[0].x
return _decorator
@decorate_with_self
def func1_to_decorate(self):
return self.y
@decorate_without_self
def func2_to_decorate(self):
return self.y
A().func1_to_decorate(), A().func2_to_decorate() # returns (30, 30)