Python : 使用装饰器在文件上写入日志
Python : Using Decorators to write Logs on a file
我正在尝试使用 python 装饰器在文件上写入日志,当我在一种方法上使用它时它可以工作,但是一旦我开始尝试在多种方法上使用它,事情开始变得混乱。
例如,如果我有 2 个方法 A() 和 B() 的 2 个日志,B() 在 A() 内部被调用,一个用于当我调用它时,一个用于当我调用它时结束它事情变成这样:A1 B1 B2 A2 B1 B2 B1 B2
A1 到 A2 没问题,但之后 B() 被调用了 x 次(调用次数显然发生了变化),我不明白为什么。
这是我的装饰器:
class LogDecorator(object):
state: str
def __init__(self, state):
self.state = state
self.log_file = 'log.txt'
def __call__(self, *function):
if len(function) >= 1:
def wrapper(params=None):
if self.state == 'main':
self.reset_log_file()
function_name = function[0].__name__
self.append_log_to_file('Calling function ' + function_name + '...')
result = function[0]() if params is None else function[0](params)
self.append_log_to_file('Function ' + function_name + ' ended. Returned ' + str(result))
return result
return wrapper
def __get__(self, obj, objtype):
return functools.partial(self.__call__, obj)
def append_log_to_file(self, message: str) -> None:
log_file = open(self.log_file, 'a')
log_file.write(message)
log_file.close()
def reset_log_file(self):
log_file = open(self.log_file, 'w+')
log_file.write('')
log_file.close()
我使用 'main' 状态,因为我在 API 的端点上,我想为每个 API 调用重置文件。
这是我的第一个class主状态
class AppService:
@staticmethod
@LogDecorator(state='main')
def endpoint() -> Response:
response: Response = Response()
response.append_message('Getting all tests')
tests: list = TestDAO.get_all()
return response
这是我的第二个class
class TestDAO(BaseDAO):
@staticmethod
@LogDecorator(state='sub')
def get_all() -> list:
return db.session.query(Test).all()
此示例中的预期输出为
Calling function endpoint...
Calling function get_all...
Function get_all ended. Returned [Objects]
Function endpoint ended. Returned {Object}
但我得到了
Calling function endpoint...
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Function endpoint ended. Returned {Object}
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
谁能弄清楚为什么装饰器会这样?
提前致谢
让我们期待以下示例的输出。
def decorator(f):
def g():
print('Hello, G.')
return g
@decorator
def f():
print('Hello, F.')
f()
它将打印
Hello, G.
装饰器根本没有装饰f
,而是f
没有任何装饰,它return是一个全新的方法(定义为g
) .或者,装饰器也可以 return 匿名方法。
def decorator(f):
return lambda : print('Hello, G.')
装饰器做的就是这个。它采用一个方法(必要时带有参数)并可能使用给定的方法(又名装饰)定义一个新方法。然后它 return 是新定义的方法,但与给定函数具有相同的名称。以下抽象会有所帮助。
@decorator
def f():
print('Hello, F.')
vvvvvvvvvvvvvvvvvvvvvv
def f(): # the name is not changed
#def g(): as if anonymous function
print('Hello, G.')
所以看起来decoratedf
,然而,它是一个new方法,只是命名为f
。如果你从 AppService
调用 TestDAO.get_all
,你调用的已经是 decorated TestDAO.get_all
.
显然我的问题是在调试模式下,当我“观察”作为函数的变量的值时,函数再次 运行。
去掉断点问题就解决了
我正在尝试使用 python 装饰器在文件上写入日志,当我在一种方法上使用它时它可以工作,但是一旦我开始尝试在多种方法上使用它,事情开始变得混乱。
例如,如果我有 2 个方法 A() 和 B() 的 2 个日志,B() 在 A() 内部被调用,一个用于当我调用它时,一个用于当我调用它时结束它事情变成这样:A1 B1 B2 A2 B1 B2 B1 B2
A1 到 A2 没问题,但之后 B() 被调用了 x 次(调用次数显然发生了变化),我不明白为什么。
这是我的装饰器:
class LogDecorator(object):
state: str
def __init__(self, state):
self.state = state
self.log_file = 'log.txt'
def __call__(self, *function):
if len(function) >= 1:
def wrapper(params=None):
if self.state == 'main':
self.reset_log_file()
function_name = function[0].__name__
self.append_log_to_file('Calling function ' + function_name + '...')
result = function[0]() if params is None else function[0](params)
self.append_log_to_file('Function ' + function_name + ' ended. Returned ' + str(result))
return result
return wrapper
def __get__(self, obj, objtype):
return functools.partial(self.__call__, obj)
def append_log_to_file(self, message: str) -> None:
log_file = open(self.log_file, 'a')
log_file.write(message)
log_file.close()
def reset_log_file(self):
log_file = open(self.log_file, 'w+')
log_file.write('')
log_file.close()
我使用 'main' 状态,因为我在 API 的端点上,我想为每个 API 调用重置文件。
这是我的第一个class主状态
class AppService:
@staticmethod
@LogDecorator(state='main')
def endpoint() -> Response:
response: Response = Response()
response.append_message('Getting all tests')
tests: list = TestDAO.get_all()
return response
这是我的第二个class
class TestDAO(BaseDAO):
@staticmethod
@LogDecorator(state='sub')
def get_all() -> list:
return db.session.query(Test).all()
此示例中的预期输出为
Calling function endpoint...
Calling function get_all...
Function get_all ended. Returned [Objects]
Function endpoint ended. Returned {Object}
但我得到了
Calling function endpoint...
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Function endpoint ended. Returned {Object}
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
Calling function get_all...
Function get_all ended. Returned [Objects]
谁能弄清楚为什么装饰器会这样?
提前致谢
让我们期待以下示例的输出。
def decorator(f):
def g():
print('Hello, G.')
return g
@decorator
def f():
print('Hello, F.')
f()
它将打印
Hello, G.
装饰器根本没有装饰f
,而是f
没有任何装饰,它return是一个全新的方法(定义为g
) .或者,装饰器也可以 return 匿名方法。
def decorator(f):
return lambda : print('Hello, G.')
装饰器做的就是这个。它采用一个方法(必要时带有参数)并可能使用给定的方法(又名装饰)定义一个新方法。然后它 return 是新定义的方法,但与给定函数具有相同的名称。以下抽象会有所帮助。
@decorator
def f():
print('Hello, F.')
vvvvvvvvvvvvvvvvvvvvvv
def f(): # the name is not changed
#def g(): as if anonymous function
print('Hello, G.')
所以看起来decoratedf
,然而,它是一个new方法,只是命名为f
。如果你从 AppService
调用 TestDAO.get_all
,你调用的已经是 decorated TestDAO.get_all
.
显然我的问题是在调试模式下,当我“观察”作为函数的变量的值时,函数再次 运行。
去掉断点问题就解决了