389

Is it possible to declare a variable in Python, like so?:

var

so that it initialized to None? It seems like Python allows this, but as soon as you access it, it crashes. Is this possible? If not, why?

EDIT: I want to do this for cases like this:

value

for index in sequence:

   if value == None and conditionMet:
       value = index
       break

Related Questions

See Also

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • You've posted a duplicate question, voting to close this question in favour of the other one. – Jerub Mar 19 '09 at 23:18
  • There is still some difference, this one deals with the not being able to use a variable just by declaring. – Joan Venge Mar 19 '09 at 23:36
  • There's not really any such thing as declaring a variable in the python world, as your first question explains. – Harley Holcombe Mar 20 '09 at 02:32
  • 2
    why didn't anyone ever say 'just assign to it' because variables do not exist before they are assigned to period. And variables in python are not containing the type information. Objects do that. Variables are just for holding the object at that point in time. Furthermore, the program above should throw a NameError exception on the first line. (Thats what I get in 2.X and 3.X both) – osirisgothra Jul 09 '15 at 05:11

14 Answers14

466

Why not just do this:

var = None

Python is dynamic, so you don't need to declare things; they exist automatically in the first scope where they're assigned. So, all you need is a regular old assignment statement as above.

This is nice, because you'll never end up with an uninitialized variable. But be careful -- this doesn't mean that you won't end up with incorrectly initialized variables. If you init something to None, make sure that's what you really want, and assign something more meaningful if you can.

Todd Gamblin
  • 58,354
  • 15
  • 89
  • 96
  • 2
    I was gonna do that, but just thought implicitly it would do that. – Joan Venge Mar 19 '09 at 22:50
  • 11
    The point is for this to be explicit, not implicit. No guessing what the initial value is. No wondering if an uninitialized variable throws an exception or magically has a useful value. – S.Lott Mar 19 '09 at 23:31
  • 2
    Only issue I have with this was I was keeping track of a counter (minValue) and any time a value was lower than it, I was setting it to become the new minValue. If I declared minValue as None originally, then apparently it is still lower than any numbers I compared it against. I ended up just initializing it at sys.maxint – TJ Biddle May 29 '12 at 17:41
  • ...they exist automatically in the first scope where they're assigned. So, you have to hunt down that first assignment and figure it out. ugh! – Ed Randall Nov 09 '17 at 09:39
  • 'NoneType' object is not subscriptable – Robin Mollah May 25 '22 at 19:53
  • @RobinMollah exactly as it says: if nothing ever assigns a *different* value to `var`, then `var` will still be equal to the `None` that was assigned before the loop. There are not very many things you can do with `None`. In particular, you cannot get its elements, because it is not a thing that has elements. – Karl Knechtel Jun 28 '22 at 21:19
  • @TJBiddle in 3.x, comparing between `None` and integers will raise a `TypeError`. For the 2.x behaviour, see e.g. https://stackoverflow.com/questions/2214194. – Karl Knechtel Jun 28 '22 at 21:21
  • 'why not just do this...' I am using MyPy to annotate and if I have a variable whose value will be determined in an if statement then we have to find a way around type annotations. Consider `my_num: int = None` MyPy will scream at me because None is not an int. So then I am forced to... `my_num: typing.Optional[int] = None` but every time I use my_num, I have to type narrow. For example `def foo(num: int) -> None: ... foo(my_num)` MyPy will scream at me again To fix this I need to do. `assert isinstance(my_num, int) foo(my_num)` – Dario Dec 13 '22 at 11:08
  • I suggest changing *"... in the first scope where they're assigned"* to *"... in the scope where they're assigned"*. Each variable has only one scope, and variables can be in scope *before* they are assigned (hence `UnboundLocalError`). – kaya3 Mar 24 '23 at 01:16
  • @Dario: FWIW, I answered this question in 2009 and mypy didn't exist until 2012. That said, the question was whether it's possible to declare a variable in Python "so that it initialized to None". If you're using mypy and you don't want to initialize a variable as None, then don't. Just write `my_num: int`. See https://mypy.readthedocs.io/en/stable/class_basics.html#instance-and-class-attributes. – Todd Gamblin Jun 13 '23 at 16:17
88

In Python 3.6+ you could use Variable Annotations for this:

https://www.python.org/dev/peps/pep-0526/#abstract

PEP 484 introduced type hints, a.k.a. type annotations. While its main focus was function annotations, it also introduced the notion of type comments to annotate variables:

# 'captain' is a string (Note: initial value is a problem)
captain = ...  # type: str

PEP 526 aims at adding syntax to Python for annotating the types of variables (including class variables and instance variables), instead of expressing them through comments:

captain: str  # Note: no initial value!

It seems to be more directly in line with what you were asking "Is it possible only to declare a variable without assigning any value in Python?"

Note: The Python runtime does not enforce function and variable type annotations. They can be used by third party tools such as type checkers, IDEs, linters, etc.

Tagar
  • 13,911
  • 6
  • 95
  • 110
  • 4
    Should be the accepted answer (at this point in Python's evolution etc) – scharfmn Jun 10 '21 at 14:01
  • Re "Note: no initial value!": it does not actually create the variable, either. Attempting to access `captain` before assigning a value will cause the same `NameError` as it would have otherwise. On the other hand, the code also does not impose any restriction on what can be assigned. Code like `captain: str`, while valid in 3.6 and up, has **no effect** in Python itself; it is **only** potentially used by third-party type-checking tools. – Karl Knechtel Jun 28 '22 at 21:12
  • @KarlKnechtel yep, this is called out in PEP 526, I added that note, thanks – Tagar Jul 20 '22 at 22:11
60

I'd heartily recommend that you read Other languages have "variables" (I added it as a related link) – in two minutes you'll know that Python has "names", not "variables".

val = None
# ...
if val is None:
   val = any_object
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • 2
    You could also write `val = val or any_object` to initialize it. – Zoltán Dec 18 '13 at 22:29
  • 1
    @Zoltán: it breaks if a valid value for val is "false" e.g., zero or empty. Use `is` to test whether a value is `None`. – jfs Dec 19 '13 at 02:14
  • 2
    After reading the article at the supplied link, it appears to be little more than semantic sophistry. – Andrew P. Mar 15 '18 at 22:50
  • 1
    @AndrewP.: don't dismiss it so easily. I stand by my recommendation after all these years. "nametag -> balloon" model is very simple and at the same time it describes well the name binding behavior in Python. – jfs Apr 11 '22 at 07:05
16

I'm not sure what you're trying to do. Python is a very dynamic language; you don't usually need to declare variables until you're actually going to assign to or use them. I think what you want to do is just

foo = None

which will assign the value None to the variable foo.

EDIT: What you really seem to want to do is just this:

#note how I don't do *anything* with value here
#we can just start using it right inside the loop

for index in sequence:
   if conditionMet:
       value = index
       break

try:
    doSomething(value)
except NameError:
    print "Didn't find anything"

It's a little difficult to tell if that's really the right style to use from such a short code example, but it is a more "Pythonic" way to work.

EDIT: below is comment by JFS (posted here to show the code)

Unrelated to the OP's question but the above code can be rewritten as:

for item in sequence:
    if some_condition(item): 
       found = True
       break
else: # no break or len(sequence) == 0
    found = False

if found:
   do_something(item)

NOTE: if some_condition() raises an exception then found is unbound.
NOTE: if len(sequence) == 0 then item is unbound.

The above code is not advisable. Its purpose is to illustrate how local variables work, namely whether "variable" is "defined" could be determined only at runtime in this case. Preferable way:

for item in sequence:
    if some_condition(item):
       do_something(item)
       break

Or

found = False
for item in sequence:
    if some_condition(item):
       found = True
       break

if found:
   do_something(item)
jfs
  • 399,953
  • 195
  • 994
  • 1,670
kquinn
  • 10,433
  • 4
  • 35
  • 35
  • Is there a difference between a dynamic language and a very dynamic language? – Gavin Miller Mar 19 '09 at 22:35
  • There's a great article explaining the different axes of programming language typing, and how they're continuums, not boolean values; unfortunately I can never find that article again when I want to cite it :( I consider Python "very dynamic" because it's on the far end of multiple axes. – kquinn Mar 19 '09 at 23:09
3

Well, if you want to check if a variable is defined or not then why not check if its in the locals() or globals() arrays? Your code rewritten:

for index in sequence:
   if 'value' not in globals() and conditionMet:
       value = index
       break

If it's a local variable you are looking for then replace globals() with locals().

Johan
  • 1,189
  • 3
  • 15
  • 28
2

I usually initialize the variable to something that denotes the type like

var = ""

or

var = 0

If it is going to be an object then don't initialize it until you instantiate it:

var = Var()
Andrew Hare
  • 344,730
  • 71
  • 640
  • 635
2

First of all, my response to the question you've originally asked

Q: How do I discover if a variable is defined at a point in my code?

A: Read up in the source file until you see a line where that variable is defined.

But further, you've given a code example that there are various permutations of that are quite pythonic. You're after a way to scan a sequence for elements that match a condition, so here are some solutions:

def findFirstMatch(sequence):
    for value in sequence:
        if matchCondition(value):
            return value

    raise LookupError("Could not find match in sequence")

Clearly in this example you could replace the raise with a return None depending on what you wanted to achieve.

If you wanted everything that matched the condition you could do this:

def findAllMatches(sequence):
    matches = []
    for value in sequence:
        if matchCondition(value):
            matches.append(value)

    return matches

There is another way of doing this with yield that I won't bother showing you, because it's quite complicated in the way that it works.

Further, there is a one line way of achieving this:

all_matches = [value for value in sequence if matchCondition(value)]
Jerub
  • 41,746
  • 15
  • 73
  • 90
2

If I'm understanding your example right, you don't need to refer to 'value' in the if statement anyway. You're breaking out of the loop as soon as it could be set to anything.

value = None
for index in sequence:
   doSomethingHere
   if conditionMet:
       value = index
       break 
Peter
  • 27,590
  • 8
  • 64
  • 84
Nails N.
  • 561
  • 4
  • 11
2

I know it's coming late but with python3, you can declare an uninitialized value by using

uninitialized_value:str

# some code logic

uninitialized_value = "Value"

But be very careful with this trick tho, because

uninitialized_value:str

# some code logic

# WILL NOT WORK
uninitialized_value += "Extra value\n"
Ekure Edem
  • 310
  • 2
  • 10
  • 1
    The code `uninitialized_value:str` has **no effect** in the actual program. It is **only** used by third-party type-checking tools. It is **not** a "declaration", because Python doesn't have declarations. It **does not** make the name `uninitialized_value` exist (which is why the `+=` doesn't work), and it **does not** prevent assigning a value of a different type (only the third-party type checker will complain). – Karl Knechtel Aug 13 '22 at 13:25
1

If None is a valid data value then you need to the variable another way. You could use:

var = object()

This sentinel is suggested by Nick Coghlan.

Chris_Rands
  • 38,994
  • 14
  • 83
  • 119
1

Is it possible to declare a variable in Python (var=None):

def decl_var(var=None):
if var is None:
    var = []
var.append(1)
return var
Pasha
  • 134
  • 1
  • 7
0
var_str = str()
var_int = int()
Rory McCrossan
  • 331,213
  • 40
  • 305
  • 339
Zaur
  • 431
  • 4
  • 5
0

You can trick an interpreter with this ugly oneliner if None: var = None It do nothing else but adding a variable var to local variable dictionary, not initializing it. Interpreter will throw the UnboundLocalError exception if you try to use this variable in a function afterwards. This would works for very ancient python versions too. Not simple, nor beautiful, but don't expect much from python.

ZAB
  • 963
  • 10
  • 18
0

You look like you're trying to write C in Python. If you want to find something in a sequence, Python has builtin functions to do that, like

value = sequence.index(blarg)