Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
不带参数的setter方法名的Python命名约定_Python_Naming_Conventions - Fatal编程技术网

不带参数的setter方法名的Python命名约定

不带参数的setter方法名的Python命名约定,python,naming,conventions,Python,Naming,Conventions,我一直在用类编写python代码,这些类将有一个名为以下内容的方法: def set_log_paths(self): 问题是,这个方法不带参数,它决定了一些值应该基于自我的其他值。在这种情况下使用“set”一词是否不合适?我问这个问题是因为它不是一个直接的getter或setter,就像我们在与私有成员的语言中使用的那样 在我的方法名称中有一个常用的常规词吗?如果您不传递任何值,而是在调用方法时根据当前值计算值,那么描述操作的动词应该是“更新”——因此更新日志路径() 只需仔细检查一下您是否

我一直在用类编写python代码,这些类将有一个名为以下内容的方法:

def set_log_paths(self):
问题是,这个方法不带参数,它决定了一些值应该基于自我的其他值。在这种情况下使用“set”一词是否不合适?我问这个问题是因为它不是一个直接的getter或setter,就像我们在与私有成员的语言中使用的那样


在我的方法名称中有一个常用的常规词吗?

如果您不传递任何值,而是在调用方法时根据当前值计算值,那么描述操作的动词应该是“更新”——因此
更新日志路径()

只需仔细检查一下您是否真的需要这种设计,以及您/您的类的其他用户忘记调用这些“更新”方法的可能性有多大

Python的内省很容易允许采用“”中的某些元素,当它们所依赖的值发生更改时,可以使用这些元素来触发这些更新程序方法

这种体系结构的一个最佳选择是为属性设置一个描述符,在调用
\uuuuu set\uuuuu
时,该描述符将检查类级注册表以“查看”是否应触发事件,然后是一个装饰器,使您能够列出触发事件的属性。具有适当的
\uuuu init\u子类\uuuuu
方法的基类可以设置所有内容

假设类中的“基本属性”作为类主体中的带注释属性—用于此操作的描述符、装饰器和基类代码可能是:

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
让我们来看看这个:

In [2]: t = Test()                                                                                       

In [3]: t.path1 = "/tmp"                                                                                 

In [4]: t.path2 = "/inner"                                                                               

In [5]: t.log_paths                                                                                      
Out[5]: '/tmp/inner'
因此,这是一段复杂的代码,但通常位于框架内或基本实用程序库中的代码-有了这50行代码,您可以使用Python为您工作,并让它调用更新方法,因此它们的名称根本不重要!:-)
(好的,对于所问的问题来说,这段代码太过分了——但我今晚睡觉前想做一些类似的事情——免责声明:我没有测试这里涉及的与继承相关的角落案例)

元问题:有更好的地方问这些问题吗?我担心在意见问题上被否决。这个问题的答案可能是“没有约定”,但这不是一个真正的观点。对我来说,至少这样的案例表明了一种潜在的可能性。为什么在构造函数中不执行
set\u log\u路径
?如果这是因为后来设置了一些值,也许这应该是其他函数的一部分?作为您类的客户机,我可能无法猜测是否需要调用此方法。只是想弄清问题的真相。@Bradfolon,Meta-Meta问题你问过Meta这个问题吗?假设他在
\uuuu init\uuuuu
中做了几个步骤,然后在函数调用中对这些步骤进行分组,以提高可读性(当然要有好的可读函数名)。那我看没问题。至于
set
word,有类似
setup
configure
的选项。此外,如果它是该方法所做的……而且setter和getter在Python中由于属性而不是那么常见(用这个名称),因此即使是客户机代码用户也应该怀疑它不是传统的setter,而是更复杂的操作。复数形式也有助于这一暗示。这当然是有争议的。。。