Соглашение об именах Python для имени метода установки без аргументов
Я писал код Python с классами, у которых будет метод, называемый что-то вроде:
def set_log_paths(self):
Дело в том, что этот метод не принимает аргумента, он определяет, какие значения должны быть основаны на других значениях себя. Неуместно ли в этом случае использовать слово "набор"? Я спрашиваю, потому что это не прямой получатель или установщик, как можно было бы использовать на языке с частными членами.
Есть ли в моем названии метода обычное слово?
1 ответ
Если вы не передаете никаких значений, а вместо этого вычисляете значение в момент вызова метода, основываясь на текущих значениях, разумно, чтобы глагол, описывающий действие, был "обновлен" - поэтому update_log_paths()
,
Просто дважды проверьте, действительно ли вам нужен этот дизайн, и каковы шансы того, что вы / другие пользователи вашего класса забудут вызвать эти методы "обновления".
Самоанализ Python позволяет легко перенять некоторые элементы из " реактивного программирования", которые можно использовать для запуска этих методов обновления при изменении значений, от которых они зависят.
Одним из оптимальных вариантов такой архитектуры будет дескриптор ваших свойств, который после __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
И давайте это сработает:
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, чтобы он работал для вас, и заставить его вызывать методы обновления, чтобы их имя не имеет значения вообще!:-) (хорошо, этот код является излишним для заданного вопроса - но я был готов сделать что-то подобное перед сном сегодня вечером - отказ от ответственности: я не проверял связанные с наследованием угловые случаи, описанные здесь)