【问题标题】:What are Python namespaces all about什么是 Python 命名空间
【发布时间】:2011-04-24 05:10:15
【问题描述】:

我刚刚开始学习 Python,并且在 Python 中遇到了 “命名空间” 概念。虽然我知道它是什么,但我无法理解这个概念的严重性。

网上的一些浏览显示,反对 PHP 的原因之一是它不支持命名空间。

有人能解释一下如何使用命名空间以及此功能如何使编程变得更好(不仅仅是在 Python 中,因为我假设命名空间不是仅限于特定语言的概念)。

我主要来自 Java 和 C 编程背景。

【问题讨论】:

标签: python programming-languages namespaces


【解决方案1】:

命名空间是实现作用域的一种方式。

在 Java(或 C)中,编译器通过静态范围分析确定变量在何处可见。

  • 在 C 中,作用域要么是函数体,要么是全局的,要么是外部的。编译器会为您解释这一点,并根据范围规则解析每个变量名称。编译所有模块后,外部名称由链接器解析。

  • 在 Java 中,作用域是方法函数的主体,或类的所有方法。一些类名也具有模块级范围。同样,编译器会在编译时计算出这一点,并根据作用域规则解析每个名称。

在 Python 中,每个包、模块、类、函数和方法函数都拥有一个“命名空间”,在其中解析变量名。另外,如果名称不在本地命名空间中,则使用全局命名空间。

每个变量名在本地命名空间(函数体、模块等)中检查,然后在全局命名空间中检查。

变量通常只在本地命名空间中创建。 global 和 nonlocal 语句可以在本地命名空间之外创建变量。

当一个函数、方法函数、模块或包被评估(即开始执行)时,就会创建一个命名空间。将其视为“评估上下文”。当一个函数或方法函数等完成执行时,命名空间被删除。变量被删除。对象也可能被丢弃。

【讨论】:

  • 命名空间是在作用域内实现名称管理的一种方式,因为作用域不仅仅是名称管理。看我的回答。
【解决方案2】:

命名空间可防止可能由不同人编写的具有相同名称的类、方法和对象之间发生冲突。

来自 Java 背景的您可能熟悉如何使用包来实现这一点,例如您可以创建一个movieyoda.DateUtils 类,我可以创建一个mikej.DateUtils 类,并且该包允许代码使用这些类来区分它们。 (Python 有something very similar。)

命名空间是在 5.3.0 中添加到 PHP 中的,但在早期版本中(以及在其他不提供命名空间的语言中),您必须在类和方法名称前加上一些前缀,以降低名称冲突的风险。例如movieyoda_parse_file 函数。

【讨论】:

    【解决方案3】:

    要了解命名空间,您还必须对 Python 中的模块有所了解。模块只是一个包含 Python 代码的文件。此代码可以是 Python 类、函数或只是名称列表的形式。每个模块都有自己的全局命名空间。因此,您不能在同一个模块中拥有两个具有相同名称的类或两个函数,因为它们共享模块的命名空间。

    参考:http://bytebaker.com/2008/07/30/python-namespaces/

    【讨论】:

      【解决方案4】:

      命名空间提供了一种管理范围内定义的标识符的方法。换句话说,它们用于将名称映射到值(或者更准确地说是对内存位置的引用)。

      例如,在命名空间的上下文中,以下表达式

      x = 10
      

      将标识符x 与保存值为10 的对象的内存位置相关联。


      在 Python 中,命名空间基本上有两种“类型”; 实例和类命名空间。

      Instance Namespace 管理单个对象范围内名称和值之间的映射。另一方面,源代码中定义的每个类都有一个单独的类命名空间。这种类型的命名空间处理对象的所有实例共享的所有成员。


      示例

      现在考虑以下示例,其中每个成员都表示它是否属于类或实例命名空间:

      class Customer:
      
          def __init__(self, first_name, last_name, email): # __init__ -> Customer Class Namespace
              self._first_name = first_name # _first_name -> Instance Namespace
              self._last_name = last_name # _last_name -> Instance Namespace
              self._email = email # _email -> Instance Namespace
      
          def get_full_name(self): # Customer Class Namespace
              return f"{self._first_name} {self._last_name}"
      
      
      class PremiumCustomer(Customer):
      
          PREMIUM_MEMBERSHIP_COST = 4.99  # PremiumCustomer Class Namespace
      
      
          class Subscription: # PremiumCustomer Class Namespace
      
              def __init__(self, customer_email): # Subscription Class Namespace
                  self._customer_email = customer_email # Instance Namespace
      
          def __init__(self, first_name, last_name, email, card_number): # PremiumCustomer Class Namespace
              super().__init__(first_name, last_name, email)
              self._card_number = card_number # _card_number -> Instance Namespace
      
          def get_card_number(self): # PremiumCustomer Class Namespace
              return self._card_number
      

      【讨论】:

        【解决方案5】:

        我完成了 S.Lott 的答案。

        我想说,命名空间是在作用域内实现名称管理的一种方式,因为作用域不仅仅是名称管理。

        在 C 中,作用域有 4 种类型:全局、函数、块和函数参数(原型)。根据需要,这些类型中的每一种都可以创建一个或多个名称空间。 C中有4 ns -- s/u/e 的标签 -- 类型名、函数名和变量名的 id -- 函数原型内的参数 -- s/u 中的成员和位域。

        这样,标签标识符和函数名不会冲突,但 typedef 定义的类型名可以与变量名冲突。

        在 python 中有一个内置的命名空间,它包含了全局 ns,而全局 ns 由加载的模块提供。内置 ns 包含变量。变量的符号可以定义对象或函数——例如,+ 在此处定义。模块的全局 ns 一直持续到终止。

        另见that,当然还有that。

        【讨论】:

          【解决方案6】:

          如果您与其他人一起编写了一个大程序,您可以根据需要编写自己的程序部分。文件中的所有变量都是私有的,不会有冲突。 在编写 PHP 程序时,很容易错误地重写全局变量。在 python 中,您可以根据需要导入其他模块变量,它们将在您的模块上是“全局的”。

          你可以认为 Python 中的一个文件一个对象。当你编写 PHP 程序时,你可以通过编写带有实例变量的类来达到同样的目的。

          【讨论】:

            猜你喜欢
            • 2011-03-23
            • 1970-01-01
            • 2013-06-04
            • 2013-02-08
            • 2012-06-16
            相关资源
            最近更新 更多