目次
回复内容:
ホームページ バックエンド開発 Python チュートリアル 为什么 Python 不是 lexical scoping?

为什么 Python 不是 lexical scoping?

Jun 06, 2016 pm 04:23 PM
def print return

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

比如

<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的
<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>
ログイン後にコピー
你以为Python是

<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>
ログイン後にコピー
python的闭包里的自由变量是按引用传递的,而不是按值传递,所以会有这个结果。
这和scoping没有关系。
C++的lambda就可以选择capture by copy或者capture by reference. 根据之前阅读Python源码的经验(如果记错请指正),在题主的例子里面,这个inner是一个闭包。闭包在Python里面的实现方式是保存一个通往外部namespace的指针(可以理解成一个dictionary)。

楼主可以参看这个例子
<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>
ログイン後にコピー

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


<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>
ログイン後にコピー
把楼主的代码改写成 lua 可以看看 Python 和 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>
ログイン後にコピー
题主所说的 现代化的编程语言指的是什么? 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>
ログイン後にコピー
<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>
foo()  
# 输出4
ログイン後にコピー
我觉得完全没有背离啊。。
输出感觉当前 x 走的 這個問題很好回答:x是inner函數的環境變量,所以在inner的定義中出現的x其實就是對定義外面的,也就是inner的環境變量的一個引用而已。

函數只有在被調用的時候才會執行,你前面將置為1,後面又改為3,不過是改變了x的引用值而已,相當於給x重新賦值。然後執行inner函數,使用x所對應的值為3,因此答案就是4了。
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C言語のreturnの使い方を詳しく解説 C言語のreturnの使い方を詳しく解説 Oct 07, 2023 am 10:58 AM

C 言語における return の使い方は、 1. 戻り値の型が void の関数については、return 文を使用して関数の実行を早期に終了することができます; 2. 戻り値の型が void ではない関数については、 return ステートメントは、関数の実行を終了するためのものです。結果は呼び出し元に返されます。 3. 関数の実行を早期に終了します。関数内で return ステートメントを使用して、関数の実行を早期に終了することもできます。関数が値を返さない場合。

Javaのreturn文とfinally文の実行順序は何ですか? Javaのreturn文とfinally文の実行順序は何ですか? Apr 25, 2023 pm 07:55 PM

ソースコード: publicclassReturnFinallyDemo{publicstaticvoidmain(String[]args){System.out.println(case1());}publicstaticintcase1(){intx;try{x=1;returnx;}finally{x=3;}}}#出力 上記のコードの出力は、単純に次のように結論付けることができます:finally の前に return が実行されます。バイトコード レベルで何が起こるかを見てみましょう。以下は、case1 メソッドのバイトコードの一部をインターセプトし、ソース コードを比較して、各命令の意味に注釈を付けます。

Vue3 はセットアップ構文シュガーをどのように使用して return の書き込みを拒否しますか Vue3 はセットアップ構文シュガーをどのように使用して return の書き込みを拒否しますか May 12, 2023 pm 06:34 PM

Vue3.2 セットアップ構文シュガーは、単一ファイル コンポーネント (SFC) で結合された API を使用して、Vue3.0 の面倒なセットアップを解決するコンパイル時構文シュガーです。宣言された変数、関数、インポートによって導入されたコンテンツは、インポートによって公開されます。使用上の問題点 1. 宣言した変数、関数、import で導入した内容を使用中に return する必要はなく、糖衣構文を使用することができます。 // 導入した内容をインポート import{getToday }from'./utils'//variable constmsg='Hello !'//function func

JavaScript関数の戻り値とreturn文の詳しい解説 JavaScript関数の戻り値とreturn文の詳しい解説 Aug 04, 2022 am 09:46 AM

JavaScript 関数は、外部と対話するための 2 つのインターフェースを提供し、パラメータは外部情報を受け取る入り口として機能し、戻り値は演算結果を外部にフィードバックする出口として機能します。次の記事では、JavaScript 関数の戻り値を理解し、return ステートメントの使用法を簡単に分析します。

JavaScript で return キーワードを使用する JavaScript で return キーワードを使用する Feb 18, 2024 pm 12:45 PM

JavaScript での return の使用には特定のコード例が必要です。 JavaScript では、return ステートメントを使用して関数から返される値を指定します。関数の実行を終了するために使用できるだけでなく、関数が呼び出された場所に値を返すこともできます。 return ステートメントには次の一般的な用途があります。 値を返す return ステートメントは、関数が呼び出された場所に値を返すために使用できます。簡単な例を次に示します。 functionadd(a,b){

Pythonで戻り値を使う方法 Pythonで戻り値を使う方法 Oct 07, 2023 am 11:10 AM

Python の戻り値 return の使い方は、関数が return ステートメントを実行すると、実行が直ちに停止され、関数が呼び出された場所に指定された値が返されます。詳細な使用法: 1. 単一の値を返す; 2. 複数の値を返す; 3. null 値を返す; 4. 関数の実行を早期に終了する。

JavaScriptでのreturn文の使い方 JavaScriptでのreturn文の使い方 Feb 26, 2024 am 09:21 AM

JavaScript で return を使用する方法には、具体的なコード例が必要です。JavaScript では、return は非常に重要なキーワードです。通常、関数の値を返すか、関数の実行を終了するために使用されます。 return ステートメントは、関数の呼び出し元に値を返し、関数の実行を終了するために使用されます。 return ステートメントは関数内のどこでも使用でき、数値、文字列、ブール値などの任意の JavaScript データ型を返すことができます。

キーボードのどこに印字があるのでしょうか? キーボードのどこに印字があるのでしょうか? Jun 19, 2023 am 09:37 AM

プリント スクリーン キーはキーボード デバイスの矢印キー上にあり、「prtsc sysrq」という文字が表示され、f12 の右側にあります。 「prtsc sysrq」という単語が含まれるボタンがない場合は、「fn」と「insert(prt sc)」を見つけて、最初に「fn」をクリックし、次に「insert(PRT sc)」をクリックすると、プリントスクリーンのスクリーンショット機能が実現されます。 。

See all articles