Инициализировать несколько атрибутов при инициализации из одного атрибута

#python-3.x

#python-3.x

Вопрос:

У меня есть класс как таковой:

 class Line:
    def __init__(self, text: str):
        self.text = text

  

Строка в моем случае может иметь много features . Например,

  1. Строка считается длинной, если в ней более 50 символов.
  2. Если строка содержит символы, отличные от ascii, то флаг устанавливается как non_ascii = True и так далее
  3. Найдите все URL-адреса в строке

Я могу реализовать их в терминах методов класса:

 class Line:
    def __init__(self, text: str):
        self.text = text

    def is_ascii(self):
        # check and return
    
    def is_long(self):
        # check and return

    def urls(self):
        # find and return urls
  

Проблема, с которой я сталкиваюсь, заключается в том, что мне нужно выполнять вызовы метода для объекта Line несколько раз на разных этапах процесса (некоторые вызовы методов довольно сложны с точки зрения вычислений).

Что я хотел бы иметь, так это то, что при инициализации я хотел бы, чтобы объект Line имел предварительно заполненные атрибуты, такие как is_ascii, is_long, urls, чтобы к ним можно было обращаться несколько раз без необходимости вычислять их каждый раз при обращении к ним.

 class Line:
    def __init__(self, text: str):
        self.text = text
        self.is_ascii = do some processing on self.text, and assign value
        self.is_long = do some processing on self.text, and assign value
        self.urls = do some processing on self.text, and assign value
  

Я не уверен, имеет ли смысл иметь всю эту логику внутри блока инициализации. Как бы мне добиться этого «питоническим» способом?

Комментарии:

1. @Carcigenicate: спасибо за ответ. Если это возможно, не могли бы вы показать, как будет работать кэширование? Я не очень хорошо разбираюсь в Python.

Ответ №1:

Вы могли бы просто использовать методы, которые вы выполняете, и вызывать их изнутри __init__ :

 class Line:
    def __init__(self, text: str):
        self.text = text
        self.is_ascii = self.calc_is_ascii(self.text)
        self.is_long = self.calc_is_long(self.text)
        self.urls = self.calc_urls(self.text)

    def calc_is_ascii(self):
        # check and return

    def calc_is_long(self):
        # check and return

    def calc_urls(self):
        # find and return urls
  

Вы также могли бы сделать так, чтобы при вызове метода он проверял, было ли значение уже вычислено, и использовал кэшированное значение, в противном случае он вычисляет и кэширует его:

 class Line:
    def __init__(self, text: str):
        self.text = text
        self.is_ascii = None
        self.is_long = None
        self.urls = None

    def calc_is_ascii(self):
        if self.is_ascii is None:
            # Do expensive calculation of self.is_ascii
            self.is_ascii = expensive_result
        
        # Use the cached, previously calculated value
        return self.is_ascii

    # Then the same pattern for other methods
  

Это имеет то преимущество, что если один из атрибутов никогда не нужен, работа по его вычислению не выполняется.

Я инициализирую атрибуты None . Если они None позже, я знаю, что они еще не были вычислены. Если это не так None , я знаю, что они уже были вычислены, поэтому я могу просто вернуть вычисленный результат. Это, конечно, предполагает, что None это недопустимое значение.