python 命名空间报错_从Python的两种导入模块(from import和import)方式谈命名空间与作用域...

本文通过一个Python命名空间错误的例子,深入探讨了命名空间的定义、分类,包括局部、全局和内建命名空间,并介绍了作用域的概念及变量查找规则。最后提出了解决该问题的方法,并引发关于导入模块方式选择的讨论。
摘要由CSDN通过智能技术生成

在谈论python命名空间之前,首先介绍一个因为python命名空间引起的坑。

一、问题实例

项目中使用pyqt编写gui,gui在处理文本文件时使用了10进制转16进制的hex函数

代码片段:

from PyQt4.QtCore import *

print hex(10)

期望的输出为0xa,但实际上运行的时候报错

TypeError: hex(QTextStream): argument 1 has unexpected type 'int'

检查了后发现了是PyQt4.QtCore中存在hex函数,导致系统函数hex被重载了。这个问题是python命名空间

与作用域导致的,那么,什么是python的命名空间与作用域呢?

二、命名空间(Namespace)

【定义】

名称到对象的映射。命名空间由一个字典实现,键为变量名,值是变量对应的值。各个命名空间是独立的,

一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响。

【分类】

Python程序执行期间会有2个或3个活动的命名空间(函数调用时有3个,函数调用结束后2个)。按照

变量定义的位置,可以划分为以下3类:

1 、Local。局部命名空间,每个函数所拥有的命名空间,记录了函数中定义的所有变量,包括函数的入参、

内部定义的局部变量。

local命名空间可以在函数中使用locals()函数获取。

def test_function_namespace():

a = 1

b = 2

print locals()

执行结果如下,表示a,b两个变量属于test_function_namespace这个函数的本地命名空间:

{'a': 1, 'b': 2}

2、Global。全局命名空间,每个模块加载执行时创建的,记录了模块中定义的变量,包括模块中定义的函数、

类、其他导入的模块、模块级的变量与常量。

global命名空间可以在模块中任意位置使用globals()函数获取。

def test_module_namespace():

a = 1

b = 2

print globals()

执行结果如下,可以看到test_module_namespace中的a、b变量并不属于该模块的全局命名空间,说明

local与global命名空间是相互隔离的:

{'test_class_namespace': , 'test_module_namespace': , '__builtins__': , '__file__': 'Z:/test/test_celery/tasks/test.py', 'TestClass': , '__package__': None, 'test_instance_namespace': , 'test_function_namespace': , '__name__': '__main__', '__doc__': None}

3、Built-in,python自带的内建命名空间,任何模块均可以访问,放着内置的函数和异常。从某种意义上来

说,一个对象(object)或类(Class)的所有属性(attribute)(包含方法)也构成了一个namespace。在程序执行

期间,有多个类实例就会有多个命名空间同时存在。

类或对象的命名空间用__dict__()方法获取获取类的命名空间

def test_class_namespace():

print TestClass.__dict__

执行结果如下,所有TestClass类的对象共享该命名空间:

{'a': 1, '__module__': '__main__', '__dict__': , '__weakref__': , '__doc__': None, '__init__': }

期望的输出为0xa,但实际上运行的时候报错

获取对象的命名空间

def test_instance_namespace():

test_instance = TestClass()

print test_instance.__dict__

执行结果如下,每一个实例都会有一个独立的命名空间:

{'b': 2}

三、作用域(Scope)

【定义】

作用域是针对变量而言,指申明的变量在程序里的可应用范围。或者称为变量的可见性。

【分类】

Local(函数内部)局部作用域

Enclosing(嵌套函数的外层函数内部)嵌套作用域(闭包)

Global(模块全局)全局作用域

Built-in(内建)内建作用域

【变量查找法则】

当程序引用某个变量的名字时,就会从当前名字空间开始搜索。搜索顺序规则便是: LEGB。即从内往外一层

一层的查找,找到了之后,便停止搜索,如果最后没有找到,则抛出在NameError的异常

【命名空间与作用域的关系】

命名空间定义了在某个作用域内变量名和绑定值之间的对应关系,命名空间是键值对的集合,变量名与值是

一一对应关系。作用域定义了命名空间中的变量能够在多大范围内起作用。

四、解决方案:

在module_yy中执行from module_xx import func_xx后,module_yy的命名空间中就拥有了func_xx。

后面再更改module_xx 命名空间中的fun_xx,不会改变module_yy的命名空间中的func_xx。

而在module_yy中执行import module_xx 后,module_yy的命名空间中就拥有了module_xx。可以通过

module_xx.func_xx调用函数,后面再更改module_xx 命名空间中的fun_xx,在module_yy的调用

module_xx.func_xx也会改变。

修改后的代码:

import PyQt4.QtCore

print hex(10)

输出为:

0xa

五、疑问:

为何大部分python源代码都使用了from module_xx import func_xx方式?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值