Python学习笔记(5)——package, module

一个常见的定义module的方法是写一个.py文件,除此以外,Python的底层实现是C/C++,所以你也可以使用C/C++来写module,当然这是比较高级的方法了,暂时不作深入。

Module

通常,我们使用import关键字来引入一个module:

import os

它会调用内置函数__import()__,并把结果绑定到相应的变量名,__import()__本身会搜索并创建一个module对象,也就是说如果这样用也是可以的:

os = __import__('os')

print(os.path.exists('c:/'))

当然没有必要这么做。
import关键字和__import()__函数是在importlib模块实现的,该模块甚至允许你编写你自己的importer来自定义import过程,当然这是比较高阶的内容了。
除此以外,也可以用from关键字来指定module的package,以from [package name] import [module name]的形式来import module。
另外,使用as关键字,可以给module指定一个别名,方便使用一些名字较长的module:

import os.path as op


print(op.exists('c:/'))

Submodule

__init__.py中,可以使用import关键字引入submodule,如此,会将submodule加入module的命名空间:
目录结构:

spam/
    __init__.py
    foo.py

__init__.py

from .foo import Foo

foo.py

def Foo():
    print('foo')

如此,便可以如下引用Foo()

import spam


spam.Foo()

Package

Python的package可以看作是文件夹,而module就是文件夹中的文件(可以是普通的.py文件或者C文件),但是也可能有其它形式,module不一定是在本地文件系统里面的,为了简化,我们可以简单地看成文件夹跟文件。
package本身可以看作是一种特殊的module,一个判定方式是如果module具有__path__属性,那么这个module就是一个package。
我们import一个module,打印它的__path__,可以看到报错:NameError: name '__path__' is not defined,但是我们import一个package以后,打印它的__path__是可以看到结果的:

import os
import getkey

print(getkey.__path__)
print(os.__path__)

分别打印内置module os和第三方package getkey的__path__属性,可以看到输出:

['C:\\Users\\***\\AppData\\Local\\Programs\\Python\\Python38\\lib\\site-packages\\getkey']
Traceback (most recent call last):
  File "c:/Users/***/PycharmProjects/Test/test.py", line 5, in <module>
    print(os.__path__)
AttributeError: module 'os' has no attribute '__path__'

package可以有subpackage,关系上类似文件系统的父目录跟子目录,import时使用.来引用。

Regular package

Python有两种package:regular packagenamespace package,其中regular package是在Python 3.2以及之前的版本中定义的,如果你接触Python较早,应该对这个很熟悉,regular package的目录下面需要有一个__init__.py文件:

parent/
 __init__.py
 one/
  __init__.py
 two/
  __init__.py
 three/
  __init__.py

在import module时,__init__.py中的代码会被执行,比如import parent.one,会执行parent/__init__.pyparent/one/__init__.py

Namespace package

在3.3及以后的版本中,Python添加了namespace package的特性,如前所述,package跟module不一定是在本地文件系统中的,或者不一定是以文件夹/.py文件的形式,它可以是来自zip文件或者网络或者任何东西,并且同一个pakcage可以以分布式的形式存在于不同的地方,总之namespace package相对于传统的package,具有分布式的特点且更加抽象化,在大型项目中非常有用,它允许开发者在不同的独立目录下创建属于同一个package的module,并且可以使用相同的package name。
参考PEP 420,Python提供了pkgutil.extend_path来定义一个namespace package,在__init__.py里加入如下代码:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

如果你使用setuptools这个工具,那么在setup.py中写以下代码作用也是相同的:

import pkg_resources
pkg_resources.declare_namespace(__name__)

举个例子,我们创建如下目录结构:

└─libs
│   ├─a
│   │  └─pkg
│   │      └─__init__.py
│   │      └─a.py
│   └─b
│      └─pkg
│          └─__init__.py
│          └─b.py
└─test.py

在两个__init__.py中加入上述代码,在a.pyb.py中分别定义两个函数:
a.py

def a():
    print('hello a')

b.py

def b():
    print('hello b')

那么,在test.py中可以如此import两个module:

import sys

sys.path += ['libs/a', 'libs/b']

from pkg.a import a
from pkg.b import b

a()
b()

注意,要先把两个package的路径加入sys.path,并且由于extend_path是运行时计算的,所以在编辑器里会报错,但是运行是没问题的。
此外,这种方式各个module的import顺序是无法保证的,也就是同名package下的module得是独立的,相互不要有依赖。

隐式Namespace package

除上述方法之外,在3.3及以后的版本中,package目录下可以不写__init__.py,如此就把它隐式地声明为了一个namespace package,也就是说,把上一节中的__init__.py都删除,也是可以正常运行的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容

  • Python基础知识_0001 1.0 Python是一种怎样的语言 Python是一门跨平台、开源、免费的解释型...
    爱学习的小白F1阅读 1,089评论 0 1
  • 高阶函数:将函数作为参数 sortted()它还可以接收一个key函数来实现自定义的排序,reversec参数可反...
    royal_47a2阅读 684评论 0 0
  • Python3 Study Notes 本人很少写 python 代码, 一般都是用 go 的, 去年时用 pyt...
    jouyouyun阅读 352评论 0 7
  • 这篇内容其实很早就在自己的电脑上整理完成了,主要用作对做记录整理Python和其他语言不太一样的地方,使自己可以快...
    KwokKwok阅读 333评论 0 0
  • 模块是包括 Python 定义和声明的文件. 后缀.py. 模块名可以由全局变量__name__获取. fibo....
    罗佳欣阅读 405评论 0 0