Рекурсивная замена {шаблон} в / с использованием свойств объекта - PullRequest
2 голосов
/ 17 июня 2020

Я хочу использовать свойства объекта для рекурсивной замены шаблона. Поскольку свойства объекта неизвестны во время определения класса, я не могу использовать @ декораторы свойств

Пример

class Test():
    def __init__(self):
        self.date = '{year}-{month}'
        self.year = '2020'
        self.month = '06'

        self.path = '/dev/null'
        self.file_name = 'ABC-{date}.mp4'
        self.file = '{path}/{file_name}'

    def print(self):
        print(__class__)
        print ("Filename is {file_name}".format(**vars(self)))
        print ("File {file} will be written to {path}".format(**vars(self)))

t = Test()
t.print()

Фактически выход

<class '__main__.Test'>
Filename is ABC-{date}.mp4
File {path}/{file_name} will be written to /dev/null

Желаемый выход

<class '__main__.Test'>
Filename is ABC-2020-06.mp4
File /dev/null/ABC-2020-06.mp4 will be written to /dev/null

Ответы [ 4 ]

1 голос
/ 17 июня 2020

Вы можете использовать свойства. Вам просто нужно использовать их больше, чем вы ожидали.

class Test:
    def __init__(self):
        self.year = '2020'
        self.month = '06'

        self.path = '/dev/null'

    @property
    def file(self):
        return '{0.path}/{0.file_name}'.format(self)

    @property
    def file_name(self):
        return 'ABC-{0.date}.mp4'.format(self)

    @property
    def date(self):
        return '{0.year}-{0.month}'.format(self)

    def print(self):
        print(__class__)
        print ("Filename is {0.file_name}".format(self))
        print ("File {0.file} will be written to {0.path}".format(self))

t = Test()
t.print()

path, year и month - единственные «жестко заданные» атрибуты; остальное можно вывести. Рекурсия (такая, какая она есть) подразумевается в том смысле, что каждый доступ к атрибуту может быть свойством, которое само вызывает другое свойство. Это ключевое преимущество свойств: их интерфейс неотличим от атрибута экземпляра.

1 голос
/ 17 июня 2020

Вы упомянули рекурсию, но на самом деле не использовали рекурсию в своем коде.

Вы можете добиться желаемого поведения, реализуя рекурсивный метод, который форматирует заданную строку шаблона до тех пор, пока результат визуализации не будет таким же, как ввод :

def render(self, template):
    rendered = template.format(**vars(self))
    return rendered if rendered == template else self.render(rendered)

def print(self):
    print(self.render("Filename is {file_name}"))
    print(self.render("File {file} will be written to {path}"))

С указанными выше изменениями ваш код выведет:

Filename is ABC-2020-06.mp4
File /dev/null/ABC-2020-06.mp4 will be written to /dev/null
0 голосов
/ 17 июня 2020

Вы можете сделать это, используя небольшой вспомогательный класс (названный FL ниже) вместе с литералами f-strings вместо метода str.format(). Вот что я имею в виду:

class FL:
    """ Lazy literal f-string interpolation: Postpones evaluation of string
        until instance is converted to a string.
    """
    def __init__(self, func):
        self.func = func
    def __str__(self):
        return self.func()


class Test():
    def __init__(self):
        self.date = FL(lambda: f'{self.year}-{self.month}')
        self.year = '2020'
        self.month = '06'

        self.path = '/dev/null'
        self.file_name = FL(lambda: f'ABC-{self.date}.mp4')
        self.file = FL(lambda: f'{self.path}/{self.file_name}')

    def print(self):
        print(__class__)
        print(FL(lambda: f"Filename is {self.file_name}"))
        print(FL(lambda: f"File {self.file} will be written to {self.path}"))

t = Test()
t.print()
0 голосов
/ 17 июня 2020

Это возможно, переопределив __dict__ и __getattribute__:

class Test:
    def __init__(self):
        self.date = '{year}-{month}'
        self.year = '2020'
        self.month = '06'

        self.path = '/dev/null'
        self.file_name = 'ABC-{date}.mp4'
        self.file = '{path}/{file_name}'
        self.__dict__ = {x: getattr(self, x) for x in vars(self)}

    def __getattribute__(self, a):
        real_attribute = super().__getattribute__(a)
        if isinstance(real_attribute, str) and "{" in real_attribute:
            return real_attribute.format(
                **{
                    x: getattr(self, x)
                    for x in vars(self)
                    if "{" + x + "}" in real_attribute
                }
            )
        return real_attribute
    def print(self):
        print(__class__)
        print ("Filename is {file_name}".format(**vars(self)))
        print ("File {file} will be written to {path}".format(**vars(self)))

t = Test()
t.print()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...