2014-01-15 4 views
4

У меня есть объект класса, который создает некоторые поля данных:Как убедиться, что функция класса не будет вызвана до тех пор, пока не будет вызвана другая функция класса?

class DataFields(object): 

    _fields_ = ['field_1', 'field_2', 'data_length'] 

    def __init__(self, data=None): 
     if data != None: 
      self.create_fields(data) 

    def create_fields(self, data): 
     i = 0 
     for field in self._fields_: 
      setattr(self, field, data[i]) 
      i += 1 

    def get_datalength(self): 
     return self.data_length 

Что является лучшим способом, чтобы убедиться, что функция get_datalength() нельзя назвать, если data_length поле не было создано (то есть, если не функция create_fields() был вызван один раз).

Я думал об использовании либо переменную, которая инициализируется в create_fields и проверяется в get_datalength() или try-except внутри функции get_datalength(). Каков самый питонический (или лучший) способ?

+1

Лучший способ, вероятно, 'create_fields' возвращает новый объект с соответствующими методами, которые вы хотите. Не пытайтесь делать все в одном классе. – roippi

+0

Я думаю, что это именно то, что мне нужно сделать. Спасибо за совет! – plover

+0

В приведенном выше .... есть ли причина, по которой вам нужно разрешить запуск create_fields после инициализации? если вы удалите данные по умолчанию, тогда всегда гарантируется, что он всегда запускается во время init. –

ответ

4

Я думаю, что самый вещий способ будет сгенерировано исключение:

def get_datalength(self): 
    try: 
     return self.data_length 
    except AttributeError: 
     raise AttributeError("No length call create_fields first") 

Простая причина: Нельзя запретить пользователю вызывать эту функцию на объекте. Либо пользователь получит AttributeError и не поймет, что происходит, либо вы предоставили собственный класс ошибок или, по крайней мере, сообщение об ошибке.

КСТАТИ: Это не вещий создание методов получения (нет таких вещей, как «частных членов») Если вам нужно сделать меньше работы на стоимость возвращения его взглянуть на @property декоратора

@property 
def datalength(self): 
    return do_some_stuff(self.data_length) 
+0

Кстати, для метода исключения вам ничего не нужно ... если пользователь пытается получить доступ к 'myobject.field1', и он не был создан, который уже вернет значение, если оно существует, и 'AttributeError', если это не так. –

+2

Приятно дать лучшее объяснение того, что не так. Вы можете сделать это, не потеряв трассировку стека, например: 'кроме AttributeError, как e: e.args = (" no attribute 'length'; call create_fields first ",); raise' – kindall

+0

Спасибо, получил его прямо сейчас – ProfHase85

1

Используя getattr со значением по умолчанию, вы можете вернуть None или какое-либо значение, если нет data_length атрибут еще в случае:

def get_datalength(self): 
    return getattr(self, 'data_length', None) 
0

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

def fn2(self): 
    print("this is fn2") 

class test: 
    def fn1(self): 
     print("this is fn1") 
     self.fn2 = fn2 
    def fn2(self): # omit this if you want fn2 to only exist after fn1 is called 
     print("Please call fn1 first") 

Я бы не рекомендовал это для повседневного использования, но в некоторых случаях это может быть полезно. Если вы опускаете определение fn2 внутри класса, то метод fn2 будет присутствовать только после вызова fn1. Для облегчения технического обслуживания коды вы можете сделать то же самое, как это:

class test: 
    def fn1(self): 
     print("this is fn1") 
     self.fn2 = self._fn2 
    def _fn2(self): 
     print("this is fn2") 
    def fn2(self): # omit this if you want fn2 to only exist after fn1 is called 
     print("Please call fn1 first") 

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

0

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

called['method1'] 
called['method2'] 
called['method3'] 
... 

И установив ключ в этом вызове метода

class SomeClass(obj): 
    def method1(): 
     called['method1'] = 1 
    def method2(): 
     if method1 in called: 
      # continue 
Смежные вопросы