亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

松散后期綁定與嚴格后期綁定

松散后期綁定與嚴格后期綁定

白豬掌柜的 2023-05-09 14:44:51
在閱讀 Python 的執行模型文檔時,我意識到 Python 的自由變量似乎沒有嚴格的后期綁定屬性,即任何代碼塊中出現的名稱綁定都可以用于名稱解析。確實,執行:def f():    return xdef g():    x = 0    return f()print(g())提出:NameError: name 'x' is not defined它們具有松散的后期綁定屬性,其中只有出現在引入自由變量的代碼塊的外部代碼塊中的名稱綁定才能用于名稱解析。確實在執行def f():    return xx = 0print(f())印刷:0與嚴格的后期綁定屬性相比,松散的后期綁定屬性有哪些優點和缺點?
查看完整描述

2 回答

?
慕標5832272

TA貢獻1966條經驗 獲得超4個贊

這通常稱為動態作用域和靜態作用域。粗略地說,動態作用域通過調用嵌套確定作用域,靜態作用域通過聲明嵌套確定作用域。


一般來說,對于任何具有調用堆棧的語言來說,動態作用域很容易實現——名稱查找只是線性地搜索當前堆棧。相比之下,靜態范圍更復雜,需要幾個不同的范圍和自己的生命周期。


然而,靜態作用域通常更容易理解,因為變量的作用域永遠不會改變——名稱查找必須解析一次并且將始終指向相同的作用域。相比之下,動態作用域更脆弱,在調用函數時名稱在不同的作用域或沒有作用域被解析。


Python 的作用域規則主要由引入嵌套作用域(“閉包”)的PEP 227和引入可寫嵌套作用域(“閉包”)的PEP 3104nonlocal定義。這種靜態作用域的主要用例是允許高階函數(“函數生成函數”)自動參數化內部函數;這通常用于回調、裝飾器或工廠函數。


def adder(base=0):  # factory function returns a new, parameterised function

    def add(x):

        return base + x  # inner function is implicitly parameterised by base

    return add

兩個 PEP 都將 Python 如何處理靜態作用域的復雜性編纂成文。具體來說,范圍在編譯時解析一次——此后每個名稱都嚴格地是全局的、非本地的或本地的。作為回報,靜態作用域允許優化變量訪問——從快速的局部數組、閉包單元的間接數組或慢速全局字典中讀取變量。


這種靜態作用域的名稱解析的人工制品是UnboundLocalError :名稱可能在本地作用域但尚未在本地分配。即使在某處為名稱分配了一些值,靜態作用域也禁止訪問它。


>>> some_name = 42

>>> def ask():

...     print("the answer is", some_name)

...     some_name = 13

...

>>> ask()

UnboundLocalError: local variable 'some_name' referenced before assignment

存在各種方法來規避這一點,但它們都歸結為程序員必須明確定義如何解析名稱。


雖然 Python 本身并不實現動態作用域,但它可以很容易地被模擬。由于動態作用域與每個調用堆棧的作用域堆棧相同,因此可以顯式實現。


Python 本機提供了threading.local將變量上下文化到每個調用堆棧的功能。類似地,contextvars允許明確地將變量置于上下文中——這對于例如async回避常規調用堆棧的代碼很有用。線程的原始動態范圍可以構建為線程本地的文字范圍堆棧:


import contextlib

import threading



class DynamicScope(threading.local):  # instance data is local to each thread

    """Dynamic scope that supports assignment via a context manager"""

    def __init__(self):

        super().__setattr__('_scopes', [])  # keep stack of scopes


    @contextlib.contextmanager  # a context enforces pairs of set/unset operations

    def assign(self, **names):

        self._scopes.append(names)  # push new assignments to stack

        yield self                  # suspend to allow calling other functions

        self._scopes.pop()          # clear new assignments from stack


    def __getattr__(self, item):

        for sub_scope in reversed(self._scopes):  # linearly search through scopes

            try:

                return sub_scope[item]

            except KeyError:

                pass

        raise NameError(f"name {item!r} not dynamically defined")


    def __setattr__(self, key, value):

        raise TypeError(f'{self.__class__.__name__!r} does not support assignment')

assign這允許全局定義一個動態范圍,可以在有限的時間內將名稱編輯到該范圍。分配的名稱在被調用的函數中自動可見。


scope = DynamicScope()


def print_answer():

    print(scope.answer)  # read from scope and hope something is assigned


def guess_answer():

    # assign to scope before calling function that uses the scope

    with scope.assign(answer=42):

        print_answer()


with scope.assign(answer=13):

    print_answer()  # 13

    guess_answer()  # 42

    print_answer()  # 13

print_answer()      # NameError: name 'answer' not dynamically defined


查看完整回答
反對 回復 2023-05-09
?
江戶川亂折騰

TA貢獻1851條經驗 獲得超5個贊

靜態(早期)和動態(晚期)綁定:

綁定是指將程序文本中的名稱與它們所指的存儲位置相關聯。在靜態綁定中,這種關聯是在構建時預先確定的。使用動態綁定,此關聯直到運行時才確定。

動態綁定是發生在 Python 中的綁定。這意味著 Python 解釋器僅在代碼運行時才進行綁定。例如 -

>>> if False:
...     x  # This line never runs, so no error is raised
... else:
...     1 + 2
...3>>>

動態綁定的優點

  • 動態類型綁定的主要優點是靈活性。編寫通用代碼更容易。

    • Ex - 使用動態類型綁定的語言處理數據列表的程序可以編寫為通用程序。

動態綁定的缺點

  • 編譯器的錯誤檢測能力減弱。編譯器可能捕獲的一些錯誤。

  • 運行時的相當大的開銷。


查看完整回答
反對 回復 2023-05-09
  • 2 回答
  • 0 關注
  • 150 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號