2015-08-11 4 views
1

Как сгенерировать свойства в python с помощью метакласса? У меня есть некоторые записи данных, поля которых имеют некоторые отношения между ними. , и я хотел бы иметь каждую запись как тип (класс) и автоматически генерировать эти свойства и отношения.Свойства автогенератора python

Я хочу указать это соотношение в виде структуры данных (скажут ДИКТ) и автоматическое создание классов со свойствами

Record 1 
     Field  description 
     ---------------------------- 
     numOfPin  no# of following pin array 
     pin_array  array with numOfpin elements 
     read_result if opt_flag bit 0 is set, invalid. ignore this value 
     opt_flag  ... 
Record 2 
    .... 

Изменить: разъяснение .. Логикой свойств недостающего/недопустимые поля и дополнительный флаг одинаково для всех записей. Поэтому я хотел бы абстрагировать это в метаклассе.

в псевдо например код питона

record1_spec = { 'numOfpin', ('pin_array','numOfPin'), 
      'opt_flag', ('read_result','opt_flag') } 
record2_spec = { 'numOfsite', ('site_array','numOfsite'), 
      'opt_flag', ('test_result','opt_flag') } 

class MetaClass: 

getter_generator(ele, opt): 
    if opt : return ele 
    else return None 

get class name (eg. record1) then fetch record_spec to create class 
for ele in record_spec: 
    if ele is tuple type: # relation between field 
    class.attribute[ele[0]] = getter_generator(ele[0], ele[1]) 

класс record1 (метаклассом = метаклассов): .....

затем record1 класс будет иметь все свойства, определенные в спецификации. Логика, если задано какое-либо поле параметра, некоторые свойства возвращают соответствующее значение.

+0

Это немного неясно, что вы пытаетесь сделать, и нужно ли metaclassing в все для ваших нужд. Как вы собираетесь назначать значения полей, например? Обратите внимание, что метакласс определяет, как создается сам класс, а не как определяются экземпляры класса. – skyking

+0

@skyking Я хочу метакласса для создания классов (для каждого типа записи, а не для записи объекта!), И каждый тип записи * должен иметь некоторые свойства, и эти свойства также могут быть сгенерированы метаклассом. У меня есть основная идея. но все онлайн-руководства по метаклассам python/tutorials не очень помогают. – Nyan

+0

Не могли бы вы привести пример того, как вы хотели бы использовать это? – skyking

ответ

3

Хорошо, давайте посмотрим, как глубока кроличья нора ...

Есть две вещи, которые, кажется, нужно сделать. Один из них заключается в создании свойств «на лету», а другой - их добавлении. Сначала давайте посмотрим на создание свойств, которые довольно прямолинейны - свойство создается путем помещения @property перед определением функции или, как должно быть, как должно быть, декорации, - для вызова property с функцией в качестве аргумента. Таким образом, мы создаем функцию на лету, и вызвать property на том, что легко:

def make_property(params): 
    def fn(self): 
     return use_self_and_params_to_calculate_result(self, params) 
    return property(fn) 

, например params может быть, например, имя поля, а затем вы можете вернуть его вобще return getattr(self, fieldname) во внутренней (т.е. fn) функция.

Теперь для следующей части, создавая класс. Параметр metaclass в создании класса используется непосредственно только для этого - он не должен быть фактическим метаклассом, он просто вызывается и должен возвращать то, что принято считать классом. Нормальный UseCase хотя должен иметь параметр metaclass быть типом класса, но мы на самом деле не нужно, что в этом случае:

def meta(name, bases, attrs): 
    attrs = dict(attrs) 

    attrs["x"] = make_property("_x") 

    return type(name, bases, attrs) 

class record1(metaclass=meta): 
    pass 

Теперь мы могли поиск record1_spec в meta через globals() (meta называется с "record1" в качестве первого аргумента), но какая забава в этом. Давайте копаем глубже в лучевую дыру, meta просто вызывается с тем, что вы ставите там, где находятся базовые очки - это просто так, что type ожидают, что они будут классами, но нам не нужно этого делать, нам нужно только убедиться, что это правда, когда мы называем type:

def meta(name, bases, attrs): 
    record_spec = bases[0] 
    bases = bases[1:] 

    attrs = dict(attrs) 

    examine_record_spec_and_populate_attrs(attrs, record_spec) 
    attrs["spec"] = record_spec 

    return type(name, bases, attrs) 

class record1(['numOfpin', ('pin_array','numOfPin'), 
       'opt_flag', ('read_result','opt_flag')], metaclass=meta): 
    pass 

Тогда вы можете найти спецификацию как record1.spec если вам понадобиться это.Если ваша запись спецификации в пар ключ-значение (т.е. как dict) можно даже использовать параметры ключевого слова в определении класса:

def meta(name, bases, attrs, **spec): 
    attrs = dict(attrs) 

    examine_record_spec_and_populate_attrs(attrs, spec) 
    attrs["spec"] = spec 

    return type(name, bases, attrs) 

class record1(numOfpin = ('pin_array','numOfPin'), 
       opt_flag = ('read_result','opt_flag'), metaclass=meta): 
    pass