Python中模块与包

一. 模块

1. 概念

为了便于代码维护,一般很多函数分组,分别放到不同的文件里,每个文件包含的代码就相对较少,维护也更方便。在Python中,一个.py文件就称之为一个模块(Module)。
Python中模块分为三种: Python标准库第三方模块应用程序自定义模块
使用模块可以帮助避免函数与其他模块函数重名,函数名与变量名重名的问题。
此外,要尽量避免定义的模块名与内置函数(build in function)重名。

2. 模块引入方法

模块的引入使用import相关语句。
在模块中可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行。
import语句是可以在程序中的任意位置使用,同一个模块可以被多次引用
为了防止在同一个文件中重复引入,python使用了一下优化方法:第一次导入后将模块名加载到内存,后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用,不会重新执行模块内的语句

import 语句

import module1[, module2[, module3[, ...moduleN]]]
Python解释器通过import 语句在搜索路径中搜索相应的模块,
模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块
若在当前目录下存在与要引入模块同名的文件,就会把要引入的模块屏蔽掉

from ... import 语句

from modulename import name1[, name2[, ... nameN]]
这个声明不会把整个modulename模块导入到当前的命名空间中,只会将它里面的name1name2单个引入到执行这个声明的模块的全局符号表

from ... import *

from modulename import *
通过使用*提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。大多数情况, Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。

3. 为模块名起别名

别名的使用可以简化编程
两个模块xmlreader.pycsvreader.py,它们都定义了函数read_data(filename),用来从文件中读取一些数据,但采用不同的输入格式。可以通过为模块起别名实现使用同样的代码实现不同的功能,例如

if file_format == 'xml':
    import xmlreader as reader
elif file_format == 'csv':
    import csvreader as reader
data=reader.read_date(filename)

二. 包

为了避免模块名冲突,Python引入了按目录来组织模块的方法,称为包(Package)。
无论是import形式还是from...import,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法,点的左边都必须是一个包。
包的本质就是一个包含__init__.py文件的目录。
需要注意的是from后import导入的模块不能带点,否则会有语法错误,如:from a import b.c是错误语法

1. __init__.py

无论使用import还是from import,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件。

2. from modulename import *

Foo                      #Top-level package
|__ __init__.py          #Initialize the glance package
|
|__ api                  #Subpackage for api
|     |__ __init__.py
|     |__ read.py
|     |__ write.py
|
|__ cmd                  #Subpackage for cmd
|     |__ __init__.py
|     |__ control.py
|
|__ db                   #Subpackage for db
      |__ __init__.py
      |__ data.py

此处是想从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:

#在__init__.py中定义
x=10

def func():
    print('from api.__init.py')

__all__=['x','read', 'func']

此时在与Foo同级的文件中执行from Foo.api import *就导入__all__中的内容,write仍然不能导入。

3. 绝对导入和相对导入

上述例子中最顶级包Foo是写给别人用的,然后在Foo包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:
绝对导入:以Foo作为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)

例如:我们在Foo/api/write.py中想要导入Foo/cmd/control.py

在Foo/api/write.py

#绝对导入
from Foo.cmd import control
control.ctrl()

#相对导入
from ..cmd import control
control.ctrl()

特别需要注意的是:可以用import导入内置或者第三方模块,但是要绝对避免使用import来导入自定义包的子模块,应该使用from... import ...的绝对或者相对导入,且包的相对导入只能用from的形式。

__all__是用于控制from...import * ,不能用于使用import单独导入包

4. 多层目录直接调用内部函数

创建如下目录结构

Foo
 |---test.py
 |---keystone
     |---auth
     |   |---plugins
     |   |   |---core.py
     |   |   |---__init__.py
     |   |
     |   |---__init__.py
     |
     |---__init__.py

core.py内容为:

def create(cls=None, auth_payload=None, method_name=None):
    print('function create')
    pass

class UserAuthInfo:
    def __init__(self):
        self.password = None
    def foo(self):
        print('cls UserAuthInfo')

要求:import keystone,然后就可以直接调用keystone.create和keystone.UserAuthInfo

在keystone目录下的__init__.py中输入如下代码

from .auth.plugins.core import create
from .auth.plugins.core import UserAuthInfo

在test.py中调用core.py中的函数

import keystone
keystone.create()
a = keystone.UserAuthInfo()
a.foo()

>>function create
>>cls UserAuthInfo

5. 包与包之间模块导入

目录结构及调用关系如下所示

Foo
 |---dir1
 |   |---hello.py
 |---dir2
     |---main.py
     
其中,hello.py:
def add(x,y)
    return x+y

main.py如何能调用到hello.py中的add函数。

解决方法

import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # 当前project的目录
print(BASE_DIR)
sys.path.append(BASE_DIR) # 添加当前project目录到环境变量

from dir1 import hello

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

推荐阅读更多精彩内容