这两个Python语句有什么不同?

5
我正在深入研究Python的WiringPi-Python代码,发现有几个类似于这样的代码块:
def wiringPiSetup():
  return _wiringpi2.wiringPiSetup()
wiringPiSetup = _wiringpi2.wiringPiSetup

对我来说有些困惑,因为我认为这个:

def wiringPiSetup():
  return _wiringpi2.wiringPiSetup()

将产生与此完全相同的结果:

wiringPiSetup = _wiringpi2.wiringPiSetup

我知道第一个是声明一个新的函数,而第二个是对原始函数的引用,但在我的测试中,我发现它们完全等效。看这里:

>>> def a():
...     return 4
... 
>>> def a1():
...     return a()
... 
>>> a2 = a
>>> 
>>> a1()
4
>>> a2()
4

所以,为什么WiringPi-Python会把两者都放入,而任何一个都足够呢?
顺便提一句: - 我使用的是Python 2.7.3 - 这是我看到这个文件的地方: here

3
嗯?好问题,我毫无头绪他们为什么要那样做。 - Martijn Pieters
尝试移除其中一个选项。这会导致任何问题吗? - mpenkov
4
我注意到的第一件事是,“此文件由swig自动生成”,这可能解释了这个看似毫无意义的声明。我从未使用过SWIG,也不知道为什么它会生成那样的代码。 - Two-Bit Alchemist
如果以后有人做了这样的事情:_wiringpi2.wiringPiSetup = newfunc,会发生什么呢?如果你调用 wiringPiSetup 函数版本,你可能会得到不同的结果。 - acushner
@acushner 在Python中,赋值操作基本上只是改变事物的名称。你的第一个例子将会把 _wiringpi2.wiringPiSetup 重命名为 newfunc 并执行 newfunc 的任何操作。如果你仍然有一个名称指向 wiringPiSetup 的原始定义,它将表现出原始的行为。 - Two-Bit Alchemist
是的,这就是我想要表达的。如果你将对 _wiringpi2.wiringPiSetup 的访问封装在一个函数调用中,你将得到最近分配的行为,而如果你使用从文件导入时的直接赋值,它可能会不同。 - acushner
2个回答

3
这个文件是由SWIG生成的。函数定义实际上是“死代码”,也就是说您可以完全删除函数定义,只保留赋值即可。
由于代码是自动生成的,因此代码效率有些低下。生成此代码的SWIG函数指出:
if (Getattr(n, "feature:python:callback") || !have_addtofunc(n)) {
  /* If there is no addtofunc directive then just assign from the extension module (for speed up) */
  Printv(f_dest, name, " = ", module, ".", name, "\n", NIL);
}

因此,第二个任务是将生成的Python函数替换为更快的使用方式。

如果在生成时有额外的Python代码要添加(当存在文档字符串、前置或后置值时 have_addtofunc() 为真),则不会生成替换行。

原始函数可能保留在原处,以便自动完成工具可以利用函数签名。


回答这个问题需要3秒钟的时间差。 - vz0
很好的研究,你们俩! - Two-Bit Alchemist
谢谢,看起来这是正确的。不过我还想知道是否只有这个原因才让那段死代码留在那里。 - Daniel
@DWilches:看起来这个更改是故意的;以前它只是不生成函数。这是一个从SVN转换到Git的提交,因此该分支的原始分支和提交无法(轻松地)检索到。 - Martijn Pieters

1
这个文件是由SWIG生成的。从阅读SWIG Python generator soure code (emitFunctionShadowHelper)来看,代码生成器会为被包装的函数创建一个包装器函数,如果这个函数有一些文档字符串,但是如果函数没有任何文档字符串,那么代码生成器就会发出一个简单的赋值语句。似乎可以在该函数中添加一个"else"子句。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接