我的 in-class 装饰器是否不够 Pythonic 或 PyCharm 在 lint 警告中不够聪明?
Is my in-class decorator not Pythonic enough or PyCharm not smart enough in lint warning?
我想在 class 中定义一个装饰器。我不想把它定义为一个分离的、独立的函数,因为这个装饰器是专门为这个 class 而我想把相关的方法放在一起的。
这个装饰器的目的是检查一些先决条件,尤其是成员变量持有的数据库连接、SSH连接等是否仍然可用。如果没有,装饰函数将不会被调用,并且会进行一些错误报告和清理工作。
我做了以下测试 class 来测试它是否有效,并且代码运行良好。但是我发现 PyCharm 显示了对这段代码的警告。所以我想知道,这是否意味着我的代码不是 Pythonic,或者 PyCharm 不够聪明,错误地给出了这个警告?
如果我的代码不是Pythonic,怎么改?
如果是 PyCharm 的错误,我和我的团队应该如何配置 PyCharm 让它专门忽略这种警告,同时保留大多数其他 lint 检查?
class TestClass:
def __init__(self):
self.flag = True
def dec(func):
def wrapper(self, *args, **kwargs):
if not self.flag:
print("Won't run!")
return empty_fun(self, *args, **kwargs)
return func(self, *args, **kwargs)
def empty_fun(*args, **kwargs):
return None
return wrapper
@dec
def foo(self):
print("foo")
@dec
def bar(self, msg, more, *args, **kwargs):
print("message: %s" % msg)
print("more %s:" % more)
for item in args:
print("other item: %s" % item)
name = kwargs.get('name')
age = kwargs.get('age')
print('name: %s' % name)
print('age: %s' % age)
def main():
t = TestClass()
t.foo()
print('-'*10)
t.bar("abc", 'def', 'hij', 'klm', name='Tom', age=20)
if __name__ == '__main__':
main()
这是 PyCharm 报告的 lint 警告:
您的代码在技术上是正确的(因为它将按预期工作),但需要注意的是 dec
将成为 TestClass
的方法并且如果这样调用将会中断。你至少应该把它设为 staticmethod
来避免这种情况。
wrt/ pythonicity,在不需要时使这个装饰器成为 class 的一部分确实是非 pythonic 的。它仅适用于此 class 的事实并不是使其成为 class 成员的理由,更不是使其成为 public API 成员的理由。
您可能可以在评论中添加 linter 提示以使其静音,但我个人只是从 class 中提取此装饰器,将其设为私有,并记录它只能与此 class.
作为旁注:我假设您的 empty_func
是 "error reporting and clean-up work" 的占位符 - 否则它根本没用 - 但它真的需要在装饰器中定义吗?
从 Python decorator as a staticmethod 开始,似乎不鼓励将装饰器放在 class 中。
想想看,Python 提供了这种很好的划分方式,称为 模块 。您是否考虑过将与此相关的所有代码 class 放在一个模块中,而将其他代码放在其他模块中?
I'd strongly recommend to move the decorator to the module scope -- it does not seem to belong inside the class. If you want to keep it inside the class, don't make it a staticmethod
, but rather simply del
it at the end of the class body -- it's not meant to be used from outside the class in this case.
我想在 class 中定义一个装饰器。我不想把它定义为一个分离的、独立的函数,因为这个装饰器是专门为这个 class 而我想把相关的方法放在一起的。
这个装饰器的目的是检查一些先决条件,尤其是成员变量持有的数据库连接、SSH连接等是否仍然可用。如果没有,装饰函数将不会被调用,并且会进行一些错误报告和清理工作。
我做了以下测试 class 来测试它是否有效,并且代码运行良好。但是我发现 PyCharm 显示了对这段代码的警告。所以我想知道,这是否意味着我的代码不是 Pythonic,或者 PyCharm 不够聪明,错误地给出了这个警告?
如果我的代码不是Pythonic,怎么改? 如果是 PyCharm 的错误,我和我的团队应该如何配置 PyCharm 让它专门忽略这种警告,同时保留大多数其他 lint 检查?
class TestClass:
def __init__(self):
self.flag = True
def dec(func):
def wrapper(self, *args, **kwargs):
if not self.flag:
print("Won't run!")
return empty_fun(self, *args, **kwargs)
return func(self, *args, **kwargs)
def empty_fun(*args, **kwargs):
return None
return wrapper
@dec
def foo(self):
print("foo")
@dec
def bar(self, msg, more, *args, **kwargs):
print("message: %s" % msg)
print("more %s:" % more)
for item in args:
print("other item: %s" % item)
name = kwargs.get('name')
age = kwargs.get('age')
print('name: %s' % name)
print('age: %s' % age)
def main():
t = TestClass()
t.foo()
print('-'*10)
t.bar("abc", 'def', 'hij', 'klm', name='Tom', age=20)
if __name__ == '__main__':
main()
这是 PyCharm 报告的 lint 警告:
您的代码在技术上是正确的(因为它将按预期工作),但需要注意的是 dec
将成为 TestClass
的方法并且如果这样调用将会中断。你至少应该把它设为 staticmethod
来避免这种情况。
wrt/ pythonicity,在不需要时使这个装饰器成为 class 的一部分确实是非 pythonic 的。它仅适用于此 class 的事实并不是使其成为 class 成员的理由,更不是使其成为 public API 成员的理由。
您可能可以在评论中添加 linter 提示以使其静音,但我个人只是从 class 中提取此装饰器,将其设为私有,并记录它只能与此 class.
作为旁注:我假设您的 empty_func
是 "error reporting and clean-up work" 的占位符 - 否则它根本没用 - 但它真的需要在装饰器中定义吗?
从 Python decorator as a staticmethod 开始,似乎不鼓励将装饰器放在 class 中。
想想看,Python 提供了这种很好的划分方式,称为 模块 。您是否考虑过将与此相关的所有代码 class 放在一个模块中,而将其他代码放在其他模块中?
I'd strongly recommend to move the decorator to the module scope -- it does not seem to belong inside the class. If you want to keep it inside the class, don't make it a
staticmethod
, but rather simplydel
it at the end of the class body -- it's not meant to be used from outside the class in this case.