如何防止意外覆盖Python内置函数?
我知道,给一个与Python内置函数同名的变量命名是个坏主意。但是如果一个人不知道所有要避免的“禁忌”变量名(例如如何防止意外覆盖Python内置函数?,python,python-2.7,Python,Python 2.7,我知道,给一个与Python内置函数同名的变量命名是个坏主意。但是如果一个人不知道所有要避免的“禁忌”变量名(例如列表,集,等等),那么有没有办法让Python至少阻止你(例如通过错误消息)破坏内置函数 例如,下面的命令行4允许我覆盖/损坏内置函数set(),而不会阻止我/产生错误。(在调用set()时,该错误一直未被注意到,直到到达下面的命令行6。)。理想情况下,我希望Python在命令行4停止我(而不是等到命令行6) 注意:以下执行是在Python2.7(iPython)控制台中执行的。(水
列表
,集
,等等),那么有没有办法让Python至少阻止你(例如通过错误消息)破坏内置函数
例如,下面的命令行4允许我覆盖/损坏内置函数set()
,而不会阻止我/产生错误。(在调用set()
时,该错误一直未被注意到,直到到达下面的命令行6。)。理想情况下,我希望Python在命令行4停止我(而不是等到命令行6)
注意:以下执行是在Python2.7(iPython)控制台中执行的。(水蟒Spyder IDE)
[1]中的:myset=set([1,2])
在[2]中:打印(myset)
集合([1,2])
在[3]中:myset
Out[3]:{1,2}
[4]中:set=set([3,4])
In[5]:打印(套)
集合([3,4])
In[6]:集合
Out[6]:{3,4}
[7]中:myset2=set([5,6])
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
myset2=set([5,6])
TypeError:“set”对象不可调用
背景:我当时正在学习教程。本教程涉及创建一个变量valled
set
(与Python内置函数同名)。我一行一行地尝试了教程,并得到了“set object is not callable”错误。上述测试由本练习驱动。(更新:我联系了HackerRank支持人员,他们确认他们可能在创建内置名称的变量时出错。)这是一个有趣的想法;不幸的是,Python的限制性不是很强,并且没有为这种意图提供现成的解决方案。在更深的嵌套范围中重写较低级别的标识符是Python理念的一部分,事实上,这是需要的,并且经常使用。如果您以某种方式禁用了此功能,我想很多库代码将立即被破坏
不过,您可以创建一个检查函数,用于测试当前堆栈中的任何内容是否已被重写。为此,您将逐步遍历所处的所有嵌套帧,并检查它们的局部变量是否也存在于其父帧中。这是一项非常内省的工作,可能不是你想做的,但我认为这是可以做到的。有了这样一个工具,您可以使用Python的跟踪功能在每一行执行后检查状态是否仍然是干净的;这与调试器用于逐步调试的功能相同,因此这可能也不是您想要的
这是可以做到的,但这就像把眼镜钉在墙上,以确保你永远不会忘记它们在哪里
一些更实际的方法:
对于像您提到的那些内置程序,您始终可以通过显式编写
\uu内置程序\uuu.set
等来访问它们。对于导入的东西,导入模块并根据它们的模块名调用它们(例如sys.exit()
,而不是exit()
)。通常情况下,我们知道什么时候要使用标识符,所以不要覆盖它。G如果要创建set
对象,请不要创建名为set
的变量。正如其他人所说,Python的理念是允许用户“误用”东西,而不是试图想象和防止误用,所以没有类似的东西是内置的。但是,由于Python如此开放,它允许您以有限的方式实现类似于您所说的内容。您可以用对象替换某些变量名称空间字典,以防止您喜欢的变量被覆盖。(当然,如果这以意外的方式破坏了您的任何代码,那么您将获得这两部分。)
为此,您需要使用、或或重写之类的内容。这些允许您提供像字典一样的对象,用于存储变量。我们可以通过子类化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)
>>> 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
将my_globals
设置为当前名称空间,设置如下变量:
x = 3
将转换为以下内容:
my_globals['x'] = 3
以下代码将使用我们针对顶级命名空间的更安全字典执行Python文件:
execfile('safetyfirst.py', SafeGlobals(__builtins__=__builtins__))
带有code.interact()
的示例:
你不能。您可以使用linter(例如,
pylint
)来检查这类东西,但是Python允许您重用除a或None
之外的任何东西。FWIW,一个好的IDE会向您指出这些东西。你不能阻止它,Python是建立在“我们都是同意的成年人”的概念上的,所以你可以自由地做你想做的事。这是可能的,但您必须知道,您首先隐藏了该函数。当然,分叉Python并编写一个不允许您使用内置函数作为变量名的实现。没有那么多需要担心的。是的,可以通过\uuuu内置\uuuuu.set
访问,当然,除非之前有人给\uuuuuu内置\uuuuuuu
分配了其他内容(但更糟糕的是,到那时你也会隐藏集
)。python中似乎没有神圣的标识符。@skyking在分配给set
时似乎相对合理,以防有人不知道set
已经是一个使用过的标识符,分配给\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。也就是说,x=3
的行为可能不同于locals()['x']=3
@skyking感谢您指出这一点。重写以删除它,因为它没有必要工作;需要做的是,当设置名称空间字典时,设置变量将通过该字典。
>>> 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
>>> def f():
... set = 1
... return set
...
>>> f()
1