Python命名空间是什么意思?

50

我刚开始学习Python并接触到Python中的"命名空间"概念。虽然我大致知道它是什么,但无法理解这个概念的重要性。

上网搜索发现,PHP存在一个不利因素是没有原生支持命名空间。

有人能解释一下如何使用命名空间以及这个特性如何使编程变得更好(不仅限于Python,因为我认为命名空间不是某种特定语言的概念)。

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


2
几个小时前,一些其他的PHP开发者在命名空间方面遇到了问题:https://dev59.com/Z2865IYBdhLWcg3wQMMD 可以值得一读。 - Nick T
6个回答

50

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

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

  • 在C中,作用域可以是函数体、全局变量或外部变量。编译器会根据作用域规则来解析每个变量名。链接程序将在所有模块编译后解析外部名称。

  • 在Java中,作用域可以是方法函数体,也可以是类的所有方法函数。一些类名也具有模块级别的作用域。编译器也会在编译时根据作用域规则解析每个名称。

在Python中,每个包、模块、类、函数和方法函数都拥有一个“命名空间”,其中变量名得以解析。此外,全局命名空间是在本地命名空间中找不到名称时使用的。

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

通常只在本地命名空间中创建变量。但是,globalnonlocal语句可以在本地命名空间之外创建变量。

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


2
命名空间是在作用域内实现名称管理的一种方式,因为作用域不仅仅是名称管理。请看我的回答。 - alinsoar

5

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

如果您来自Java背景,您可能熟悉如何使用包来实现这一点,例如,您可能会创建一个movieyoda.DateUtils类,而我可以创建一个mikej.DateUtils类,该包允许使用这些类的代码进行区分。 (Python有非常相似的东西。)

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


4
为了理解Python中的命名空间,您还需要对模块有一些了解。模块只是包含Python代码的文件。这些代码可以是Python类、函数或仅是名称列表。每个模块都有自己的全局命名空间。因此,如果两个类或两个函数在同一个模块中具有相同的名称,则它们共享该模块的命名空间。
参考:http://bytebaker.com/2008/07/30/python-namespaces/

1

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

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

x = 10

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


在Python中,基本上有两种名称空间类型; 实例和类名称空间。实例名称空间管理个体对象范围内的名称和值之间的映射。另一方面,在源代码中定义的每个类都有一个单独的Class 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

0

我来补充一下S.Lott的回答。

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

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

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

在Python中,有一个内置的命名空间包含全局命名空间,并且全局命名空间由加载的模块提供。内置命名空间包含变量。变量的符号可以定义对象或函数--例如,+就是在那里定义的。模块的全局命名空间持续到终止。

另请参见此处,当然还有此处


-1
如果你和别人一起编写一个大型程序,你可以按照自己的意愿编写程序的一部分。文件中的所有变量都将是私有的,不会发生冲突。
在编写 PHP 程序时,很容易因为错误而重写全局变量。在 Python 中,如果需要,你可以导入其他模块的变量,并且它们将成为你的模块中的“全局”变量。
在 Python 中,你可以认为一个文件就是一个对象。在编写 PHP 程序时,你可以通过编写带有实例变量的类来实现相同的效果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接