Python 晚装订松。严格的后期绑定

Python 晚装订松。严格的后期绑定,python,language-design,late-binding,free-variable,Python,Language Design,Late Binding,Free Variable,在阅读Python的文档时,我意识到Python的自由变量似乎没有严格的后期绑定属性,任何代码块中出现的名称绑定都可以用于名称解析。实际上,执行: def(): 返回x def g(): x=0 返回f() 打印(g()) 提出: NameError: name 'x' is not defined 它们有一个相当松散的后期绑定属性,只有在引入自由变量的代码块的外部代码块中发生的名称绑定才能用于名称解析。确实执行 def(): 返回x x=0 打印(f()) 印刷品: 0 与严格的后期绑

在阅读Python的文档时,我意识到Python的自由变量似乎没有严格的后期绑定属性,任何代码块中出现的名称绑定都可以用于名称解析。实际上,执行:

def():
返回x
def g():
x=0
返回f()
打印(g())
提出:

NameError: name 'x' is not defined
它们有一个相当松散的后期绑定属性,只有在引入自由变量的代码块的外部代码块中发生的名称绑定才能用于名称解析。确实执行

def():
返回x
x=0
打印(f())
印刷品:

0
与严格的后期绑定属性相比,松散的后期绑定属性有哪些优点和缺点?

静态(早期)和动态(后期)绑定:

绑定是指程序文本中的名称与它们所引用的存储位置之间的关联。在静态绑定中,此关联是在构建时预先确定的。对于动态绑定,只有在运行时才能确定此关联

动态绑定是Python中发生的绑定。这意味着Python解释器仅在代码运行时进行绑定。比如说-

>>> if False:
...     x  # This line never runs, so no error is raised
... else:
...     1 + 2
...
3
>>>
动态绑定的优势

  • 动态类型绑定的主要优点是灵活性。编写泛型代码更容易。
    • 使用动态类型绑定的语言处理数据列表的程序可以编写为通用程序
动态绑定的缺点

  • 编译器的错误检测能力减弱。编译器可能捕获的一些错误
  • 在运行时有相当大的开销
静态(早期)和动态(后期)绑定:

绑定是指程序文本中的名称与它们所引用的存储位置之间的关联。在静态绑定中,此关联是在构建时预先确定的。对于动态绑定,只有在运行时才能确定此关联

动态绑定是Python中发生的绑定。这意味着Python解释器仅在代码运行时进行绑定。比如说-

>>> if False:
...     x  # This line never runs, so no error is raised
... else:
...     1 + 2
...
3
>>>
动态绑定的优势

  • 动态类型绑定的主要优点是灵活性。编写泛型代码更容易。
    • 使用动态类型绑定的语言处理数据列表的程序可以编写为通用程序
动态绑定的缺点

  • 编译器的错误检测能力减弱。编译器可能捕获的一些错误
  • 在运行时有相当大的开销

    • 这通常被称为。粗略地说,动态作用域通过调用嵌套确定作用域,静态作用域通过声明嵌套确定作用域

      一般来说,对于任何具有调用堆栈的语言,动态范围非常容易实现–名称查找只是线性搜索当前堆栈。相比之下,静态作用域更为复杂,需要几个不同的作用域,它们有自己的生命周期

      然而,静态作用域通常更容易理解,因为变量的作用域永远不会改变——名称查找必须解决一次,并且始终指向相同的作用域。相比之下,动态作用域更为脆弱,调用函数时,名称在不同的作用域中解析或不解析


      Python的作用域规则主要通过引入嵌套作用域(“闭包”)和引入可写嵌套作用域(
      非本地
      )来定义。这种静态作用域的主要用例是允许高阶函数(“函数产生函数”)自动参数化内部函数;这通常用于回调、装饰器或工厂函数

      def加法器(base=0):#工厂函数返回一个新的参数化函数
      def添加(x):
      return base+x#内部函数由base隐式参数化
      返回添加
      
      这两个PEP都编写了Python如何处理静态作用域的复杂问题。具体地说,范围在编译时解析一次——此后每个名称严格地是全局的、非局部的或局部的。作为回报,静态作用域允许优化变量访问——变量可以从全局字典中读取,也可以从全局字典中读取

      此静态范围名称解析的人工制品是
      UnboundLocalError
      :名称可能在本地范围内,但尚未在本地分配。即使在某个地方为名称分配了一些值,静态作用域也禁止访问它

      >>一些\u name=42
      >>>def ask():
      ...     打印(“答案是”,某个人的名字)
      ...     有些名字=13
      ...
      >>>询问
      UnboundLocalError:赋值前引用的局部变量“some_name”
      
      有各种方法可以避免这种情况,但它们都归结为程序员必须明确定义如何解析名称


      虽然Python本身并没有实现动态范围,但它可以很容易地被模仿。由于动态作用域与每个调用堆栈的作用域堆栈相同,因此可以显式实现

      Python本机提供了将变量上下文化到每个调用堆栈的功能。类似地,允许显式上下文化变量–这对于避开常规调用堆栈的
      async
      代码非常有用。线程的原始动态范围可以构建为线程本地的文本范围堆栈:

      导入上下文库
      导入线程
      类DynamicScope(threading.local):#实例数据是每个线程的本地数据
      “”“支持通过上下文管理器分配的动态作用域”“”
      定义初始化(自):
      super()。uuu setattr_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
      @contextlib.contextmanager#上下文强制执行设置/取消设置操作对
      def分配(自身,**名称):