Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何防止意外覆盖Python内置函数?_Python_Python 2.7 - Fatal编程技术网

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

如何防止意外覆盖Python内置函数?,python,python-2.7,Python,Python 2.7,我知道,给一个与Python内置函数同名的变量命名是个坏主意。但是如果一个人不知道所有要避免的“禁忌”变量名(例如列表,集,等等),那么有没有办法让Python至少阻止你(例如通过错误消息)破坏内置函数 例如,下面的命令行4允许我覆盖/损坏内置函数set(),而不会阻止我/产生错误。(在调用set()时,该错误一直未被注意到,直到到达下面的命令行6。)。理想情况下,我希望Python在命令行4停止我(而不是等到命令行6) 注意:以下执行是在Python2.7(iPython)控制台中执行的。(水

我知道,给一个与Python内置函数同名的变量命名是个坏主意。但是如果一个人不知道所有要避免的“禁忌”变量名(例如
列表
,等等),那么有没有办法让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