Jak sprawdzić, czy zmienna istnieje?

953

Chcę sprawdzić, czy zmienna istnieje. Teraz robię coś takiego:

try:
   myVar
except NameError:
   # Do something.

Czy istnieją inne sposoby bez wyjątków?

Max Frai
źródło
15
Co jest nie tak z wyjątkiem?
S.Lott,
10
@ S.Lott: jeśli myVarjest to coś naprawdę skomplikowanego, którego opracowanie / ocena zajmuje dużo czasu, czy to nie tryzwolni?
dbliss,
3
@dbliss: To zmienna. Oprócz kilku naprawdę dziwnych przypadków, jeśli robisz coś szalonego z execmetaklasami, nie będzie to drogie.
użytkownik2357112 obsługuje Monikę
Bardziej kompletna odpowiedź: stackoverflow.com/a/1592578/1661797
nickboldt 29.09.16

Odpowiedzi:

1626

Aby sprawdzić istnienie zmiennej lokalnej:

if 'myVar' in locals():
  # myVar exists.

Aby sprawdzić istnienie zmiennej globalnej:

if 'myVar' in globals():
  # myVar exists.

Aby sprawdzić, czy obiekt ma atrybut:

if hasattr(obj, 'attr_name'):
  # obj.attr_name exists.
Ayman Hourieh
źródło
29
Ok i jak mogę sprawdzić atrybut istniejący w klasie?
Max Frai
7
i jak przekształcić nazwę zmiennej, która prawdopodobnie nie istnieje, w ciąg znaków?
SilentGhost
15
Ale OP pisze kod, mogą wpisać „myVar” zamiast myVar. Jeśli nazwa zmiennej nie jest znana, gdy kod jest zapisywany, zostanie on zapisany w zmiennej łańcuchowej w czasie wykonywania, a także wysłany czek będzie działał.
Ayman Hourieh
8
Istnieją również wbudowane zmienne, a jeśli masz zagnieżdżone funkcje, zmienne w zewnętrznych zakresach. Jeśli chcesz sprawdzić je wszystkie, prawdopodobnie najlepiej jest NameErrormimo wszystko uruchomić .
Petr Viktorin
14
Najbardziej podobało mi się, if hasattr(obj, 'attr_name'):co też działa na zajęcia: tj.if hasattr(self, 'attr_name'):
Ron Kalian
118

Stosowanie zmiennych, które jeszcze nie zostały zdefiniowane lub zestaw (pośrednio lub bezpośrednio) jest prawie zawsze złe w dowolnym języku, ponieważ często oznacza, że logika programu nie zostało przemyślane prawidłowo, a to może spowodować w nieprzewidywalnym zachowaniu.

Jeśli musisz to zrobić w Pythonie, następująca sztuczka, podobna do twojej, zapewni, że zmienna ma pewną wartość przed użyciem:

try:
    myVar
except NameError:
    myVar = None

# Now you're free to use myVar without Python complaining.

Jednak nadal nie jestem przekonany, że to dobry pomysł - moim zdaniem powinieneś spróbować zmienić kod swojego kodu, aby taka sytuacja nie wystąpiła.

paxdiablo
źródło
8
Być może jest to zmienna zależności i zgodnie z wersją / platformą może istnieć lub nie, i nie ma innego sposobu, aby dowiedzieć się, która to wersja.
WhyNotHugo
35
Zmienne stanu nie istnieją przed ich przypisaniem - jeśli narysujesz linię z poprzedniej pozycji do bieżącej pozycji, a następnie ustaw poprzednią = bieżącą, nie oznacza to, że „nie znasz swoich zmiennych” przy pierwszym wywołaniu. A napisanie dodatkowej linii kodu w celu zainicjowania previous = null poza procedurą rysowania nie oznacza, że ​​„znasz swoje zmienne” lepiej.
Dave
4
Chodzi mi o to, że blok „if last: draw (last, current); last = current” jest łatwy do zrozumienia i nie jest źle programowany. Dodanie słowa „spróbuj / z wyjątkiem” w celu sprawdzenia istnienia „ostatniego” przed przetestowaniem go pogarsza czytelność tego kodu.
Dave
23
„Używanie zmiennych, które nie zostały zdefiniowane, jest w rzeczywistości czymś złym w każdym języku”. Oszczędź mi protekcjonalnej mowy. Niektórzy z nas używają Pythona do prostych skryptów matematycznych lub statystycznych przy użyciu IDE, takich jak Spyder, które działają jak Matlab. Czasami ma to sens w tych środowiskach, aby pozwolić użytkownikowi na definiowanie zmiennych w globalnej konsoli i sprawdzanie, czy nie są one zadeklarowane w skrypcie, tak jak w przypadku matematyki w Matlabie.
Ricardo Cruz,
15
@Ricardo, być może, zamiast zakładać, że jest to protekcjonalność, możesz przynajmniej rozważyć możliwość, że jest to dobra rada od kogoś, kto może być bardziej kompetentny :-) Czy też uważasz, że to równie protekcjonalne, gdybym odradzał nieograniczone korzystanie z globalnej zmienne, kod spaghetti, boskie obiekty, wypuszczanie nieprzetestowanego kodu lub pisanie systemów operacyjnych w języku COBOL? Moja odpowiedź wyjaśniła, dlaczego uważam, że to zły pomysł (i nic nie było w pytaniu wskazującym, dlaczego OP uznała to za konieczne), ale nadal dawało szansę na to, że naprawdę chcieli to zrobić.
paxdiablo
52

Prostym sposobem jest zainicjowanie go na początku myVar = None

Potem:

if myVar is not None:
    # Do something
Chinedum Ukejianya
źródło
2
W tej odpowiedzi należy poprawić wiele. Raczej - Prostym sposobem jest zadeklarowanie go jako pierwszego. myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
Shawn Mehan
bardzo mi się podoba, ponieważ w moich exceptwypowiedziach
ustawiłem różne wartości
dlaczego nie coś takiego: if myVar: # Do something Pozwala to uniknąć konieczności czytania podwójnego negatywu
jjisnow
@ jjisnow Ponieważ chcesz, aby ten warunek był spełniony, nawet jeśli myVarjest pusta lista, zero, pusty ciąg itp.
Gabriel
7
@jjisnow if myVar: # Do somethingrzuca NameErrorw python3, jeśli myVar nie jest zadeklarowany
Agile Bean
25

Użycie try / wyjątek jest najlepszym sposobem na sprawdzenie istnienia zmiennej. Ale jest prawie na pewno lepszy sposób robienia czegokolwiek, co robisz, niż ustawianie / testowanie zmiennych globalnych.

Na przykład, jeśli chcesz zainicjować zmienną na poziomie modułu przy pierwszym wywołaniu jakiejś funkcji, lepiej jest napisać kod podobny do tego:

my_variable = None

def InitMyVariable():
  global my_variable
  if my_variable is None:
    my_variable = ...

źródło
2
Staram się tego nie używać, ponieważ zanieczyszcza globalną przestrzeń nazw. Jednym ze sposobów, aby tego uniknąć, jest uczynienie funkcji klasą z my_variable jako zmienną klasy i zdefiniowanie wywołania jako treści istniejącej funkcji, ale jest to kłopotliwe dla kodu i otwiera wiele innych pytań. Wolę używać atrybutów funkcji, patrz poniżej.
samwyse
17

dla obiektów / modułów możesz także

'var' in dir(obj)

Na przykład,

>>> class Something(object):
...     pass
...
>>> c = Something()
>>> c.a = 1
>>> 'a' in dir(c)
True
>>> 'b' in dir(c)
False
Wyrmwood
źródło
11

Zakładam, że test będzie używany w funkcji podobnej do odpowiedzi user97370 . Nie podoba mi się ta odpowiedź, ponieważ zanieczyszcza globalną przestrzeń nazw. Jednym ze sposobów, aby to naprawić, jest użycie klasy:

class InitMyVariable(object):
  my_variable = None

def __call__(self):
  if self.my_variable is None:
   self.my_variable = ...

Nie podoba mi się to, ponieważ komplikuje kod i otwiera pytania, takie jak: czy powinno to potwierdzić wzorzec programowy Singleton? Na szczęście Python przez pewien czas pozwalał funkcjom mieć atrybuty, co daje nam to proste rozwiązanie:

def InitMyVariable():
  if InitMyVariable.my_variable is None:
    InitMyVariable.my_variable = ...
InitMyVariable.my_variable = None
samwyse
źródło
9

catchjest wywoływany exceptw Pythonie. poza tym w takich prostych przypadkach jest w porządku. Są takie, AttributeErrorktóre można wykorzystać do sprawdzenia, czy obiekt ma atrybut.

SilentGhost
źródło
5

Sposób, który często działa dobrze w przypadku obsługi tego rodzaju sytuacji, to nie jawne sprawdzanie, czy zmienna istnieje, ale po prostu kontynuuj i zapisz pierwsze użycie prawdopodobnie nieistniejącej zmiennej w try / oprócz NameError:

# Search for entry.
for x in y:
  if x == 3:
    found = x

# Work with found entry.
try:
  print('Found: {0}'.format(found))
except NameError:
  print('Not found')
else:
  # Handle rest of Found case here
  ...
Roger Dahl
źródło
3

Stworzyłem niestandardową funkcję.

def exists(var):
     var_exists = var in locals() or var in globals()
     return var_exists

Następnie wywołaj funkcję podobną do zastępującej variable_namezmienną, którą chcesz sprawdzić:

exists("variable_name")

Wróci TruelubFalse

Abhishek R.
źródło
2
Nie, to nie zadziała. locals()jest ... err ... lokalny dla funkcji exists😅
bgusach
1
1) Funkcja locals () jest lokalna. 2) Dlaczego dodatkowe przypisanie var_exists?
Dave