2010-02-17 16 views
9

Python jest dostarczany z przydatną funkcją dir(), która zawiera listę treści klasy dla ciebie. Na przykład, dla tej klasy:Jak powtórzyć atrybuty klasy, w kolejności, w jakiej zostały zdefiniowane?

class C: 
    i = 1 
    a = 'b' 

dir(C) wróci

['__doc__', '__module__', 'a', 'i'] 

To jest wielki, ale zauważ, jak kolejność 'a' i 'i' jest teraz inna niż kolejność zostały one zdefiniowane w

.

Jak mogę powtórzyć atrybuty C (potencjalnie ignorując wbudowane atrybuty modułu &) w kolejności, w jakiej zostały zdefiniowane? Dla powyższej klasy C będzie to 'i', a następnie 'a'.

Dodatek: - Pracuję nad kodem do serializacji/rejestrowania, w którym chcę serializować atrybuty w kolejności, w jakiej zostały zdefiniowane, tak aby dane wyjściowe były podobne do kodu, który utworzył klasę.

+0

Dlaczego zamówienie w ogóle zostało zdefiniowane? Zamówienie nie ma znaczenia w tym przypadku. Jak wykorzystasz te informacje, jeśli możesz je zdobyć? –

+0

Czy serializujesz klasę lub wystąpienia klasy? W twoim przykładzie "a" i "i" są atrybutami klas. Jeśli masz na myśli atrybuty instancji, powinieneś zdefiniować je w '__init__' używając' self.a = 'b'' i 'self.i = 1'. – PaulMcG

+0

Są to atrybuty na poziomie klasy, które nie są tak użyteczne, jak zmienne instancji. Dlaczego starasz się zachować kolejność atrybutów klasowych? Czy nie byłoby lepiej zachować kolejność zmiennych instancji?Dlaczego próbujesz robić sztuczki ze zmiennymi na poziomie klasy? –

Odpowiedz

7

Nie sądzę, że jest to możliwe w Pythonie 2.x. Kiedy członkowie klasy otrzymują metodę __new__, są oni przedstawiani jako słownik, więc kolejność została już utracona w tym momencie. Dlatego nawet metaclasy nie mogą ci w tym pomóc (chyba że są dodatkowe funkcje, które przeoczyłem).

W Pythonie 3 możesz użyć nowej specjalnej metody __prepare__, aby utworzyć uporządkowany dict (jest to nawet podane jako przykład w PEP 3115).

+0

Oto jak Django to robi (Python 2.x i nowsze): https://github.com/django/django/blob/stable/1.3.x/django/db/models/fields/__init__.py#L56 – tobych

+0

Nie używałem jeszcze Django, ale wydaje mi się, że wymaga to, aby w każdym zadaniu utworzyć nową instancję 'Field'? Brzmi jak dobre rozwiązanie. – nikow

+0

Tak, właśnie to robi Django. – tobych

1

Ta informacja nie jest dostępna, ponieważ atrybuty są przechowywane w dykcie, która jest z natury nieuporządkowana. Python nie przechowuje tej informacji o zamówieniu w dowolnym miejscu.

Jeśli chcesz, aby Twoje formatu serializacji do przechowywania rzeczy w określonej kolejności byś określić że kolejność wyraźnie. Nie używałbyś dir, która zawiera rzeczy, których nie znasz lub których nie obchodzi, jawnie dostarczysz listę (lub cokolwiek) opisującą serializację.

2

Jestem nowy w Pythonie, więc moje rozwiązanie może nie być skuteczna

class Q: 
def __init__(self): 
    self.a = 5 
    self.b = 10 

if __name__ == "__main__": 
    w = Q() 
    keys = w.__dict__.keys() 
    for k in keys: 
     print "Q.%s = %d"%(k,w.__dict__[k]) 

wyjściowa wynosi:

Q.a = 5 
Q.b = 10 
+0

To nie zachowuje zamówienia. –

2

umieścić tę metodę w swojej klasie

def __setattr__(self, attr, value): 
    if attr not in dir(self): 
     if attr == "__ordered_fields__": 
      super.__setattr__(self, attr, value) 
     else: 
      if not hasattr(self, "__ordered_fields__"): 
       setattr(self, "__ordered_fields__", []) 
      self.__ordered_fields__.append(attr) 
      super.__setattr__(self, attr, value) 

oraz pobierz pola w kolejności, po prostu zrób coś takiego:

print(self.__ordered_fields__) 
Powiązane problemy