为什么 Python 不是 lexical scoping?

php中文网
发布: 2016-06-06 16:23:05
原创
1351人浏览过

这似乎背离了现代程序设计语言的一般设计思路。

比如

<span class="k">def</span> <span class="nf">foo</span><span class="p">():</span>
    <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="k">def</span> <span class="nf">inner</span><span class="p">():</span>
        <span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="n">x</span> <span class="o">=</span> <span class="mi">3</span>
    <span class="k">print</span> <span class="n">inner</span><span class="p">()</span>
登录后复制

回复内容:

这段代码是lexical scoping,静态作用域是指我们可以根据代码文本的位置,确定变量的存在区域。

按照python的LEGB(Local,Enclosing,Global,Built-in)规则,当调用inner()时,x实际上是在foo的scope中找到的。inner之所能够访问foo中的x,是因为inner is inside the text of foo,这正是lexical的含义
为什么 Python 不是 lexical scoping?
Bash是Dynamic Scoping的
<code class="bash"><span class="nv">x</span><span class="o">=</span><span class="m">1</span>                                                                                                 
<span class="k">function</span> g <span class="o">()</span> <span class="o">{</span> <span class="nb">echo</span> <span class="nv">$x</span> <span class="p">;</span> <span class="nv">x</span><span class="o">=</span><span class="m">2</span> <span class="p">;</span> <span class="o">}</span> 
<span class="k">function</span> f <span class="o">()</span> <span class="o">{</span> <span class="nb">local </span><span class="nv">x</span><span class="o">=</span><span class="m">3</span> <span class="p">;</span> g <span class="p">;</span> <span class="o">}</span> 
f  <span class="c">#f中的g执行时打印出的x是3而不是1</span>
<span class="nb">echo</span> <span class="nv">$x</span>  <span class="c">#这时打印出的x是1</span>
</code>
登录后复制
你以为Python是

<code class="ocaml"><span class="k">let</span> <span class="n">foo</span> <span class="bp">()</span> <span class="o">=</span>
  <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">in</span>
    <span class="k">let</span> <span class="n">inner</span> <span class="bp">()</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">in</span>
      <span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">3</span> <span class="k">in</span>
        <span class="n">print</span> <span class="o">(</span><span class="n">inner</span> <span class="bp">()</span><span class="o">)</span>
</code>
登录后复制
python的闭包里的自由变量是按引用传递的,而不是按值传递,所以会有这个结果。
这和scoping没有关系。
C++的lambda就可以选择capture by copy或者capture by reference. 根据之前阅读Python源码的经验(如果记错请指正),在题主的例子里面,这个inner是一个闭包。闭包在Python里面的实现方式是保存一个通往外部namespace的指针(可以理解成一个dictionary)。

楼主可以参看这个例子
<code class="python"><span class="k">def</span> <span class="nf">foo</span><span class="p">():</span>
	<span class="k">def</span> <span class="nf">inner</span><span class="p">():</span>
		<span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
	<span class="n">x</span> <span class="o">=</span> <span class="mi">1</span>
	<span class="k">print</span> <span class="n">inner</span><span class="p">()</span> <span class="c"># output 2</span>
	<span class="n">x</span> <span class="o">=</span> <span class="mi">2</span>
	<span class="k">print</span> <span class="n">inner</span><span class="p">()</span> <span class="c"># output 3</span>
</code>
登录后复制

这分明就是lexical scoping嘛,譬如说等价的c#代码

PHP开发实用指南 2.0
PHP开发实用指南 2.0

对于一个刚进入PHP 开发大门的程序员,最需要的就是一本实用的开发参考书,而不仅仅是各种快速入门的only hello wold。在开发的时候,也要注意到许多技巧和一些“潜规则”。PHP是一门很简单的脚本语言,但是用好它,也要下功夫的。同时,由于PHP 的特性,我一再强调,最NB 的PHP 程序员都不是搞PHP 的。为什么呢?因为PHP 作为一种胶水语言,用于粘合后端 数据库和前端页面,更多需

PHP开发实用指南 2.0 387
查看详情 PHP开发实用指南 2.0

<code class="csharp"><span class="k">void</span> <span class="nf">Foo</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">x</span><span class="p">=</span><span class="m">1</span><span class="p">;</span>
    <span class="n">Func</span><span class="p"><</span><span class="kt">int</span><span class="p">></span> <span class="n">inner</span> <span class="p">=</span> <span class="p">()=></span><span class="n">x</span><span class="p">+</span><span class="m">1</span><span class="p">;</span>
    <span class="n">x</span><span class="p">=</span><span class="m">3</span><span class="p">;</span>
    <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">inner</span><span class="p">());</span>
<span class="p">}</span>
</code>
登录后复制
把楼主的代码改写成 lua 可以看看 Python 和 Lua 在处理上的不同:

第一个例子结果都是一样的,因为变量绑定的是引用而不是值。第二个例子:

<code class="lua"><span class="k">function</span> <span class="nf">foo</span><span class="p">()</span>
	<span class="k">function</span> <span class="nf">inner</span><span class="p">()</span>
		<span class="k">return</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span>
	<span class="k">end</span>
	<span class="kd">local</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">3</span>
	<span class="nb">print</span><span class="p">(</span><span class="n">inner</span><span class="p">())</span>
<span class="k">end</span>

<span class="n">foo</span><span class="p">()</span>
</code>
登录后复制
题主所说的 现代化的编程语言指的是什么? js经过这么多代的更新迭代,现在也是这样~

<code class="js"><span class="p">(</span><span class="kd">function</span> <span class="nx">foo</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">function</span> <span class="nx">inner</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">return</span> <span class="nx">x</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="nx">x</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">inner</span><span class="p">());</span>
<span class="p">})();</span>
</code>
登录后复制
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
<span class="n">foo</span><span class="p">()</span>  
<span class="c"># 输出4</span>
登录后复制
我觉得完全没有背离啊。。
输出感觉当前 x 走的 這個問題很好回答:x是inner函數的環境變量,所以在inner的定義中出現的x其實就是對定義外面的,也就是inner的環境變量的一個引用而已。

函數只有在被調用的時候才會執行,你前面將置為1,後面又改為3,不過是改變了x的引用值而已,相當於給x重新賦值。然後執行inner函數,使用x所對應的值為3,因此答案就是4了。
python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号