ホームページ バックエンド開発 Python チュートリアル Python と Lua のデフォルトのスコープとクロージャ

Python と Lua のデフォルトのスコープとクロージャ

Oct 19, 2016 pm 01:34 PM

デフォルトのスコープ

私は少し前に Lua を学びましたが、Lua のデフォルトのスコープが Python のデフォルトのスコープとは逆であることがわかりました。 Lua が変数を定義する場合、変数のデフォルトのスコープはグローバルです。これはあまり正確ではありません。Lua が x = 1 のようなステートメントを実行する場合、現在の環境から開始して x レイヤーを検索します。 find x グローバル変数は特定の状況下でのみ定義されます)、Python が変数を定義する場合、変数のスコープはデフォルトでローカル (現在のブロック) になります。さらに、Lua では変数を定義するときに変数の前に local キーワードを追加することでローカル変数を定義できますが、Python には同様のキーワードがなく、Python 変数は現在のブロックでのみ定義できます。

グローバル変数は良くないことはわかっていますが、ローカル変数は良いものです。プログラムを作成するときは、ローカル変数を使用するようにしてください。そのため、最初は Python の規則の方が優れていると考えていました。その利点は、入力が少なくて済むことです。 Lua プログラムを書くとき、私は心の中で「ローカルを忘れるな、ローカルを忘れるな」と言い続けていますが、時々、いくつかのことがネットをすり抜けて魔法のバグを引き起こすことがあります。

クロージャー

Python のデフォルトのスコープの問題に初めて気づいたのは、クロージャーを使用するときでした。クロージャに関しては、Lua チュートリアルに次のコードがあります:

function new_counter()
  local n = 0
  local function counter()
    n = n + 1
    return n
  end
  return counter
end
   
c1 = new_counter()
c2 = new_counter()
print(c1())  -- 打印1
print(c2())  -- 打印1
print(c1())  -- 打印2
print(c2())  -- 打印2
ログイン後にコピー

クロージャの本質は、SICP の第 3 章の環境モデルを参照できます。ここでは、関数カウンターにプライベート メンバー n があると簡単に想像できます。

ここで質問が来ます: Python を使用して、同じ関数を持つクロージャを実装したいのですが?

まず、Lua コードを Python コードに直接書き換えます:

def new_counter():
  n = 0
  def counter():
    n = n + 1
    return n
  return counter
ログイン後にコピー

その後、私は唖然としました。このプログラムは実行できず、未割り当ての変数 n が 4 行目でアクセスされます。エラーの理由は、Python がクロージャをサポートしていないためではなく、Python の代入操作が上位レベルの変数 n にアクセスできないことです (実際、Python はそれを代入ではなくローカル変数の定義であるとみなします。ローカル変数の定義とPython での代入操作は構文的に矛盾しているため、Python は単に再定義可能な定義ステートメントのみをサポートしています)。 Python のデフォルトのスコープはローカルであるため、プログラムが n = n + 1 まで実行されると、Python はこれが変数定義操作であると判断し、(初期化されていない) ローカル変数 n を作成し、このレベルで new_counter n を正常に上書きしてから試行します。 n + 1 を n に代入しようとしましたが、n が初期化されていないため、n + 1 を計算できないため、プログラムはエラーを報告します。


クロージャ代入の関数を実装するには、ちょっとしたトリックを使うことができます:

def new_counter():
  n = [0]
  def counter():
    n[0] = n[0] + 1
    return n[0]
  return counter
ログイン後にコピー

n[0] = n[0] + 1 が間違っていない理由は、ここに等号があるためです。とその前の n = n + 1 の等号は意味が異なります。 n[0] = n[0] + 1 の等号は、n の属性を変更することを意味します。実際、この等号は最終的に list の __setitem__ メソッドを呼び出します。 n = n + 1 の等号は、値 n + 1 を現在の環境のシンボル n にバインドすることを意味します (シンボル n が現在の環境にすでに存在する場合は、それを上書きします)。

もう一つの余談: くそー、こんなふうに書く必要はない、とても醜い。とにかく、Python はオブジェクト指向言語です。カウンターを実装するには、クラスを作成する必要があります。

定義と代入の分離

まず、Python と Lua のデフォルト スコープの特徴をまとめてみましょう:

プログラムを作成するときは、ローカル キーワードを覚えておいてください (本当に定義したい場合を除く)。グローバル変数)、誤ってローカルを忘れた場合、プロンプトは表示されず、バグが修正されるまで待ちます。

2. Python のデフォルトのスコープはローカルです。プログラムを書く際の精神的な負担は少なくなりますが、上位レベルの変数に値を代入する機能が失われます (変更は可能ですが、言語がより複雑になります)。 。

両方のデフォルトのスコープに問題があるようですね?個人的には、上記の問題の原因は、Python と Lua が定義と代入の分離を認識していないことにあると考えています。 Python と Lua では、x = 1 のようなステートメントは定義または代入を表すことができます。実際、これら 2 つの言語に限らず、多くの高級言語は定義と代入の分離を実現していません。定義と代入は機能的には似ていますが、本質的には異なります。

以下では、例として x = 1 を使用して定義と代入を説明します:

定義とは、シンボル x を現在の環境に登録し、1 に初期化することを意味します。 x がすでに存在する場合、エラーが報告される (再定義は許可されない) か、上書きされます (再定義は許可されます)。

代入とは、現在の環境から始めて、シンボル x が初めて見つかるまでレイヤーごとに検索し、その値を 1 に変更することを意味します。見つからない場合は、エラーが報告されます (変数が存在しません)。

ここで、定義と代入を分離するために Python を少し変更します。定義を示すには「:=」を使用し、代入を示すには「=」を使用します。次に、実行できない new_counter サンプルを書き直します (Python の代入操作はローカル変数の定義と競合します。つまり、Python には実際には代入操作がありません。そのため、単純にすべての「=」を「:=」に置き換えるだけで済みます)。 ) 、どこが間違っているかを確認してください:

def new_counter():
  n := 0
  def counter():
    n := n + 1
    return n
  return counter
ログイン後にコピー

なぜこのプログラムが間違っているのかは明らかです。 4 行目で必要なのは、定義操作ではなく代入操作です。これを正しい書き方に変更します:

def new_counter():
  n := 0
  def counter():
    n = n + 1
    return n
  return counter
ログイン後にコピー

このようにすると、正しく実行されます (Python インタープリター XD の修正バージョンがある場合)。

最後に、Lua について話しましょう。 Lua では、定義と割り当ての分離が半分達成されたように感じます。 local キーワードを含む等号ステートメントを定義する必要があります。問題は、ローカルのない等号ステートメントです。この種のステートメントの場合、Lua は次の処理を実行します。まず代入を試み、代入が失敗した (変数が存在しない) 場合は、最も外側の環境 (グローバル環境) で変数を定義します。つまり、ローカルのない等号ステートメントでは、定義と代入が混在します。さらに、定義と割り当ての分離が達成されている場合、デフォルトのスコープの問題を考慮する必要はありません。すべての定義は現在の環境で定義され、すべてローカル変数を定義します。関数本体や他のブロックでグローバル変数を定義するメリットはまったく思いつきません。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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)

LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? Apr 01, 2025 pm 05:09 PM

LinuxターミナルでPythonバージョンを表示する際の許可の問題の解決策PythonターミナルでPythonバージョンを表示しようとするとき、Pythonを入力してください...

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? Apr 01, 2025 pm 11:15 PM

PythonのPandasライブラリを使用する場合、異なる構造を持つ2つのデータフレーム間で列全体をコピーする方法は一般的な問題です。 2つのデータがあるとします...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? 中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

正規表現とは何ですか? 正規表現とは何ですか? Mar 20, 2025 pm 06:25 PM

正規表現は、プログラミングにおけるパターンマッチングとテキスト操作のための強力なツールであり、さまざまなアプリケーションにわたるテキスト処理の効率を高めます。

uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? Apr 01, 2025 pm 10:51 PM

UvicornはどのようにしてHTTPリクエストを継続的に聞きますか? Uvicornは、ASGIに基づく軽量のWebサーバーです。そのコア機能の1つは、HTTPリクエストを聞いて続行することです...

人気のあるPythonライブラリとその用途は何ですか? 人気のあるPythonライブラリとその用途は何ですか? Mar 21, 2025 pm 06:46 PM

この記事では、numpy、pandas、matplotlib、scikit-learn、tensorflow、django、flask、and requestsなどの人気のあるPythonライブラリについて説明し、科学的コンピューティング、データ分析、視覚化、機械学習、Web開発、Hの使用について説明します。

文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? 文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? Apr 01, 2025 pm 11:18 PM

Pythonでは、文字列を介してオブジェクトを動的に作成し、そのメソッドを呼び出す方法は?これは一般的なプログラミング要件です。特に構成または実行する必要がある場合は...

See all articles