Як перевірити наявність змінної?


953

Я хочу перевірити, чи існує змінна. Зараз я роблю щось подібне:

try:
   myVar
except NameError:
   # Do something.

Чи існують інші без винятку способи?


15
Що не так з винятком?
С.Лотт

10
@ S.Lott: якщо myVarщось дійсно складне, що потребує тривалого часу, щоб виробити / оцінити, чи не tryсповільнить це справи?
dbliss

3
@dbliss: це змінна. Крім деяких справді дивних випадків, якщо ви робите щось божевільне з execметакласами або це не буде дорого.
user2357112 підтримує Monica

Більш повну відповідь: stackoverflow.com/a/1592578/1661797
nickboldt

Відповіді:


1627

Щоб перевірити наявність локальної змінної:

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

Щоб перевірити існування глобальної змінної:

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

Щоб перевірити, чи має об’єкт атрибут:

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

29
Гаразд, і як я можу перевірити атрибут, наявний у класі?
Макс Фрай

7
і як ви перетворите ім'я змінної, яка, можливо, не існує в рядок?
SilentGhost

15
Але ОП набирає код, вони можуть набрати 'myVar' intstead 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
Змінні стану не існують до того, як вони будуть призначені - якщо ви намалюєте рядок від попередньої позиції до поточної позиції, а потім встановите попереднє = поточне, це не означає, що ви "не знаєте своїх змінних" під час першого дзвінка. І написання додаткового рядка коду для ініціалізації попереднього = null поза програмою малювання не означає, що ви «краще знаєте свої змінні».
Дейв

4
Моя думка полягає в тому, що блок "if last: draw (last, current); last = current" є легким для розуміння і не поганим програмуванням. Додавання "спробувати / за винятком", щоб перевірити наявність "останнього", перш ніж мати можливість протестувати, це заважає читабельності цього коду.
Дейв

23
"Використання змінних, які не були визначені, насправді є поганою справою в будь-якій мові". Деякі з нас використовують Python для простих скриптів з математики чи статистики за допомогою IDE, таких як Spyder, які працюють як Matlab. Іноді в цих середовищах є сенс дозволити користувачеві визначати змінні в глобальній консолі та перевіряти інше, чи не визначено вони в сценарії, як це робиться в математиці в Matlab.
Рікардо Крус

15
@ Рікардо, можливо, замість того, щоб припускати, що це поблажливість, ви можете хоч би розглянути можливість того, що це просто хороша порада від того, хто може бути більш обізнаним :-) Або ви вважаєте це однаково покровительським, якби я радив проти нестримного використання глобального змінні, код спагетті, об'єкти God, випускаючи неперевірений код або записуючи операційні системи в COBOL? У моїй відповіді було зазначено, чому я вважаю це поганою ідеєю (і в питанні нічого не було, що вказувало б на те, чому ОП вважає це необхідним), але все ж надало можливість виходу з місця, коли вони дійсно хотіли це зробити.
paxdiablo

52

Простий спосіб - ініціалізувати його на першому слові myVar = None

Потім пізніше:

if myVar is not None:
    # Do something

2
У цій відповіді можна багато чого покращити. Швидше - простий спосіб спочатку це оголосити. myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
Шон Механ

мені це дуже подобається, тому що я в своїх exceptзаявах встановив речі "Нічого"
HashRocketSyntax,

чому б не щось на кшталт: if myVar: # Do something Це дозволяє уникнути необхідності читати подвійний негатив
jjisnow

@jjisnow Тому що ви хочете, щоб ця умова була справжньою, навіть якщо myVarце порожній список, нуль, порожній рядок тощо
Габріель

7
@jjisnow if myVar: # Do somethingкидає NameErrorв python3, якщо myVar не оголошено
Agile Bean

25

Використання спробувати / крім - це найкращий спосіб перевірити наявність змінної. Але майже напевно є кращий спосіб робити все, що ви робите, ніж установка / тестування глобальних змінних.

Наприклад, якщо ви хочете ініціалізувати змінну рівня модуля під час першого виклику якоїсь функції, вам краще скористатися таким кодом:

my_variable = None

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

2
Я намагаюся не використовувати це, оскільки це забруднює глобальний простір імен. Один із способів уникнути цього - зробити функцію класом, з мій_перемінною як змінною класу, і визначити виклик як тіло існуючої функції, але це больове кодування і відкриває купу інших питань. Я вважаю за краще використовувати атрибути функції, див. Нижче.
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

Я припускаю, що тест буде використовуватися у функції, подібній до відповіді user97370 . Мені не подобається ця відповідь, оскільки вона забруднює глобальний простір імен. Один із способів виправити це - замість цього використовувати клас:

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

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