Как проверить, существует ли переменная?


955

Я хочу проверить, существует ли переменная. Сейчас я делаю что-то вроде этого:

try:
   myVar
except NameError:
   # Do something.

Есть ли другие способы без исключений?


15
Что не так с исключением?
S.Lott

10
@ S.Lott: если myVarчто-то действительно сложное, на его изготовление / оценку уходит много времени, разве не все будет tryмедленно?
ДБЛИС

3
@dbliss: это переменная. Помимо некоторых действительно странных случаев, если вы делаете что-то сумасшедшее execили метаклассы, это не будет дорого.
user2357112 поддерживает Monica

Более полный ответ: stackoverflow.com/a/1592578/1661797
nickboldt

Ответы:


1629

Чтобы проверить существование локальной переменной:

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

Чтобы проверить существование глобальной переменной:

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

Чтобы проверить, есть ли у объекта атрибут:

if hasattr(obj, 'attr_name'):
  # obj.attr_name exists.

31
Хорошо, а как я могу проверить атрибут, существующий в классе?
Макс Фрай

7
и как вы превращаете имя переменной, которая, возможно, не существует в строку?
SilentGhost

15
Но ОП набирает код, вместо myVar они могут напечатать «myVar». Если имя переменной неизвестно при написании кода, оно будет сохранено в строковой переменной во время выполнения, и проверенная мной проверка также будет работать.
Айман Хуриех

8
Есть также встроенные переменные и, если у вас есть вложенные функции, переменные во внешних областях. Если вы хотите проверить их все, лучше всего запустить их в NameErrorконце концов.
Петр Викторин

14
Мне понравилось больше всего, if hasattr(obj, 'attr_name'):что работает и для классов: т.е.if hasattr(self, 'attr_name'):
Рон

118

Использование переменных , которые еще не были определены или набор (явно или неявно) почти всегда плохо в любом языке, так как она часто указывает на то, что логика программы не была продумана правильно, и, скорее всего, результат в непредсказуемом поведении.

Если вам нужно сделать это в Python, следующий трюк, который похож на ваш, перед использованием гарантирует, что переменная имеет какое-то значение:

try:
    myVar
except NameError:
    myVar = None

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

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


8
Может быть, это переменная зависимости, и в зависимости от версии / платформы она может существовать или не существовать, и нет другого способа узнать, какая это версия.
WhyNotHugo

35
Переменные состояния не существуют до того, как они назначены - если вы рисуете линию от предыдущей позиции к текущей позиции, а затем задаете предыдущую = текущую, это не означает, что вы «не знаете своих переменных» при первом вызове. И написание дополнительной строки кода для инициализации previous = null вне процедуры рисования не означает, что вы «лучше знаете свои переменные».
Дейв

4
Моя точка зрения заключается в том, что блок «если последний: отрисовка (последний, текущий); последний = текущий» легко понять и не плохое программирование. Добавление «попробовать / исключить» для проверки существования «последнего» перед тем, как можно будет его проверить, снижает читабельность этого кода.
Дэйв

23
«Использование переменных, которые не были определены, на самом деле плохо на любом языке» Избавь меня от снисходительной речи. Некоторые из нас используют Python для простых математических или статистических сценариев, используя IDE, такие как Spyder, которые работают как Matlab. Иногда в этих средах имеет смысл позволить пользователю определять переменные в глобальной консоли и в противном случае проверять, не объявлены ли они в сценарии, как при выполнении математики в Matlab.
Рикардо Крус,

15
@Ricardo, возможно, вместо того, чтобы предполагать, что это снисходительность, вы можете, по крайней мере, рассмотреть возможность того, что это просто хороший совет от кого-то, кто может быть более осведомленным :-) Или вы бы посчитали это одинаково покровительственным, если бы я советовал не ограничивать использование глобального переменные, спагетти-код, объекты бога, выпуск непроверенного кода или написание операционных систем на языке COBOL? В моем ответе говорилось, почему я думал, что это плохая идея (и в вопросе не было ничего, указывающего, почему OP посчитал это необходимым), но все же предоставлялась возможность, если они действительно хотели это сделать.
paxdiablo

53

Простой способ - сначала инициализировать его, сказав myVar = None

Затем позже:

if myVar is not None:
    # Do something

2
В этом ответе многое можно улучшить. Скорее - простой способ объявить об этом первым. myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
Шон Механ,

мне это очень нравится, потому что я установил None в своих exceptвысказываниях
HashRocketSyntax

почему не что-то вроде этого: if myVar: # Do something Это избавляет от необходимости читать двойной негатив
jjisnow

@jjisnow Потому что вы хотите, чтобы это условие было истинным, даже если myVarэто пустой список, ноль, пустая строка и т. д.
Габриэль

7
@jjisnow if myVar: # Do somethingбросает NameErrorв Python3 если MYVAR не объявлен
AGile компоненты -

25

Использование try / исключением - лучший способ проверить существование переменной. Но почти наверняка есть лучший способ сделать то, что вы делаете, чем устанавливать / тестировать глобальные переменные.

Например, если вы хотите инициализировать переменную уровня модуля при первом вызове некоторой функции, вам лучше использовать код, подобный следующему:

my_variable = None

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

2
Я стараюсь не использовать это, потому что это загрязняет глобальное пространство имен. Один из способов избежать этого состоит в том, чтобы сделать функцию классом, с my_variable в качестве переменной класса, и определить вызов в качестве тела существующей функции, но это неудобно для кода и открывает кучу других вопросов. Я предпочитаю использовать атрибуты функции, см. Ниже.
samwyse

17

для объектов / модулей вы также можете

'var' in dir(obj)

Например,

>>> class Something(object):
...     pass
...
>>> c = Something()
>>> c.a = 1
>>> 'a' in dir(c)
True
>>> 'b' in dir(c)
False

11

Я предполагаю, что тест будет использоваться в функции, аналогичной ответу пользователя 97370 . Мне не нравится этот ответ, потому что он загрязняет глобальное пространство имен. Один из способов исправить это - использовать класс:

class InitMyVariable(object):
  my_variable = None

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

Мне это не нравится, потому что это усложняет код и открывает такие вопросы, как, должно ли это подтвердить шаблон программирования Singleton? К счастью, Python позволил функциям некоторое время иметь атрибуты, что дает нам простое решение:

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

9

catchназывается exceptв Python. кроме этого это хорошо для таких простых случаев. Там AttributeErrorможно использовать, чтобы проверить, есть ли у объекта атрибут.


5

Способ, который часто работает хорошо для обработки такой ситуации, состоит в том, чтобы не явно проверять, существует ли переменная, а просто пойти дальше и обернуть первое использование, возможно, несуществующей переменной, в try / кроме 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
  ...

3

Я создал пользовательскую функцию.

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

Затем следует вызов функции, аналогичной замене variable_nameпеременной, которую вы хотите проверить:

exists("variable_name")

Вернется TrueилиFalse


2
Нет, это не сработает. locals()является ... ошибочным ... локальным для функции exists😅
bgusach

1
1) Функция localals () является локальной. 2) Почему дополнительное назначение var_exists?
Дейв
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.