2011-08-25 16 views
6

Jest to dość proste pytanie, mam nadzieję, że wszyscy mnie oświecić. W poniższym przykładzie w jaki sposób zdefiniować __repr__, aby dynamicznie ustawić self.name?Dynamicznie tworzenie klas w python i __repr__

Dzięki!

import re 

inputlist = 'Project="Sparcy" Desc=""\nProject="Libs" Desc=""\nProject="Darwin" Desc=""\nProject="Aaple" Desc="The big project"' 

regex = re.compile('([^ =]+) *= *("[^"]*"|[^ ]*)') 

results = [] 
for project in inputlist.split("\n"): 
    items = [ (k.strip(), v.strip()) for k, v in regex.findall(project)] 
    if len(items) < 2: 
     print("Houston we have a problem - Only %s k/v pair found for %s" % (len(items), project)) 
     continue 
    item_dict = dict(items[1:]) 
    item_dict['name'] = items[0][1] 
    klass = type(items[0][0], (object,), item_dict) 
    results.append(klass) 

print results 

Co szukam jest to

kod psuedo

for result in results 
type(result) → Project 
print result → Sparky 

Odpowiedz

3

Zgaduję, że chcesz

print results 

wrócić

["Sparcy", "Libs", "Darwin", "Aaple"] 
  1. Drukowanie listy pokazuje repr jej elementów.
  2. repr(elt) jest określana przez type(elt).__repr__.
  3. Ponieważ w tym przypadku elementy są klasami, musisz ustawić __repr__ dla typu klasy.

import re 

inputlist = '''\ 
Project="Sparcy" Desc="" 
Project="Libs" Desc="" 
Project="Darwin" Desc="" 
Project="Aaple" Desc="The big project" 
Site="Phoenix" Protocol="Cheese"''' 

regex = re.compile('([^ =]+) *= *("[^"]*"|[^ ]*)') 

results = [] 
for project in inputlist.split("\n"): 
    items = [ (k.strip(), v.strip()) for k, v in regex.findall(project)] 
    if len(items) < 2: 
     print("Houston we have a problem - Only %s k/v pair found for %s" % (len(items), project)) 
     continue 
    item_dict = dict(items[1:]) 
    item_dict['name'] = items[0][1] 
    projectname=items[0][0] 
    metametaklass=type('meta_'+projectname,(type,),{'__repr__':lambda cls: cls.__name__}) 
    metaklass=metametaklass(projectname,(type,),{'__repr__':lambda cls: cls.name}) 
    klass=metaklass(projectname+'_class', (object,), item_dict) 
    results.append(klass) 

print(results) 

daje

["Sparcy", "Libs", "Darwin", "Aaple", "Phoenix"] 

i

for result in results: 
    print(type(result)) 
    print(result)  
    print('-'*80) 

plony

Project 
"Sparcy" 
-------------------------------------------------------------------------------- 
Project 
"Libs" 
-------------------------------------------------------------------------------- 
Project 
"Darwin" 
-------------------------------------------------------------------------------- 
Project 
"Aaple" 
-------------------------------------------------------------------------------- 
Site 
"Phoenix" 
-------------------------------------------------------------------------------- 

PS. Zauważ, że jest to perwersja __repr__, ponieważ obiekt repr powinien być jednoznacznym ciągiem znaków reprezentującym obiekt. Oznacza to, że ma dostarczyć wystarczającej ilości informacji do odtworzenia obiektu. Prawdopodobnie powinieneś zdefiniować inną funkcję, zamiast zajmować się metaclasses.

+0

Czy wiesz, jak móc zdefiniować typ. Sposób, który rozumiem, że to działa, polega na zdefiniowaniu '__metaclass__', który go użyje. Korzystasz z tego dla '__repr__'. Jak nie propagować tego dla '__metaclass__'. Typ __goal → (Sparky) == Project__ – rh0dium

+0

@ rh0dium: Nie jestem pewien, czy rozumiem to pytanie. Edytowałem swój post, więc 'print (type (klass))' wypisze 'Project'. – unutbu

+0

Ale to już nie jest dynamiczne. Co się dzieje, gdy ty to zrobisz ... 'inputlist = 'Site =" Phoenix "Protocol =" Cheese "\ n' – rh0dium