如何防止意外覆盖Python内置函数?

Atl*_*as7 5 python python-2.7

我知道命名一个与Python内置函数同名的变量是个坏主意.但是如果一个人不知道要避免的所有"禁忌"变量名称(例如list,set等等),是否有办法让Python至少阻止你(例如通过错误消息)破坏内置函数?

例如,下面的命令行4允许我覆盖/损坏内置函数,set()而不会阻止我/产生错误.(这个错误一直没有被注意到,直到它被set()调用到下面的命令行6.).理想情况下,我希望Python在命令行4停止我(而不是等到命令行6).

注意:以下执行是在Python 2.7(iPython)控制台中执行的.(Anaconda Spyder IDE).

In [1]: myset = set([1,2])

In [2]: print(myset)
set([1, 2])

In [3]: myset
Out[3]: {1, 2}

In [4]: set = set([3,4])

In [5]: print(set)
set([3, 4])

In [6]: set
Out[6]: {3, 4}

In [7]: myset2 = set([5,6])
Traceback (most recent call last):

  File "<ipython-input-7-6f49577a7a45>", line 1, in <module>
    myset2 = set([5,6])

TypeError: 'set' object is not callable
Run Code Online (Sandbox Code Playgroud)

背景:我正在遵循HackerRank Python Set Challenge的教程.本教程涉及创建一个变量valled set(与Python内置函数同名).我逐行完成了教程,并得到了"set object is not callable"错误.上述测试是由这项练习推动的.(更新:我联系了HackerRank支持,他们已经确认他们可能在创建具有内置名称的变量时出错了.)

Dan*_*etz 4

正如其他人所说,Python 的哲学是允许用户“误用”事物,而不是试图想象和防止误用,因此没有内置类似的东西。但是,通过如此开放地被搞乱,Python 允许您以有限的方式实现您正在谈论的东西*。您可以用对象替换某些变量命名空间字典,以防止您最喜欢的变量被覆盖。(当然,如果这以意想不到的方式破坏了你的任何代码,你就会得到这两部分。)

为此,您需要使用诸如eval()execexecfile()、 或code.interact()、 或 override 之类的东西__import__()。这些允许您提供像字典一样的对象,用于存储变量。我们可以通过子类化创建一个“更安全”的替换字典dict

class SafeGlobals(dict):
    def __setitem__(self, name, value):
        if hasattr(__builtins__, name) or name == '__builtins__':
            raise SyntaxError('nope')
        return super(SafeGlobals, self).__setitem__(name, value)

my_globals = SafeGlobals(__builtins__=__builtins)
Run Code Online (Sandbox Code Playgroud)

my_globalsset 设置为当前命名空间,设置如下变量:

x = 3
Run Code Online (Sandbox Code Playgroud)

将翻译为以下内容:

my_globals['x'] = 3
Run Code Online (Sandbox Code Playgroud)

以下代码将执行一个 Python 文件,使用我们更安全的字典作为顶级命名空间:

execfile('safetyfirst.py', SafeGlobals(__builtins__=__builtins__))
Run Code Online (Sandbox Code Playgroud)

一个例子code.interact()

>>> code.interact(local=SafeGlobals(__builtins__=__builtins__))
Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> x = 2
>>> x
2
>>> dict(y=5)
{'y': 5}
>>> dict = "hi"
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "<stdin>", line 4, in __setitem__
SyntaxError: nope
Run Code Online (Sandbox Code Playgroud)

*不幸的是,这种方法非常有限。它只会阻止覆盖顶级命名空间中的内置函数。您可以随意覆盖其他命名空间中的内置函数:

>>> def f():
...     set = 1
...     return set
... 
>>> f()
1
Run Code Online (Sandbox Code Playgroud)

  • 访问 locals 恰好与访问 `locals()` 的元素相同,但规范不保证这种行为。也就是说,“x = 3”的行为可能与“locals()['x'] = 3”不同。 (2认同)