2017-01-12 8 views
0

Я работаю с данными, которые используются как переменные после их импорта. Я хотел бы использовать переменные в объекте как атрибуты.Pythonic способ импорта и использования данных в качестве атрибутов объекта

До сих пор я достиг этого, написав класс ImportData, а затем он состоит из другого класса Obj, который использует его для других вычислений. Другое решение, которое я использовал, - наследовать от класса ImportData. У меня есть пример ниже:

, определяющий класс данных

class ImportData: 
    def __init__(self, path): 
     # open file and assign to some variables 
     # such as: 
     self.slope = 1 
     self.intercept = -1 

раствор 1: использование композиции

class Obj: 
    def __init__(self, data_object): 
     self.data = data_object 

    def func(self, x): 
     return self.data.slope*x + self.data.intercept 


data_object = ImportData('<path>') 
obj = Obj(data_object) 

# get the slope and intercept 
print('slope =', obj.data.slope, ' intercept =', obj.data.intercept) 

# use the function 
print('f(2) =', obj.func(2)) 

Раствор 2: Использование наследования

class Obj(ImportData): 
    def __init__(self,path): 
     super().__init__(path) 

    def func(self, x): 
     return self.slope*x + self.intercept 

obj = Object('<path>') 
# get the slope and intercept 
print('slope =', obj.slope, ' intercept =', obj.intercept) 

# use the function 
print('f(2) =', obj.func(2)) 

Я не нравится составное решение, потому что я должен вводить дополнительные «данные» каждый раз, когда мне нужно получить доступ к атрибуту, но я не уверен, что унаследовал tance - это правильный путь.

Я в левом поле и есть лучшее решение?

ответ

0

Вашего чувство, что прикован доступ атрибута в составленном растворе код запах является правильным: data является деталью реализации Obj и должны быть скрыт от клиентов Obj «s, так что если реализация изменения ImportData класса, вы только нужно изменить Obj, и не каждый класс, который вызывает obj.data.

Мы можем скрыть Obj.data, указав Obj a __getattr__ метод контроля доступа к его атрибутам.

>>> class ImportData: 
...  def __init__(self, path): 
...   self.slope = 1 
...   self.intercept = -1 
... 
>>> data = ImportData() 


>>> class Obj: 
...  def __init__(self, data_object): 
...   self.data = data_object 

...  def func(self, x): 
...   return self.slope*x + self.intercept 

...  def __getattr__(self, name): 
...   try: 
...    return getattr(self.data, name) 
...   except AttributeError: 
...    raise AttributeError('{} object has no attribute {}.'.format(self.__class__.__name__, name)) 

>>> o = Obj(data) 
>>> o.func(2) 
1 
>>> o.slope 
1 
>>> o.intercept 
-1 
>>> 

Обычно, если питон не удается найти атрибут объекта - например obj.slope - это возбудит AttributeError. Однако, если объект имеет метод __getattr__, python будет вызывать __getattr__ вместо того, чтобы создавать исключение.

В приведенной выше коде, Obj.__getattr__ ищет атрибут data, если он не существует на Obj, поэтому клиент Obj «s можно назвать obj.slope вместо obj.data.slope. Повторное поднятие AttributeError выполняется так, что сообщение об ошибке относится к Obj, а не к ImportData

+0

Это классно, если только кто-то не набирает «o». в IDE будут перечислены данные как опция. Другая интересная вещь заключается в том, что назначение o.slope переходит в o и не нарушает метод. Является ли композиция еще лучше, чем наследование в этом случае? – StevenD

+0

В этом конкретном случае завершения кода в IDE, возможно, нет. Если это проблема, вы можете префикс 'data' с символом подчеркивания (так что' _data'), чтобы обозначить читателям кода, который вы считаете деталью реализации Obj, к которому не следует напрямую обращаться. Но это не означает, что наследование - это нечто большее, чем состав, или наоборот; оба имеют свои плюсы и минусы, в зависимости от проблем, которые вы пытаетесь решить. – snakecharmerb