Python模块和包的管理

目录

  • 模块和包
  • 导入包的几种方式
  • 包内引用
  • 自定义init.py
  • 添加本地的包到项目中

模块和包

首先,先介绍两个概念:

  • 模块:一个python文件(xxx.py)就是一个模块。我们可以在一个模块里定义变量、方法、类
  • 包:模块通过包来组织和管理。从实现的方式来看,包是一个包含init.py的文件夹

导入包的几种方式

- import item.subitem.subsubitem
- from package import item (推荐使用的方式)
- from package import *

现在假设我们有下面的文件结构,michasel.py、james.py和amanda.py的代码是类似的,除了name的值不一样:

# 文件结构
school
   boys 
       michael.py
       james.py
       __init__.py
   girls
       amanda.py
       __init__.py
   __init__.py
   
# michael.py 示例代码
name = 'Michael'

def say_hello():
    print('hi, this is %s.' % (name, ))

class Info(object):
    def __init__(self):
        pass

    def info(self):
        say_hello()

默认情况下,我们不需要在init.py下添加任何代码就可以使用上述的前两种方式导入。

  • import item.subitem.subsubitem:使用这种方法,可以导入包或者模块,但是不能导入一个模块中定义的内容,比如模块中的类,方法或者变量等。并且引用包中的内容的时候,必须使用完整的名字(这里就是item.subitem.subsubitem)。一般使用这种方式的时候,我们可以给导入的包或者模块起别名,这样就可以避免使用很长的完整名。

import school.boys.michael
school.boys.michael.say_hello()
michael.say_hello() # NameError: name 'michael' is not defined

# 取别名
import school.boys.james as james
james.say_hello()


  • from package import item:从字面理解,就是从某个包中导入子包或者模块。除此之外,还可以导入某个模块中定义的类,方法或者变量等。同时,与上面那种方法相比,这种方法可以通过import后面的名字直接使用(而不需要使用完整名)。

from school.boys import james
james.say_hello()

from school.boys.michael import name
print(name)

  • from package import *:执行from package import * 的时候,如果init.py中定义了all列表,则会把列表中列出的模块全部导入。如果没有定义all列表,那么就不支持import *;如果定义了all却没有赋值,那么import *不会导入任何模块。

# 没有定义__all__
from school.boys import *
james.say_hello() # NameError: name 'james' is not defined

# 设置__all__ = __all__ = ['james', 'michael']
from school.boys import *
james.say_hello() # Correct 
michael.say_hello() # Correct

# 设置__all__ = [](空列表)
from school.boys import *
james.say_hello() # NameError: name 'james' is not defined

包内引用

一个模块可以导入本包内的模块,也可以从邻包导入。导入的时候,可以使用相对位置或者绝对位置导入。需要注意的是,在主模块中导入不论本包或者邻包的模块的时候,总是要使用绝对位置,下面通过具体的示例来说明。

############## 引用相同包中的模块 ##############
# 在james.py中引用michael.py中定义的name
# 使用相对位置
from .michael import name as michael_name
print(michael_name)

# 使用绝对位置
from school.boys.michael import name as michael_name
################################################


############## 引用邻包中的模块 ################
# 在james.py中引用amanda.py中定义的name
# 使用相对位置
from ..girls.amanda import name as amanda_name
print(amanda_name)

# 使用绝对位置
from school.girls.amanda import name as amanda_name
################################################


############## 主模块(例如把james.py作为主模块来运行)中,必须使用绝对位置 ##############
# 例如,在james.py中以相对位置导入michael.py,并且把james.py作为主模块运行,会出现一下错误
# ModuleNotFoundError: No module named '__main__.michael'; '__main__' is not a package
from .michael import name as michael_name
print(michael_name)
#####################################################################################

自定义init.py

  • 自动加载子模块 - 还是以本文开始的文件结构为例。现在,我们想在导入school.boys包的时候,自动就导入james.py和michael.py这两个模块。只需要在boys下的init.py中添加下面的代码
# school/boys/__init__.py
from . import james
from . import michael

# 在主模块中导入
import school.boys
school.boys.michael.say_hello()

  • 合并子模块为单一的逻辑模块 - 例如james.py下有james_greeting方法,michael.py下有michael_greeting方法,希望在主模块中调用的时候,看起来这两个方法属于同一个模块,比如属于boys这个包,这样就不需要导入michael.py、james.py
# school/boys/__init__.py
from .james import james_greeting
from .michael import michael_greeting

# 在主模块中导入
import school.boys
school.boys.michael_greeting()
school.boys.james_greeting()

  • 包命名空间 - 文章一开始的部分就提到,我们可以在一个模块中导入一个包,一个包下面包含init.py文件。如果你好奇,或许你已经试过了 - 如果我们删除了包下面的init.py,我们依然可以在模块中导入这个包,这个神奇的魔法是通过“包命名空间”实现。当一个文件夹下不包含init.py的时候,那么解释器将把这个文件夹理解为包命名空间。这种用法,可能会用在一些开发框架中,对于框架的使用者而言,可以创建相同名称的文件夹并创建自己的模块,相当于把自己的模块整合到该开发框架中。我们可以输出某个包的str,通过判断是否包含"namespace"来判断是否是包命名空间。

import school.boys
print(school.boys.__path__)
print(school.boys)

# output

# 包
['D:\\Workspace\\Python\\PackageDemo\\school\\boys']
<module 'school.boys' from 'D:\\Workspace\\Python\\PackageDemo\\school\\boys\\__init__.py'>

# 包命名空间
_NamespacePath(['D:\\Workspace\\Python\\PackageDemo\\school\\boys'])
<module 'school.boys' (namespace)>

添加本地的包到项目中

有一种情况是,在公司的项目中,我们需要使用到一些自家的通用的包,这个包无法通过网络获取,但是在我们的开发环境中可以找到,那在我们开发的项目中,如何去导入呢?一种简单粗暴的方法是,将包所在的路径添加的系统变量PATHONPATH中(其实还可以pip install --user packagename 来安装私有包);另一个种是我们在项目中,修改sys.path,这样去告诉解释器去哪里找这个包。例如,现在我们把这个自家是包复制到项目是packages目录中:


import sys
from os.path import abspath, join, dirname
sys.path.insert(0, join(abspath(dirname(__file__)), 'src'))

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

推荐阅读更多精彩内容

  • 在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,比如在Pyth...
    一只写程序的猿阅读 3,981评论 0 3
  • 模块 一个模块就是包含了python定义和声明的文件,文件名就是模块名字加上.py后缀,通过导入模块来引入其他文件...
    断尾壁虎V阅读 1,598评论 0 1
  • 类 类的概念在许多语言中出现,很容易理解。它将数据和操作进行封装,以便将来的复用。 模块 模块,在Python可理...
    随风化作雨阅读 1,894评论 0 5
  • 1.1Python中的模块介绍和使用 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt函数,必须用语句#...
    TENG书阅读 412评论 0 0
  • [2] 恩惠与平安 腓立比书一章2节【腓1:2】愿恩惠、平安从神我们的父并主耶稣基督归与你们! 原文精要 恩惠:(...
    术兵阅读 3,865评论 0 0