Fnayou Fnayou - 6 months ago 26
Python Question

Python allows assigning tuple to function (xticks of pyplot)

I have accidentally assigned a tuple to a pyplot function (that is xticks) and the function became a tuple. Restoring its previous type as a function was not possible. Is this normal or is it considered as an issue ?

import matplotlib.pyplot as plt
import matplotlib as mpl
%matplotlib inline

print mpl.__version__
# Version : 1.5.1

br = (1.0,2.0,3.0)
brand = ('Ford','Audi','Wolskvagen')
count = (100,2000,10000)
plt.xticks((1,2,3),('Ford','Audi','Wolskvagen'))

plt.scatter(x = br,y = count,c = col,s=count)

print type(plt.xticks)
#<type 'function'>

plt.xticks = ((1,2,3),('Ford','Audi','Wolskvagen'))
print type(plt.xticks)
#<type 'tuple'>
#Now, I can't use xticks function any more...

Answer

In Python, there is no such thing as a protected variable. You can write variables in the current namespace, to a module, with only a few exceptions (builtin types that are not subclassed, as well as any class that defines __slots__ (thanks Alex Hall) are the main exceptions).

For example:

>>> from collections import namedtuple
>>> x = namedtuple('x', 'a b')
>>> y = x(1, 3)
>>> y.a = 3
AttributeError: 'X' object attribute 'a' is read-only
>>> a.t = 3
AttributeError: 'X' object has no attribute 't'

This is only true for a few built-in types, as well as classes that override __setattr__ in a specific manner, or that use properties with no property setter. The general rule is, anything can be written to, whether it's a class, module, function, etc. Yes, functions.

>>> def a(x):
...     pass
>>> a.b = 1
>>> a.b
1

So, how do you fix an error if accidentally overwrite a variable in a module you imported? Either, restart the Python interpreter or reload the module.

Python2 Reloading

>>> import matplotlib.pyplot as plt
>>> plt.xticks = 5
>>> plt = reload(plt)
>>> plt.xticks
<function matplotlib.pyplot.xticks>

Python3 Reloading

>>> import matplotlib.pyplot as plt
>>> import importlib
>>> plt.xticks = 5
>>> plt = importlib.reload(plt)
>>> plt.xticks
<function matplotlib.pyplot.xticks>