2011-02-01 19 views
8

Possible Duplicate:
How to programmatically set a global (module) variable?Programowe tworzenie zmiennych w Pythonie

Mam klasy o nazwie zmienna zdefiniowana jako tak:

class Variable(): 
    def __init__(self, name): 
     self.name = name 
     self._value = None 
    def value(self): 
     return self._value 
    def __repr__(self): 
     return self.name 

Chcę utworzyć instancje 26 kapitał jednoliterowe zmiennej tak:

A = Variable('A') 
B = Variable('B') 
... 
Z = Variable('Z') 

Do tej pory próbowałem różnych rozwiązań, a najlepsze, co wymyśliłem, to:

from string import uppercase 
for char in uppercase: 
    exec "%s = %s" % (char, Variable(str(char))) in None 

Jednak to nie działa i daje mi ten błąd:

Traceback (most recent call last): 
    File "C:\Users\Administrator\Dev\python\truthtable\truthtable.py", line 7, in <module> 
    exec "%s = %s" % (char, Variable(str(char))) in None 
    File "<string>", line 1, in <module> 
NameError: name 'A' is not defined 

Co robię źle?

+8

Nie próbujesz tworzyć zmiennych dynamicznie? –

+0

Er, nazwa pytania jest trochę nieukrywana, nie jestem zbyt wpojonym w tego rodzaju semantykę. – deeb

+1

@deeb - Nie sądzę, aby Ignacio odnosił się do twojego tytułu. – senderle

Odpowiedz

15
from string import uppercase 
_g = globals() 
for char in uppercase: 
    _g[char] = Variable(char) 

Czy jest to dobry idea pozostaje wątpliwa :)

Zadziała tylko dla globals() (tj moduł przypisania stopnia), jak definicja język wyraźnie stwierdza, że ​​modyfikowanie słownika zwrócony przez locals() nie może właściwie zmieniają wartość dowolnych zmiennych lokalnych.

Możesz także zrobić coś podobnego z klasą lub instancją klasy __dict__.

+0

Modyfikowanie globals() nie jest dobrym pomysłem: nie ma oficjalnej gwarancji, że to działa: "To może się nie udać:" nie ma udokumentowanej gwarancji, że zmiany w globals() faktycznie utrzymają zmiany w module bazowym. Działa dzisiaj, może pęknąć jutro. "(Alex Martelli) – EOL

+1

To nie jest poprawne - to zastrzeżenie dotyczy * tylko * dla locals(), ponieważ gwarantowane jest poprawne działanie globals() przez specyfikację językową – ncoghlan

+0

@ncoghian: Tutaj jest oryginał komentarz Alexa, który jest prawdopodobnie bardzo doświadczonym programistą Pythona: http://stackoverflow.com/questions/1429814/how-to-programmatically-set-a-global-module-variable :) – EOL

0
from string import uppercase 
for c in uppercase: 
    locals()[c] = Variable(c) 
print A 

Nie jestem pewien, dlaczego chcesz to zrobić.

+2

Może to oficjalnie nie udać się: "Zawartość tego słownika nie powinna być modyfikowana, zmiany nie mogą wpływać na wartości lokalnych i wolnych zmiennych używanych przez tłumacza." (z dokumentacji). – EOL

4

Cóż, to nie jest ładne, ale można uzyskać dostęp do słownika globals() bezpośrednio:

for c in 'ABC': 
    globals()[c] = Variable(c) 
+1

"Przypisanie atrybutu aktualizuje słownik przestrzeni nazw modułu, np. M.x = 1 jest równoważne m .__ dict __ [" x "] = 1." (z http://docs.python.org/reference/datamodel.html) – ncoghlan

3

Nie trzeba używać exec na to, jak inni odpowiedzi pokazują, ale tutaj jest problem z oryginałem Kod:

for char in uppercase: 
    exec "%s = %s" % (char, Variable(str(char))) in None 

będzie exec A = A, B = B itd Choć może to być interesujące, jeśli jesteś gorącym zwolennikiem obiektywizmu, pyton nie obchodzi zbyt wiele dla niego.

Chcesz mieć Variable() rzeczy wewnątrz Exec dla jej znaczenia:

for char in uppercase: 
    exec "%s = Variable('%s')" % (char, char) 

W przyszłości, jeśli starasz się używać exec, najpierw spróbuj nie. Po drugie, wydrukuj to, co robisz - to pomoże w debugowaniu.

+0

Bez oceny, ale istnieje czystszy sposób (i prawdopodobnie szybszy sposób, jeśli to ma znaczenie), jak wyraźnie podano w mojej odpowiedzi. – EOL

+0

Oczywiście nie ma, mówię, aby nie robić tego w ten sposób w mojej odpowiedzi. Jest to poprawiona wersja oryginalnego kodu, który faktycznie używa 'exec'. – tkerwin

7

Najczystsze podejście zdecydowanie, jaki kiedykolwiek widziałem jest bezpośrednio dodać zmienne (tj atrybuty) do programu (czyli główny moduł), jako odpowiedzi another question on StackOverflow:

import sys 
from string import ascii_uppercase 

this_module = sys.modules[__name__] 
for char in ascii_uppercase: 
    setattr(this_module, char, Variable(char)) 

print A # Works! 

PS: Python rdzeń programiści ciężko pracowali, aby umożliwić modyfikację globals() (patrz komentarze do odpowiedzi ncoghlan). Zatem modyfikowanie globals() jest alternatywą.Nie jestem pewien, dlaczego wielu ludzi uważa, że ​​nie jest to tak czyste, chociaż (być może dlatego, że modyfikacja globals() może być modyfikowana, to nie jest to udokumentowane w postaci ?).

2

Nie próbuj umieszczać tego w globalnej zmiennej. To jest okropne. Zrób to zamiast tego.

import string 

variables = {} 
for x in string.ascii_uppercase: 
    variables[x] = Variable(x) 

Dostęp do niego można uzyskać na przykład z variables['Q'].

Jeśli chcesz otrzymać dostęp przypisać można zrobić:

class Variables(object): pass 

i

variables = Variables() 
for x in string.ascii_uppercase: 
    setattr(variables, x) = Variable(x) 

Ale w takim razie wolałbym utworzyć je dynamicznie w klasie Zmienne pojemnika.

import string 

class Variable(object): 
    def __init__(self, value): 
     self.value = value 
    def __repr__(self): 
     return "<Variable %s>" % self.value 

class Variables(object): 
    def __getattr__(self, n): 
     if n in string.ascii_uppercase: 
      v = Variable(n) 
      setattr(self, n, v) 
      return v 
     raise AttributeError("Variables instance has no attribute %s" % n) 

Zastosowanie:

>>> v = Variables() 
>>> v.G 
<Variable G> 
>>> v.Y 
<Variable Y> 
>>> v.G is v.G 
True 

Prosty i czysty, bez brzydkich hacki (dobrze, z wyjątkiem getattr, a to nie jest tak brzydki), a ty nawet nie trzeba wprowadzać zmiennych don nie potrzebuję.

+0

Chociaż zgadzam się, że jest to zazwyczaj droga, istnieją przypadki użycia do dodawania wielu obiektów bezpośrednio do lokalnej przestrzeni nazw, np. dla matematyki. x == sin (w) * (y + exp (-z)) jest światem lepszym niż v.x == m.sin (v.w) * (v.y + m.exp (-v.z)). – DSM

+0

No cóż, myślę, że obsesja matematyków na temat jednoliterowych nazw zmiennych jest po prostu błędem. :) Przydaje się, gdy wykonujesz obliczenia na papierze lub upraszczasz/rozszerzasz formuły. Ale w rzeczywistej realizacji formuły w języku programowania? Nyaaahhhh'm sceptyczny ... :-) –

+2

Może natychmiast usuniesz wszystkie "v." oraz m." w moim drugim wyrazie i zobaczyć pierwsze wyrażenie, ale musiałem porównać je prawie postać po znaku, aby upewnić się, że są takie same. Dodatkowa litera dla każdej zmiennej i funkcji oraz kropka, która sprawia, że ​​myślę mnożenie. Bardziej prawdopodobne jest, że pominę oczywisty błąd w drugiej formie, ponieważ muszę przezwyciężyć wieloletnie doświadczenie w czytaniu standardowej formy bez obcej postaci. Czytelność się liczy, jak usłyszałem, że ktoś gdzieś mówi ;-), i ta zasada nie zawsze przechyla się na korzyść większej liczby postaci. – DSM

Powiązane problemy