Передача свойств в качестве параметра по умолчанию - PullRequest
1 голос
/ 21 апреля 2020

Я пытаюсь найти элегантное решение Pythoni c для следующей проблемы проектирования: Внутри класса я хочу использовать свойства в качестве параметра по умолчанию. Итак, можно сделать что-то вроде:

Class A:

  def __init__(self, a=0, b=1):
    self.a = a
    self.b = b

  def func(self, a=None, b=None):
    a = a or self.a
    b = b or self.b
    # do something with a and b

Но так как это выглядит как потенциальный шаблонный код, я пошел дальше и написал обобщенную c функцию вне моего класса.

def fallback_parameters(obj, **args):
    return [args[arg] or getattr(obj, arg) for arg in args] 

и используйте

def func(self, a=None, b=None):
    a, b = fallback_parameters(self, a=a, b=b)
    # do something with a and b

Есть ли лучший / более чистый способ добиться этого? Существующее решение? Я испытываю желание создать декоратор, поэтому мне не нужно вводить что-то вроде:

a, b, c, d, e = fallback_parameters(self, a=a, b=b, c=c, d=d, e=e)

1 Ответ

0 голосов
/ 04 мая 2020

Просто для иллюстрации, если вы хотите изменить объект attibute (вы говорите, что нет), декоратор будет выглядеть так:

def fallback_args(func):

    def inner(obj, **kwargs):
        if kwargs:
            for key in kwargs:
                setattr(obj, key, kwargs[key])
        return func(obj, **kwargs)
    return inner

class B:
    def __init__(self, a=0, b=1):
        self.a = a
        self.b = b

    @fallback_args
    def func(self, a=None, b=None):
        print("Do something with {} and {}".format(self.a, self.b))
        #or
        #a = self.a
        #b = self.b
        #print("Do something with {} and {}".format(a, b))

obj2 = B()
print(obj2.a)
print(obj2.b)
obj2.func()

print()

obj2 = B()
print(obj2.a)
print(obj2.b)
obj2.func(a=300)

print()

print(obj2.a)
print(obj2.b)

Выходы:

0
1
Do something with 0 and 1

0
1
Do something with 300 and 1

300
1

Но не желая менять объект, я не думаю, что имеет смысл просто избегать явных a = self.a or a подобных линий. Потому что, если вы не перечислите параметры в вызове, как декоратор узнает, какие имена вы упоминаете в теле методов, чтобы использовать их как резервный / загруженный? Можно сказать, что имена являются только теми, которые перечислены в сигнатуре метода. Теперь, это может быть самоанализ, но я думаю, что вижу здесь более запутанную работу, чем это заслуживает. a = self.a or a выглядит просто и явно. Так что это тоже Pythoni c, хотя вы, вероятно, могли бы написать неявное присваивание, которое вам нужно, с некоторой дополнительной работой.

Для идеи о том, как анализировать аргументы метода, см. Несколько связанный декоратор, который я написал здесь , чтобы заморозить аргументы метода.

...