Python是一门入门简单,精通困难的编程语言。
Python是一门比较高阶的语言,在基本语法和使用方面没有C、Java那么复杂。因此,对于入门者来说,很接近于自然语言的表述方式,经过短暂的的学习就可以完成一些简单的工作。
但是,我认为如果仅用一两年Python就断言“Python简单”的同学,95%都不是真正的懂得Python。
以我们经常会用的Python导入工具包为例,这对于Python初学者应该是最基础、最简单的部分,但是,绝大多数都对Python工具包理解透彻。
模块与工具包
模块(modules)和工具包(packages)这2个概念首当其冲,经常被Python开发者混为一谈。
虽然,二者有很多相同之处,但是还是存在一定差异。因此,要想彻底理解import,首先就需要理解模块与工具包的异同点。
模块
Python官网对于模块的定义如下:模块具有一个包含任意Python对象的命名空间,通常用作Python代码组织单位的对象。
实际上,一个模块通常对应一个.py文件,模块的真正功能是可以将其导入到其他代码中,并重复使用,例如:
>>> import math
>>> math.pi
3.141592653589793
第一行代码,通过import把math模块导入到代码中,通过math.pi来调用pi这一属性。
这里需要注意,这里写的math.pi不仅是单纯的pi,它还把math充当所有属性保持统一的命名空间。命名空间对于保持代码的可读性和组织性非常有用。
你可以利用 dir来查看命名空间的内容:
>>> import math
>>> dir()
['__annotations__', '__builtins__', ..., 'math']
>>> dir(math)
['__doc__', ..., 'nan', 'pi', 'pow', ...]
除了上述直接导入,我们还可以导入模块下特定的部分:
>>> from math import pi
>>> pi
3.141592653589793
>>> math.pi
NameError: name 'math'isnot defined
请注意,这里对比于前一种方式已经发生了一些转变。这里的pi是放置在全局命名空间内,而不是math的命名空间内。
包
同样,首先看一下Python官网对工具包的定义:一个Python模块,可以包含子模块或递归地包含子包。从技术上讲,包是具有__path__属性的Python模块。
从定义上可以看出,包仍然是模块。但是,它们还是有一定的区别。
从编码上来讲,Python包需要在目录下创建一个名为__init__.py的文件。
导入模块时,通常不会导入子模块和子包,但是,你可以通过添加__init__.py来将需要导入的子模块和子包囊括进去。
绝对导入与相对导入
from ... import ...这种导入当时在代码中经常会遇到,假如,我们有如下工程:
world/
│
├── africa/
│ ├── __init__.py
│ └── zimbabwe.py
│
├── europe/
│ ├── __init__.py
│ ├── greece.py
│ ├── norway.py
│ └── spain.py
│
└── __init__.py
当想要导入africa时可以这样:
from world import africa
也可以这样:
from . import africa
那么这里面的**点(.)**代表什么含义?
这里的点(.)就是一种相对导入,你可以理解为从当前包中导入africa。
相反,绝对导入语句中,需要明确命名当前包:
from world import africa
在编码过程中,你可以选择绝对导入,也可以选择相对导入。只不过,PEP 8风格指南中,建议使用绝对导入。
从这个简单的例子来看Python工具包和模块的导入,会发现,它不仅仅是import那么简单。