9

I'm working on a python program and the author has written a function that looks like this

def blah():
    str = "asdf asdf asdf"
    doStuff(str)

This seems to work, even though str is a built in function and shouldn't be used as a variable.

What is actually happening here? My guess is str will no longer be usable as a function, but only in the scope of the blah() function he's written. Is that correct? This won't redefine str globally, right?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Dave
  • 1,326
  • 2
  • 11
  • 22
  • 5
    Yes, `str` is only redefined locally. This probably isn't a huge issue and I see examples like this with names like `max` and `str` frequently. If your function has only a couple of lines of code I wouldn't lose sleep over this. – juanpa.arrivillaga Dec 09 '16 at 20:33
  • 1
    Related: http://stackoverflow.com/q/41029289/2988730 (definitely not a dupe) – Mad Physicist Dec 09 '16 at 20:45
  • This can cause problems later. See also: [Why do I get "TypeError: 'str' object is not callable" with this code?](https://stackoverflow.com/questions/6039605). – Karl Knechtel Aug 09 '22 at 06:12
  • If you are in an interactive session and encountered problems like that, and you want to fix the problem without restarting the interpreter, see [How to restore a builtin that I overwrote by accident?](https://stackoverflow.com/questions/17152760). – Karl Knechtel Aug 09 '22 at 06:30

3 Answers3

10

Internally, the function's local variable table will contain an entry for str, which will be local to that function. You can still access the builtin class within the function by doing builtins.str in Py3 and __builtin__.str in Py2. Any code outside the function will not see any of the function's local variables, so the builtin class will be safe to use elsewhere.

There is another caveat/corner case here, which is described in this question. The local table entry is created at compile-time, not at runtime, so you could not use the global definition of str in the function even before you assign "asdf asdf asdf" to it:

def blah():
    x = str(12)
    str = "asdf asdf asdf"
    doStuff(str)

will fail with an UnboundLocalError.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • 4
    builtins.str throws `name 'builtins' is not defined`, apparently you need to call it using `__builtins__.str` . I'm using Python 3.7.5. – loco.loop Oct 30 '19 at 15:54
5

This seems to work, even though str is a built in function and shouldn't be used as a variable.

Yes, that is true. Python doesn't stop you from shooting yourself in the foot. It's up to you as the developer to make sure your not overwriting builtin names.

What is actually happening here? My guess is str will no longer be usable as a function, but only in the scope of the blah() function he's written. Is that correct? This won't redefine str globally, right?

Your are partially correct here as well. If the value of str is overwritten local, then only the current scope is affected. The global value of str remains unchanged. However, if str is over written in the global scope, then it affects all sub-scopes. The reason behind this is how the Python interpreter compiles values at run-time. This behavior can be observed using a simple example:

>>> def foo():
...     str = 0
...     return str
... 
>>> foo()
0
>>> str(0)
'0'
>>>

The first example works because str is only overwritten in the scope of foo(). This second example fails however because str is overwritten globally:

>>> str = 0
>>> def foo():
...     return str(0)
... 
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
TypeError: 'int' object is not callable
>>> 

You can always import builtins(__builtins__ in Python 2) though, and reset the value of str to its original meaning:

>>> str = 0
>>> str
0
>>> import __builtins__
>>> str = __builtins__.str
>>> str
<type 'str'>
>>> str(0)
'0'
>>> 

Also, as @Brad Solomon stated, you can simply use del str to recover the builtin str value:

>>> str = 0
>>> str
0
>>> del str
>>> str
<class 'str'>
>>> 
Christian Dean
  • 22,138
  • 7
  • 54
  • 87
0

In your case, str is just a variable and nothing prevents you from the usual use of str() outside that function:

>>> str = 'Hello world!'
>>> print str
Hello world!
str(str)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable

EDIT:

Here is a simple demo:

def salut():
   str = 'Hello world!'
   return str
if __name__ == '__main__':
   s = salut()
   print str(s) #nothing prevents you from using 'str' outside 'salut()'
Yamazaku
  • 21
  • 2
  • 1
    _"nothing prevents you from the usual use of str() function"_ - That's not complete true. as juanpa.arrivillaga has already mentioned `str` is redefined locally. So you couldn't use `str()` in the current scope, but you could in the global scope. – Christian Dean Dec 09 '16 at 20:42