Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can you assign values to built-in functions in Python?

I found out about this by accident today when I noticed that a piece of Python code had used the built-in function all as a variable identifier to store the result of a list comprehension and it didn't throw an error, so I tried the following:

type('abc')
Out[1]: str

type('abc') == str
Out[2]: True

str = int

type('abc') == str
Out[4]: False

type('abc')
Out[5]: str

type = [1,2,3]

type('abc')
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-a74a7df76db1> in <module>()
----> 1 type('abc')

TypeError: 'list' object is not callable 

Hopefully, it's a valid question when I ask why this behavior is allowed in Python.

Or better yet, how do I make sure that a built-in function like str is really str and not say, int so str(123) won't be evaluated as int(123) by accident?

like image 789
Vinayak Avatar asked Aug 06 '15 20:08

Vinayak


People also ask

Can we assign values to keywords in Python?

An example of something you can't do with Python keywords is assign something to them. If you try, then you'll get a SyntaxError . You won't get a SyntaxError if you try to assign something to a built-in function or type, but it still isn't a good idea.

How are values assigned in Python?

The assignment operator, denoted by the “=” symbol, is the operator that is used to assign values to variables in Python. The line x=1 takes the known value, 1, and assigns that value to the variable with name “x”. After executing this line, this number will be stored into this variable.

Can we assign value to function?

No, you can't assign values to functions. You can assign values to function pointers, but not to functions in C++. Try assigning anything to foo in your example, for instance.


1 Answers

Python expects you to take responsibility for your code, is why. Python doesn't have private attributes, no protected classes, and almost no limits on what names you can use.

Yes, that means you can accidentally rename a built-in. Create unittests for your code, use a linter, and generally, you'll quickly learn to spot accidental use of a built-in you needed. It's no different from accidentally re-using any other name in your code.

Note that you are simply masking the built-in names; name lookups that fail to find a global next look at the built-in namespace, so if you set str to something else, that is found before the built-in. Simply delete the global:

>>> str = 'foobar'
>>> isinstance('foobar', str)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types
>>> del str
>>> isinstance('foobar', str)
True

The alternative would be to make every built-in name a reserved keyword, leaving you with a much diminished list of names that is allowed, and no flexibility in re-defining those objects. Python 2.7 has 144 such names, for example.

In this context, see this blog post by Guido van Rossum on why None, True and False are now keywords in Python 3:

Because you cannot use these as variable or function names anywhere, ever, in any Python program, everyone using Python has to know about all the reserved words in the language, even if they don't have any need for them. For this reason, we try to keep the list of reserved words small, and the core developers hem and haw a lot before adding a new reserved word to the language.

like image 118
Martijn Pieters Avatar answered Oct 21 '22 07:10

Martijn Pieters