我刚开始学习Python并接触到Python中的"命名空间"概念。虽然我大致知道它是什么,但无法理解这个概念的重要性。
上网搜索发现,PHP存在一个不利因素是没有原生支持命名空间。
有人能解释一下如何使用命名空间以及这个特性如何使编程变得更好(不仅限于Python,因为我认为命名空间不是某种特定语言的概念)。
我主要来自Java和C编程背景。
我刚开始学习Python并接触到Python中的"命名空间"概念。虽然我大致知道它是什么,但无法理解这个概念的重要性。
上网搜索发现,PHP存在一个不利因素是没有原生支持命名空间。
有人能解释一下如何使用命名空间以及这个特性如何使编程变得更好(不仅限于Python,因为我认为命名空间不是某种特定语言的概念)。
我主要来自Java和C编程背景。
命名空间是实现作用域的一种方式。
在Java(或C)中,编译器通过静态范围分析确定变量在何处可见。
在C中,作用域可以是函数体、全局变量或外部变量。编译器会根据作用域规则来解析每个变量名。链接程序将在所有模块编译后解析外部名称。
在Java中,作用域可以是方法函数体,也可以是类的所有方法函数。一些类名也具有模块级别的作用域。编译器也会在编译时根据作用域规则解析每个名称。
在Python中,每个包、模块、类、函数和方法函数都拥有一个“命名空间”,其中变量名得以解析。此外,全局命名空间是在本地命名空间中找不到名称时使用的。
每个变量名首先在本地命名空间(如函数体、模块等)中检查,然后在全局命名空间中检查。
通常只在本地命名空间中创建变量。但是,global
和nonlocal
语句可以在本地命名空间之外创建变量。
当评估函数、方法函数、模块或包(即开始执行)时,会创建一个命名空间。可以将其视为“评估上下文”。当函数或方法函数等执行完成时,该命名空间将被删除。变量也将被删除。对象也可能被删除。
命名空间可以防止不同人编写的具有相同名称的类、方法和对象之间的冲突。
如果您来自Java背景,您可能熟悉如何使用包来实现这一点,例如,您可能会创建一个movieyoda.DateUtils
类,而我可以创建一个mikej.DateUtils
类,该包允许使用这些类的代码进行区分。 (Python有非常相似的东西。)
PHP 5.3.0中添加了命名空间,但在早期版本(以及其他不提供命名空间的语言中),您必须为类和方法名称添加前缀以减少名称冲突的风险。例如,movieyoda_parse_file
函数。
命名空间提供了一种管理范围内定义的标识符的方法。换句话说,它们用于将名称映射到值(或更精确地说是引用内存位置)。
例如,在命名空间的上下文中,以下表达式
x = 10
将标识符x
与保存数值为10
的对象的内存位置关联起来。
例子
现在考虑以下例子,其中对于每个成员都指定它属于类或实例命名空间:
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
我来补充一下S.Lott的回答。
我认为,命名空间是在作用域内实现名称管理的一种方式,因为作用域不仅仅是名称管理。
在C语言中,作用域有4种类型:全局、函数、块和函数参数(原型)。每种类型都可以根据需要创建一个或多个命名空间。在C语言中有4个命名空间: -- s/u/e标签 -- 类型名称、函数名称和变量名称的ids -- 函数原型内的参数 -- s/u内的成员和位域。
这样,标签标识符和函数名称不会冲突,但由typedef定义的类型名称可能会与变量名称冲突。
在Python中,有一个内置的命名空间包含全局命名空间,并且全局命名空间由加载的模块提供。内置命名空间包含变量。变量的符号可以定义对象或函数--例如,+
就是在那里定义的。模块的全局命名空间持续到终止。