我一直在用类编写python代码,这些类具有一种称为:
def set_log_paths(self):
问题是,此方法不带参数,而是根据self的其他值确定应该使用哪些值。在这种情况下使用“ set”一词不合适吗?我问是因为它不是直接的获取器或设置器,就像在带有私人成员的语言中使用的那样。
方法名称中是否有一个常用的常规单词?
答案 0 :(得分:1)
如果您没有传递任何值,而是在调用方法的时刻根据当前值计算值,则描述该动作的动词是“更新”是合理的,因此{{1} }。
只需仔细检查一下您是否真的需要这种设计,以及您/您的班级其他用户有什么机会忘记调用这些“更新”方法?
Python的自省很容易允许采用“ reactive programing”中的某些元素,当它们依赖的值更改时,这些元素可用于触发这些更新程序方法。
这种体系结构的最佳选择是为属性设置一个描述符,该属性在调用update_log_paths()
时将检查一个类级注册表以“查看”是否应触发事件,然后一个装饰器启用您列出将触发它的属性。具有正确的__set__
方法的基类可以设置所有内容。
让我们假设您将类的“基础属性”作为类主体中的带注释的属性-可以使用的描述符,装饰器和基类代码可能与以下内容类似:
__init_subclass__
让我们开始工作吧
from functools import wraps
from collections import ChainMap
class EventDescriptor:
def __init__(self, name, default):
self.name = name
self.default = default
def __get__(self, instance, owner):
if not instance:
return self
return instance.__dict__[self.name] if self.name in instance.__dict__ else self.default
def __set__(self, instance, value):
instance.__dict__[self.name] = value
triggers = instance._post_change_registry.get(self.name, [])
for trigger in triggers:
getattr(instance, trigger)()
def triggered_by(*args):
def decorator(func):
func._triggered_by = args
return func
return decorator
class EventPropertyMixin:
def __init_subclass__(cls, **kw):
super.__init_subclass__(**kw)
for property_name, type_ in cls.__annotations__.items():
if not hasattr(cls, property_name):
raise TypeError("Properties without default values not supported in this example code")
# It would also be trivial to implement runtime type-checking in this point (and on the descriptor code)
setattr(cls, property_name, EventDescriptor(property_name, getattr(cls, property_name)))
# collects all registries in ancestor-classes, preserving order:
post_change_registry = ChainMap()
for ancestor in cls.__mro__[:0:-1]:
if hasattr(ancestor, "_post_change_registry"):
post_change_registry = post_change_registy.new_child(ancestor._post_change_registry)
post_change_registry = post_change_registry.new_child({})
for method_name, method in cls.__dict__.items():
if callable(method) and hasattr(method, "_triggered_by"):
for property_name in method._triggered_by:
triggers = post_change_registry.setdefault(property_name, [])
if method_name not in triggers:
triggers.append(method_name)
cls._post_change_registry = post_change_registry
class Test(EventPropertyMixin):
path1: str = ""
path2: str = ""
@triggered_by("path1", "path2")
def update_log_paths(self):
self.log_paths = self.path1 + self.path2
所以,这是复杂的代码,但是通常位于框架或基本实用程序库中的代码-拥有这50行代码,您可能会使用Python为您工作, 并使用它来调用更新方法,因此它们的名称完全无关紧要! :-) (好吧,这段代码对于所问的问题来说是过大了-但是我今晚想睡觉之前会产生这样的东西-免责声明:我没有测试这里涉及的与继承相关的极端情况)