在 Python 中,有时我们需要给类中的方法添加一些功能,或者改变方法的行为。我们可以通过使用装饰器来实现。
装饰器是一种可以修饰函数或方法的函数或类。它允许我们在不改变函数或方法本身的情况下,改变函数或方法的行为。
在下面的代码中,我们定义了一个 Synchronized 类,该类包含一个名为 synchronized 的装饰器。该装饰器可以将任意函数或方法包装在锁中,从而确保该函数或方法只能被一个线程同时访问。
import threading
from functools import wraps
class Synchronized(object):
def __init__(self):
self.lock = threading.Lock()
def synchronized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
with self.lock:
print("here")
return f(self, *args, **kwargs)
return wrapper
@synchronized
def go(self):
print(1)
class B(Synchronized):
@synchronized
def foo(self):
return 1
然而,当我们运行这段代码时,我们会得到一个错误:
NameError: name 'synchronized' is not defined
这是因为 Python 在解析装饰器名称时,会首先在当前类的作用域中查找。如果找不到,它会继续在父类的作用域中查找。
在上面的代码中,synchronized 装饰器是在 Synchronized 类中定义的。当我们试图在 B 类中使用 synchronized 装饰器时,Python 会首先在 B 类的作用域中查找,但找不到。然后,它会继续在 Synchronized 类的作用域中查找,但仍然找不到。因此,Python 会抛出一个错误。
2、解决方案
要解决这个问题,我们可以使用以下几种方法:
- 将 synchronized 装饰器定义在 Synchronized 类的外部。
def synchronized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
with self.lock:
print("here")
return f(self, *args, **kwargs)
return wrapper
class Synchronized(object):
def __init__(self):
self.lock = threading.Lock()
@synchronized
def go(self):
print(1)
class B(Synchronized):
@synchronized
def foo(self):
return 1
- 在 B 类中使用 Synchronized.synchronized.im_func 来访问 synchronized 装饰器。
import threading
from functools import wraps
class Synchronized(object):
def __init__(self):
self.lock = threading.Lock()
def synchronized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
with self.lock:
print("here")
return f(self, *args, **kwargs)
return wrapper
@synchronized
def go(self):
print(1)
class B(Synchronized):
@Synchronized.synchronized.im_func
def foo(self):
return 1
- 在 B 类中使用 @staticmethod 来修饰 synchronized 装饰器。
import threading
from functools import wraps
class Synchronized(object):
def __init__(self):
self.lock = threading.Lock()
@staticmethod
def synchronized(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
with self.lock:
print("here")
return f(self, *args, **kwargs)
return wrapper
@synchronized
def go(self):
print(1)
class B(Synchronized):
@synchronized
def foo(self):
return 1
这些方法都可以解决 Python 中装饰器名称解析的问题。