ChatGPT解决这个技术问题 Extra ChatGPT

How do I check if a variable exists?

I want to check if a variable exists. Now I'm doing something like this:

try:
    myVar
except NameError:
    # Do something.

Are there other ways without exceptions?

What's wrong with the exception?
@S.Lott: if myVar is something really complicated, that takes a long time to produce/evaluate, wouldn't the try slow things down?
@dbliss: It's a variable. Aside from some really weird cases if you're doing something crazy with exec or metaclasses, it's not going to be expensive.
A more complete answer: stackoverflow.com/a/1592578/1661797
Keep in mind that exceptions per se are very cheap in python, compared to e.g. java and are almost encouraged / pythonic

A
Ayman Hourieh

To check the existence of a local variable:

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

To check the existence of a global variable:

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

To check if an object has an attribute:

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

Ok, and how can i check attribute existing in class?
and how do you turn the name of variable that possibly doesn't exist into a string?
But the OP is typing the code, they can type 'myVar' intstead of myVar. If the variable name is not known when the code is written, it will be stored in a string variable at runtime, and the check I posted will also work.
There are also built-in variables, and, if you have nested functions, variables in outer scopes. If you want to check for all of them, you're probably best off triggering NameError after all.
I liked best if hasattr(obj, 'attr_name'): which works for classes too: ie if hasattr(self, 'attr_name'):
p
paxdiablo

The use of variables that have yet to been defined or set (implicitly or explicitly) is often a bad thing in any language, since it tends to indicate that the logic of the program hasn't been thought through properly, and is likely to result in unpredictable behaviour.

If you need to do it in Python, the following trick, which is similar to yours, will ensure that a variable has some value before use:

try:
    myVar
except NameError:
    myVar = None      # or some other default value.

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

However, I'm still not convinced that's a good idea - in my opinion, you should try to refactor your code so that this situation does not occur.

By way of an example, the following code was given below in a comment, to allow line drawing from a previous point to the current point:

if last:
    draw(last, current);
last = current

In the case where last has not been bound to a value, that won't help in Python at all since even the checking of last will raise an exception. A better idea would be to ensure last does have a value, one that can be used to decide whether or not it is valid. That would be something like:

last = None

# some time passes ...

if last is not None:
    draw(last, current);
last = current

That ensures the variable exists and that you only use it if it's valid for what you need it for. This is what I assume the if last was meant to do in the comment code (but didn't), and you can still add the code to force this if you have no control over the initial setting of the variable, using the exception method above:

# Variable 'last' may or may not be bound to a value at this point.

try:
    last
except NameError:
    last = None

# It will always now be bound to a value at this point.

if last is not None:
    draw(last, current);
last = current

Maybe it's a variable of a dependancy, and acording to the version/platform it may or may not exist, and there's no other way to know what version it is.
State variables don't exist before they are assigned - if you draw a line from the previous position to the current position, then set previous = current, it doesn't mean you "don't know your variables" on the first call. And writing an extra line of code to initialize previous=null outside the draw routine doesn't mean you "know your variables" any better.
My point is that a block "if last: draw(last, current); last=current" is easy to understand and not poor programming. Adding a "try/except" to check for the existence of "last" before being able to test it detracts from readability of that code.
"The use of variables that haven't been defined is actually a bad thing in any language" Spare me the condescending speech. Some of us use Python for simple mathematics or statistics scripts using IDEs such as Spyder which work like Matlab. It makes sense sometimes in those environments to allow the user to define variables in the global console and check otherwise if they are undeclared in the script like when doing mathematics in Matlab.
@Ricardo, perhaps, rather than assuming it's condescension, you may want to at least consider the possibility that it's just good advice from someone who may be more knowledgeable :-) Or would you consider it equally patronising if I advised against unconstrained use of global variables, spaghetti code, god objects, releasing untested code, or writing operating systems in COBOL? My answer stated why I thought it was a bad idea (and there was nothing in the question indicating why OP thought it was necessary) but still provided a way on the off chance they really wanted to do it.
R
Roger Dahl

A simple way is to initialize it at first saying myVar = None

Then later on:

if myVar is not None:
    # Do something

There is much that is to be improved in this answer. Rather - A simple way is to declare it first. myVar = none # do stuff... if not myVar: # give myVar a value myVar = 'something'
i like this one a lot because i set things to None in my except statements
why not something like: if myVar: # Do something This avoids the need to read a double negative
@jjisnow Because you want this condition to be true even if myVar is an empty list, zero, empty string etc.
@jjisnow if myVar: # Do something throws NameError in python3 if myVar is not declared
佚名

Using try/except is the best way to test for a variable's existence. But there's almost certainly a better way of doing whatever it is you're doing than setting/testing global variables.

For example, if you want to initialize a module-level variable the first time you call some function, you're better off with code something like this:

my_variable = None

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

I try not to use this, because it pollutes the global namespace. One way to avoid this is to make the function a class, with my_variable as a class variable, and defining call as the body of the existing function, but that's a pain to code and opens up a bunch of other questions. I prefer to use function attributes, see below.
W
Wyrmwood

for objects/modules, you can also

'var' in dir(obj)

For example,

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

this is really answer
C
Community

I will assume that the test is going to be used in a function, similar to user97370's answer. I don't like that answer because it pollutes the global namespace. One way to fix it is to use a class instead:

class InitMyVariable(object):
  my_variable = None

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

I don't like this, because it complicates the code and opens up questions such as, should this confirm to the Singleton programming pattern? Fortunately, Python has allowed functions to have attributes for a while, which gives us this simple solution:

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

S
SilentGhost

catch is called except in Python. other than that it's fine for such simple cases. There's the AttributeError that can be used to check if an object has an attribute.


R
Roger Dahl

A way that often works well for handling this kind of situation is to not explicitly check if the variable exists but just go ahead and wrap the first usage of the possibly non-existing variable in a try/except 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
  ...

P
Psychzander

I created a custom function.

def exists(var):
     return var in globals()

Then the call the function like follows replacing variable_name with the variable you want to check:

exists("variable_name")

Will return True or False


What about local variables? Maybe make that function check for local variables too.
R
RGD2

Like so:

def no(var):
    "give var as a string (quote it like 'var')"
    assert(var not in vars())
    assert(var not in globals())
    assert(var not in vars(__builtins__))
    import keyword
    assert(var not in keyword.kwlist)

Then later:

no('foo')
foo = ....

If your new variable foo is not safe to use, you'll get an AssertionError exception which will point to the line that failed, and then you will know better. Here is the obvious contrived self-reference:

no('no')

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-88-d14ecc6b025a> in <module>
----> 1 no('no')

<ipython-input-86-888a9df72be0> in no(var)
      2     "give var as a string (quote it)"
      3     assert( var not in vars())
----> 4     assert( var not in globals())
      5     assert( var not in vars(__builtins__))
      6     import keyword

AssertionError: 

in python3, the line with __builtins__ should be replaced with: import builtins assert( var not in vars(builtins)) And it's probably not a bad practise to finish out the definition with a return True line, so you can write stuff like assert no('foo') which is clearer.
J
James

It may not be performant, but you generalise the solution to a function that checks both local variables and global variables.

import inspect
def exists_var(var_name):
    frame = inspect.currentframe()
    try:
        return var_name in frame.f_back.f_locals or var_name in globals()
    finally:
        del frame

Then you can use it like this:

exists_var('myVar')

Д
Давид Шико

Short variant:

my_var = some_value if 'my_var' not in globals() else my_var:

This is good for a use case we encounter in Databricks. It is not a very good system for detailed programs because running one notebook from another will clobber any same named variables. To reduce clobbered, use preexisting value if it exists
J
Jens

This was my scenario:

for i in generate_numbers():
    do_something(i)
# Use the last i.

I can’t easily determine the length of the iterable, and that means that i may or may not exist depending on whether the iterable produces an empty sequence.

If I want to use the last i of the iterable (an i that doesn’t exist for an empty sequence) I can do one of two things:

i = None  # Declare the variable.
for i in generate_numbers():
    do_something(i)
use_last(i)

or

for i in generate_numbers():
    do_something(i)
try:
    use_last(i)
except UnboundLocalError:
    pass  # i didn’t exist because sequence was empty.

The first solution may be problematic because I can’t tell (depending on the sequence values) whether i was the last element. The second solution is more accurate in that respect.


OP asked "Are there other ways without exceptions?" - Exceptions are slow and propagate, so if use_last(i) raises UnboundLocalError you'll get the wrong answer and no error message. That said, hasattr has the same issue so I guess this is the most "pythonic" answer.
G
Gulzar

Also a possibility for objects, use __dict__.

class A(object):
    def __init__(self):
        self.m = 1

a = A()
assert "m" in a.__dict__
assert "k" not in a.__dict__