比如:
def foo():
a = 10
def foo2():
a = 20
回复内容:
这不是王垠说的么,王垠专业就是研究编程语言。研究语言的博士生针对各种语言特性做的分析,对我们都是有很多启发的。但你说的这种外面有个a,函数里面又有个a的情况,我想问问,其实实际开发中,是不是每天都要处理内外层变量名字冲突的问题?我们有两种选择:一种做法是象王垠说的:区别变量声明和赋值,就是类似声明时前面加个 var一样,另外的做法象龟多做的:没有 var,只有在冲突的时候加一些 global nolocal之类的关键字。哪种做法好,请你想想大多数情况下,99%的时候你是不会傻到内外用一样的名字的吧,好的编程习惯甚至全局变量和局部变量在命名上都是区别的,不会出现你说的冲突。系统设计就是需要不断的做出选择,龟多也一样做出了他的选择,让你 99%的情况下都不需要为每个变量去写一个 var声明去,以此保证语言的简洁性和优雅性。直到你碰到 1%的极端的情况时,用一下 nolocal global又有什么困难的呢?然而这些对用户优雅的特性,对于写 pysonar的王垠来讲,却无外乎一种折磨,要在静态分析中间指出他们的区别来是很痛苦的,这是肯定的事情,层次越高级的语言越不容易做静态分析,所以王垠被恶心到了,狂喷 global nolocal也是可以理解的。所以别人云亦云,多想想说这些话是在什么背景下说出来的,这些客观条件和自己所处的情况相同否,再做出自己的判断。——————
补充一个目前大家都没有提到的方面。题主,先不论是不是python 的设计缺陷,你通过以上例子得出的那个结论,是存在以偏概全的问题的。题主的例子表达的观点实际上为:python中,在没有声明的情况下,子函数中的同名变量无法改变外围同名变量。不过,这种网上广为流传的说法是错误的。几行代码可以说明这个问题:
def foo():
a_int=10
a_list_with_method=[0,1,10]
def foo2():
a_int=20
a_list_with_method.append(11)
foo2()
print(a_int) #python2.x 请用print a_int
print(a_list_with_method) #python2.x 请用print a_list_with_method
foo()
首先,不要求完全精确的情况下,python 其实可以说是“没有变量”,有的只是“名字绑定”,每一个名字可以视为一个实例(instance)的引用,变量只是大家沿用了更熟悉的概念而已。也就是说,`a = 20` 这句代码里,`a` 只是一个名字(引用)。然后,回到题主的代码,这是一个 python 的名字搜索机制的问题,因为 python2.x 的实现是本地范围找不到的话就去全局范围找,那么就会出现题主说的“在foo2中没有办法改变foo中a的值”的问题,这个问题后来在 python3.x 中通过引入 `nonlocal` 解决了。最后,“python不区分变量定义和赋值,是否是一个设计上的缺陷?”,这是一个伪问题,开篇说过了 python 其实可以说是“没有变量”,所以何来“定义”之说,说到“缺陷”就更是强加的罪名了。
python的closure设计的确是有缺陷的。不只是这个地方,还有引用传参却又没有强制只读。但是,我跟你说,这是个feature,不是缺陷。python设计哲学根本不鼓励你用词法作用域这种花式语法,按照python的逻辑,你应该老老实实用自变量导入所有的参数。那些nonlocal和global都是后门,不推荐使用。所谓的python设计哲学,就是简单直接,遵从感觉,不向硬件妥协,也不向数学屈膝。作用域这种复杂的数学问题,明智的方法是绕开它,不要去思考。写个python还要思考作用域,那跟写c++有什么区别?当然,如果你一定要思考这种问题,c++欢迎你(逃
这个不能算缺陷吧…想实现这种功能应该是有其它的办法来实现的。对于有些语言,比如c来说,函数是不可以嵌套的。我倒是觉得python不区分声明和赋值的话,有些地方变量名拼写错了,运行也可能不报错,然后就出现各种神奇的bug了。
因为python中所有东西都是对象,赋值其实只是引用绑定,所以这个情况某种意义上是必然的。这也与python遵循的基本原则有关。如果遵守简单唯一表示的原则,那么并没有什么不方便的地方;如果说这个原则不好,那也没办法了……
在foo2中没有办法改变foo中a的值,这能否说因为python不区分变量定义和赋值从而导致的一个缺陷?python3引入的nonlocal恰好证明了这一点?我想说的是,你从一个错误的论据导出了一个正确的结论。。python的name rebinding(assign to)机制的确有缺陷,只能rebind到local和module-global,而不能rebind到outer scope。但python是有变量声明的,比如global语句就是用来绑定global变量的,而local声明是隐式的。python 3新加的nonlocal修补了不能绑定到outer scope的问题。pep 3104 — access to names in outer scopes
你确定是设计的缺陷,而不是美德(merit)?
我觉得应该是缺陷吧,考虑如下情形variable = 10bla bla bla…varable = 3//此处由于拼写,少打了个i,认为是新变量variable += 16计算错误
初学python,有几年c++经验,我说几句我理解的。对于任何变量来说,他都应该遵循最小作用域,既然python不区分赋值既创建,那好那我就创建吧!别的我不管,你想用其他作用域的,好吧!你指定吧!至于说为什么赋值既创建,可能是因为python没有强制要求声明数据类型的缘故吧!至于说优化,默认是引用形式,只是内存性能方面的优化吧!