2017-01-07 3 views
3

У меня есть класс, в котором метод сначала должен убедиться, что атрибут присутствует, и иначе вызвать функцию для его вычисления. Затем, гарантируя, что атрибут не None, он выполняет некоторые операции с ним. Я вижу два немного различных вариантов дизайна:Python design - инициализация, настройка и получение атрибутов класса

class myclass(): 
    def __init__(self): 
     self.attr = None 

    def compute_attribute(self): 
     self.attr = 1 

    def print_attribute(self): 
     if self.attr is None: 
      self.compute_attribute() 
     print self.attr 

И

class myclass2(): 
    def __init__(self): 
     pass 

    def compute_attribute(self): 
     self.attr = 1 
     return self.attr 

    def print_attribute(self): 
     try: 
      attr = self.attr 
     except AttributeError: 
      attr = self.compute_attribute() 
     if attr is not None: 
      print attr 

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

Второй выбор, по-видимому, является более широко используемым. Однако для моих целей (научных вычислений, связанных с теорией информации) с использованием блоков try except везде может быть немного избыточным, учитывая, что этот класс не взаимодействует с другими классами, он просто берет данные и вычисляет кучу вещей.

+1

Я думаю, что вы хотите что-то вроде этого: http://stackoverflow.com/questions/3012421/python-memoising- отложенный-поиск-свойство-декоратор.Получение класса для печати само по себе не очень pythonic; вместо этого реализуем '__repr__' и/или' __str__'. – jonrsharpe

+0

Поскольку каждый объект класса обязательно должен иметь атрибут 'attr', лучше использовать дизайн первого класса. Это разъясняет, каковы атрибуты этого класса. вы также можете установить атрибут attr как атрибут класса, каждый раз, когда вы будете получать доступ с помощью self.attr, он будет проглатывать копию attr, и вы можете установить/получить только для перкулярного объекта. – Roshan

ответ

-1

Основываясь на the answer jonrsharpe linked, я предлагаю третий вариант дизайна. Идея здесь заключается в том, что никакая специальная условная логика не требуется вообще ни клиентам MyClass, ни по коду в пределах MyClass. Вместо этого декоратор применяется к функции, которая выполняет (гипотетически дорогое) вычисление свойства, а затем этот результат сохраняется.

Это означает, что дорогостоящее вычисление выполняется лениво (только если клиент пытается получить доступ к свойству) и выполняется только один раз.

def lazyprop(fn): 
    attr_name = '_lazy_' + fn.__name__ 

    @property 
    def _lazyprop(self): 
     if not hasattr(self, attr_name): 
      setattr(self, attr_name, fn(self)) 
     return getattr(self, attr_name) 

    return _lazyprop 


class MyClass(object): 
    @lazyprop 
    def attr(self): 
     print('Generating attr') 
     return 1 

    def __repr__(self): 
     return str(self.attr) 


if __name__ == '__main__': 
    o = MyClass() 
    print(o.__dict__, end='\n\n') 
    print(o, end='\n\n') 
    print(o.__dict__, end='\n\n') 
    print(o) 

Выход

{} 

Generating attr 
1 

{'_lazy_attr': 1} 

1 

Редактировать

Применение Cyclone's answer в контексте OP в:

class lazy_property(object): 
    ''' 
    meant to be used for lazy evaluation of an object attribute. 
    property should represent non-mutable data, as it replaces itself. 
    ''' 

    def __init__(self, fget): 
     self.fget = fget 
     self.func_name = fget.__name__ 

    def __get__(self, obj, cls): 
     if obj is None: 
      return None 
     value = self.fget(obj) 
     setattr(obj, self.func_name, value) 
     return value 


class MyClass(object): 
    @lazy_property 
    def attr(self): 
     print('Generating attr') 
     return 1 

    def __repr__(self): 
     return str(self.attr) 


if __name__ == '__main__': 
    o = MyClass() 
    print(o.__dict__, end='\n\n') 
    print(o, end='\n\n') 
    print(o.__dict__, end='\n\n') 
    print(o) 

Выход идентичен выше.

+1

Это не * на основе * столько * точно так же, как *. Если вы считаете, что этот вопрос является дубликатом, отметьте его как таковой, а не скопируйте ответ. – jonrsharpe

+0

@jonrsharpe Я недостаточно уверен, чтобы классифицировать его как дубликат (если это так, почему вы ссылались на другой ответ, вместо того, чтобы помечать его сами?), Но я оставлю этот ответ на некоторое время, поскольку я подумайте, что это может помочь OP (я специально подгонял его по своим требованиям). Я удалю его, если он примет другой ответ или если мой ответ ударит -3. – Tagc

+1

В связанном вопросе также кажется, что более поздний - но для меня более таинственный - [ответ] (http://stackoverflow.com/a/6849299/5429658). –

0

Во-первых, вы можете использовать hasattr, чтобы проверить, имеет ли объект атрибут, он возвращает True, если атрибут существует.

hasattr(object, attribute) # will return True if the object has the attribute 

Во-вторых, Вы можете настроить доступ атрибутов в Python, вы можете прочитать об этом здесь: https://docs.python.org/2/reference/datamodel.html#customizing-attribute-access

В принципе, вы переопределить метод __getattr__ для достижения этой цели, так что-то вроде:

класса myclass2(): защиту INIT (Я): проход

def compute_attr(self): 
    self.attr = 1 
    return self.attr 

def print_attribute(self): 
    print self.attr 

def __getattr__(self, name): 
    if hasattr(self, name) and getattr(self, name)!=None: 
     return getattr(self, name): 
    else: 
     compute_method="compute_"+name; 
     if hasattr(self, compute_method): 
      return getattr(self, compute_method)() 

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

+0

Выполнение 'if hasattr (self, name) и getattr (self, name)! = None:' была моей первоначальной идеей - она ​​проверяет все, что мне нужно, в одной строке, и это не зависит от того, помню ли я, чтобы установить атрибут или нет, но после чтения сообщений, таких как [this] (https://hynek.me/articles/hasattr/), создается впечатление, что 'hasattr' не является в целом безопасным выбором. –

+0

ИМХО, это действительно зависит от вашей системы, если вы зависите от многих сторонних классов, то, вероятно, это не очень хорошая идея, но если нет, то я не понимаю, почему вы не можете ее рассмотреть. – Bitonator

+0

@PietroMarchesi FYI вам понадобится 'getattr (self, name, None) не None:'; по умолчанию 'getattr' выдает' AttributeError' за отсутствующие атрибуты, и вы должны проверить 'None' на личность. – jonrsharpe

Смежные вопросы