python - Python 类中的装饰器
问题描述
对不起我的英语不好。我想创建一个装饰器方法,它可以检查每个步骤方法并将其写入数据库。
这是我的方法:
class Test:
@StepStatusManager.logger_steps("GET_LIST") # TypeError: logger_steps() missing 1 required positional argument: 'type'
def get_mails(self):
print("GET_MAIL")
这是我的装饰类:
class StepStatusManager:
def __init__(self):
self.db = DB()
def logger_steps(self, type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
self.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
解决方案
您正在尝试logger_steps
直接从类调用实例方法 ,StepStatusManager
而 Python 将值"GET_LIST"
作为self
参数而不是type
。您应该创建一个实例,StepStatusManager
然后让装饰器调用实例的方法。它可以很简单:
manager = StepStatusManager()
class Test:
@manager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
这现在是创建类的实例,然后调用实例上的方法,而不是尝试直接从类中调用方法。您现在可以根据manager
需要使用来装饰任意数量的方法。此外,这将使所有装饰方法都使用相同的StepStatusManager
,但如果您愿意,您可以创建不同的实例并使用它们来装饰不同的方法;如果需要,这将允许您对self.db
不同的方法使用不同的方法。
另一种方法可能是db
在类中包含变量,并改为创建logger_steps
一个类方法:
class StepStatusManager:
db = DB()
@classmethod
def logger_steps(cls, type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
cls.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
但是请注意,这不太灵活,因为它不允许您使用不同的管理器装饰方法,如果您需要的话。此外,这几乎等同于拥有一个模块而不是一个类,StepStatusManager
其中db
是一个模块变量并且logger_steps
是一个模块函数,如果您想要这个功能,这可能会更清楚:
# StepStatusManager.py
# ...
db = DB()
def logger_steps(type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
cls.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
# test.py
import StepStatusManager
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
同样,作为您提出的第一个基于类的解决方案,这可能更直接但不太灵活。
编辑:
只是为了完整性和比较,这里还有另一个版本,类似于 with 的版本@classmethod
,但@staticmethod
改为使用(要了解这两个装饰器之间的细微差别,请检查有关它的许多 SO 问题之一,例如What is the difference between @staticmethod和@classmethod?或@classmethod 和@staticmethod 对初学者的意义?):
class StepStatusManager:
db = DB()
@staticmethod
def logger_steps(type):
def logger_steps(func):
@functools.wraps(func)
def wrapper(*args):
try:
func(*args)
StepStatusManager.db.setStatus(type)
except BaseException as e:
print(e)
return wrapper
return logger_steps
class Test:
@StepStatusManager.logger_steps("GET_LIST")
def get_mails(self):
print("GET_MAIL")
由于@classmethod
和经常发生这种情况@staticmethod
,因此差异非常小。如果您使用继承,或者使用元类、装饰器或类似的东西,它们的行为可能会有所不同,但除此之外它们几乎相同。
推荐阅读
- swift - 如何根据内容自动调整 NSTextView 的大小?
- arrays - 使用 ArrayFormula() 进行小计
- c# - ExRam Gremlinq 无法与 Cosmos DB 一起使用
- python - beaglebone black:启用 uart 时没有插槽
- sql-server-2016 - 在 SQL Server 2016 WITH 和 OPENJSON 中使用条件来更改更新值
- react-native - React Native领域获取对象返回没有值的数组
- jdbc - 独立模式下的 SQL Server Kafka 连接器未在 kafka 中加载数据
- flutter - Flutter Firebase Messaging 仅适用于 iOS 模拟器
- python - Plotly:如何为 Scattergeo 设置手动边界框?
- android - 重新创建的活动在后按时返回首页,启动 API 28