为什么 Python 不是 lexical scoping?
这似乎背离了现代程序设计语言的一般设计思路。
比如
<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的含义。

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>
<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>
这和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>
第一个例子结果都是一样的,因为变量绑定的是引用而不是值。第二个例子:
<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>
<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了。

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Die Verwendung von return in der C-Sprache ist: 1. Für Funktionen, deren Rückgabewerttyp ungültig ist, können Sie die Rückgabeanweisung verwenden, um die Ausführung der Funktion vorzeitig zu beenden. 2. Für Funktionen, deren Rückgabewerttyp nicht ungültig ist, ist die Funktion von Die Return-Anweisung dient dazu, die Ausführung der Funktion zu beenden. 3. Beenden Sie die Ausführung der Funktion vorzeitig wenn die Funktion keinen Wert zurückgibt.

Quellcode: publicclassReturnFinallyDemo{publicstaticvoidmain(String[]args){System.out.println(case1());}publicstaticintcase1(){intx;try{x=1;returnx;}finally{x=3;}}}# Ausgabe Die Ausgabe des obigen Codes kann einfach zu dem Schluss kommen: return wird ausgeführt, bevor wir uns schließlich ansehen, was auf der Bytecode-Ebene passiert. Im Folgenden wird ein Teil des Bytecodes der Methode case1 abgefangen und mit dem Quellcode verglichen, um die Bedeutung jeder Anweisung darin zu kommentieren

Vue3.2-Setup-Syntaxzucker ist ein Syntaxzucker zur Kompilierungszeit, der die kombinierte API in einer einzelnen Dateikomponente (SFC) verwendet, um das umständliche Setup in Vue3.0 zu lösen. Die durch den Import eingeführten deklarierten Variablen, Funktionen und Inhalte werden bereitgestellt Rückkehr, damit sie in Vue3.0 verwendet werden können. 1. Es besteht keine Notwendigkeit, deklarierte Variablen, Funktionen und Inhalte zurückzugeben, die durch Import während der Verwendung eingeführt wurden }from'./utils'//variable constmsg='Hello !'//function func

Für die Verwendung von „return“ in JavaScript sind bestimmte Codebeispiele erforderlich. In JavaScript wird die „return“-Anweisung verwendet, um den von einer Funktion zurückgegebenen Wert anzugeben. Es kann nicht nur dazu verwendet werden, die Ausführung einer Funktion zu beenden, sondern auch einen Wert an die Stelle zurückzugeben, an der die Funktion aufgerufen wurde. Die Return-Anweisung hat die folgenden allgemeinen Verwendungszwecke: Einen Wert zurückgeben Die Return-Anweisung kann verwendet werden, um einen Wert an die Stelle zurückzugeben, an der die Funktion aufgerufen wird. Hier ist ein einfaches Beispiel: functionadd(a,b){

JavaScript-Funktionen stellen zwei Schnittstellen zur Interaktion mit der Außenwelt bereit. Die Parameter dienen als Eingang zum Empfang externer Informationen; der Rückgabewert dient als Ausgang für die Rückmeldung der Operationsergebnisse an die Außenwelt. Der folgende Artikel wird Ihnen helfen, den Rückgabewert der JavaScript-Funktion zu verstehen und die Verwendung der Rückgabeanweisung kurz zu analysieren. Ich hoffe, er wird Ihnen hilfreich sein!

Für die Verwendung von return in JavaScript sind bestimmte Codebeispiele erforderlich. In JavaScript ist return ein sehr wichtiges Schlüsselwort. Es wird normalerweise verwendet, um einen Wert in einer Funktion zurückzugeben oder die Ausführung einer Funktion zu beenden. Die Return-Anweisung wird verwendet, um einen Wert an den Aufrufer der Funktion zurückzugeben und die Ausführung der Funktion zu beenden. Die return-Anweisung kann überall in einer Funktion verwendet werden und jeden JavaScript-Datentyp zurückgeben, einschließlich Zahlen, Zeichenfolgen, booleschen Werten,

Bei der Rückgabe des Python-Rückgabewerts wird die Ausführung sofort gestoppt, wenn die Funktion die Rückgabeanweisung ausführt, und der angegebene Wert wird an die Stelle zurückgegeben, an der die Funktion aufgerufen wurde. Detaillierte Verwendung: 1. Einen einzelnen Wert zurückgeben; 2. Einen Nullwert zurückgeben; 4. Die Ausführung der Funktion vorzeitig beenden;

Die Druckbildschirmtaste befindet sich auf den Pfeiltasten des Tastaturgeräts mit der Aufschrift „prtsc sysrq“ und befindet sich rechts von f12. Wenn es keine Schaltfläche mit dem Wort „prtsc sysrq“ gibt, können Sie „fn“ und „insert(prt sc)“ finden. Klicken Sie zuerst auf „fn“ und dann auf „insert(PRT sc)“, um die Druckbildschirm-Screenshot-Funktion zu realisieren .
