python包实际怎么使用_Python--模块与包

模块

1、什么是模块?

一个模块就是一个Python文件,文件名就是模块名字加上.py后缀。因此模块名称也必须符合变量名的命名规范。

1 使用python编写的代码(.py文件)

2 已被编译为共享库或DLL的C或C++扩展

3 包好一组模块的包

4 使用C编写并链接到python解释器的内置模块

2、为什么要使用模块?

如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。

随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用,

3、如何使用模块?

方式一:import

方式二:from ... import ...

import

首先,自定义一个模块my_module.py,文件名my_module.py,模块名my_module

name = "我是自定义模块的内容..."

deffunc():print("my_module:", name)print("模块中打印的内容...")

my_module

在import一个模块的过程中,发生了哪些事情?

#用import导入my_module模块

importmy_module>>>模块中打印的内容...#怎么回事,竟然执行了my_module模块中的print语句

importmy_moduleimportmy_moduleimportmy_moduleimportmy_moduleimportmy_module>>>模块中打印的内容...#只打印一次

从上面的结果可以看出,import一个模块的时候相当于执行了这个模块,而且一个模块是不会重复被导入的,只会导入一次(python解释器第一次就把模块名加载到内存中,之后的import都只是在对应的内存空间中寻找。)成功导入一个模块后,被导入模块与文本之间的命名空间的问题,就成为接下来要搞清楚的概念了。

被导入模块与本文件之间命名空间的关系?

假设当前文件也有一个变量为: name = 'local file', 也有一个同名的func方法。

#本地文件

name = "local file"

deffunc():print(name)#本地文件有跟被导入模块同名的变量和函数,究竟用到的是哪个呢?

importmy_moduleprint(my_module.name) #根据结果可以看出,引用的是模块里面的name

my_module.func() #执行的是模块里面的func()函数

>>>模块中打印的内容...

我是自定义模块的内容...

my_module: 我是自定义模块的内容...print(name) #使用的是本地的name变量

func() #使用的是本地的func函数

>>>local file

local file

在import模块的时候发生了下面的几步:

1、先寻找模块

2、如果找到了,就在内存中开辟一块空间,从上至下执行这个模块

3、把这个模块中用到的对象都收录到新开辟的内存空间中

4、给这个内存空间创建一个变量指向这个空间,用来引用其内容。

总之,模块与文件之间的内存空间始终是隔离的

给导入的模块取别名,用as关键字

如果导入的模块名太长不好记,那么可以通过“import 模块名 as  别名”的方式给模块名取一个别名,但此时原来的模块就不再生效了(相当于创建了新的变量名指向模块内存空间,断掉原模块名的引用)。

#给my_module模块取别名

importmy_module as smprint(sm.name)>>>我是自定义模块的内容...print(my_module.name) #取了别名后,原来的模块名就不生效了

>>>NameError: name'my_module' is not defined

给模块去别名,还可以使代码更加灵活,减少冗余,常用在根据用户输入的不同,调用不同的模块。

#按照先前的做法,写一个函数,根据用户传入的序列化模块,使用对应的方法

defdump(method):if method == 'json':importjson

with open('dump.txt', 'wb') as f:

json.dump('xxx', f)elif method == 'pickle':importpickle

with open('dump.txt', 'wb') as f:

pickle.dump('xxx', f)#上面的代码冗余度很高,如果简化代码?通过模块取别名的方式,可以减少冗余

defdump(method):if method == 'json':importjson as melif method == 'pickle':importpickle as m

with open('dump.txt', 'wb') as f:

m.dump('dump.txt', f)

如何同时导入多个模块?

方式一:每行导入一个模块

importosimportsysimport time

方式二:一行导入多个模块,模块之间通过逗号“,”来分隔

import os, sys, my_module

但是,根据PEP8规范规定使用第一种方式,并且三种模块有先后顺序(内置>第三方>自定义)

#根据PEP8规范

importosimportdjangoimport my_module

模块搜索路径

通过sys内置模块,我们知道sys.path存储了所有模块的路径,但是正常的sys.path的路径中除了内置模块,第三方模块所在的路径之外,只有一个路径是永远正确的,就是当前执行的文件所在目录。一个模块是否能够被导入,就取决于这个模块所在的目录是否在sys.path中。

python解释器在启动时会自动加载一些模块,可以使用sys.modules查看

在第一次导入某个模块时(比如my_module),会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用

如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找my_module.py文件。

所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块

需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。

模块和脚本

运行一个py文件有两种方式,但是这两种执行方式之间有一个明显的差别,就是__name__。

1、已脚本的方式执行:cmd中“python xxx.py” 或者pycharm等IDE中执行

__name__ = '__main__'

2、导入模块时执行:import模块,会执行该模块。

__name__ = 模块名

然而,当你有一个py文件既可以作为脚本执行,又可以作为模块提供给其他模块引用时,这时作为模块需要导入时而不显示多余的打印逻辑/函数调用,所以这些逻辑可以放在“if __name__ = '__main__': xxx” 代码块中。

这样py文件作为脚本执行的时候就能够打印出来,以模块被导入时,便不会打印出来。

from ... import ...

from...import是另一种导入模块的形式,如果你不想每次调用模块的对象都加上模块名,就可以使用这种方式。

在from ... import ... 的过程中发生了什么事儿?

from my_module importname, funcprint(name) #此时引用模块中的对象时,就不要再加上模块名了。

func()

1、寻找模块

2、如果找到模块,在内存中开辟一块内存空间,从上至下执行模块

3、把模块中的对应关系全部都保存到新开辟的内存空间中

4、建立一个变量xxx引用改模块空间中对应的xxx, 如果没有import进来的时候,就使用不了。

from ... import ... 方式取别名

与import方式如出一辙,通过"from 模块名 import  对象名  as  别名"。

from my_module import name as n, func as f

from ... import *

import * 相当于把这个模块中的所有名字都引入到当前文件中,但是如果你自己的py文件如果有重名的变量,那么就会产生不好的影响,因此使用from...import *时需要谨慎,不建议使用。

* 与 __all__

__all__是与*配合使用的,在被导入模块中增加一行__all__=['xxx','yyy'],就规定了使用import *是只能导入在__all__中规定的属性。

#在my_module模块中定义__all__

__all__ = ['name']

name= 'My module...'

deffunc():print("my_module:", name)#在其他文件中通过import *导入所有属性

from my_module import *

print(name)>>>My module...

func()>>>NameError: name'func' is not defined

拓展知识点:

(1)pyc文件与pyi文件 *

pyi文件:跟.py一样,仅仅作为一个python文件的后缀名。

pyc文件: python解释器为了提高加载模块的速度,会在__pycache__目录中生成模块编译好的字节码文件,并且对比修改时间,只有模块改变了,才会再次编译。pyc文件仅仅用于节省了启动时间,但是并不能提高程序的执行效率。

(2)模块的导入和修改 *

1.导入模块后,模块就已经被加载到内存中,此后计算对模块进行改动,读取的内容还是内存中原来的结果。

2.如果想让改动生效,可以通过“from importlib import reload”, 需要'reload 模块名'重新加载模块,改动才生效。

(3)模块的循环使用 ****

谨记模块的导入必须是单链的,不能有循环引用,如果存在循环,那么就是程序设计存在问题。

(4)dir(模块名) ***

可以获得该模块中所有的名字,而且是字符串类型的,就可以通过反射去执行它。

包是一种通过‘.模块名’来组织python模块名称空间的方式。

(1)无论是import形式还是from ... import 形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法

(2)包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)

(3)import导入文件时,产生名称空间中的名字来源与文件,import包,产生的名称空间的名字同样来源与文件,即包下的__init__.py,导入包本质就是在导入文件

注意:

1、在python3中,即使包下没有__init__.py文件,import包仍然不会报错,而在python2中,包下一定要有该文件,否则import包会报错

2、创建包的目的不是为了运行,而是被导入使用,记住,包只有模块的一种形式而已,包即模块

包A和包B下有同名模块也不会冲突,如A.a与B.a来自两个命令空间

示例环境如下:

import os

os.makedirs('glance/api')

os.makedirs('glance/cmd')

os.makedirs('glance/db')

l = []

l.append(open('glance/__init__.py','w'))

l.append(open('glance/api/__init__.py','w'))

l.append(open('glance/api/policy.py','w'))

l.append(open('glance/api/versions.py','w'))

l.append(open('glance/cmd/__init__.py','w'))

l.append(open('glance/cmd/manage.py','w'))

l.append(open('glance/db/models.py','w'))

map(lambda f:f.close() ,l)

创建目录代码

glance/ #Top-level package

├── __init__.py #Initialize the glance package

├── api #Subpackage for api

│ ├── __init__.py

│ ├── policy.py

│ └── versions.py

├── cmd #Subpackage for cmd

│ ├── __init__.py

│ └── manage.py

└── db #Subpackage for db

│ ├── __init__.py

│ └── models.py

目录结构

#文件内容

#policy.py

def get():

print('from policy.py')

#versions.py

def create_resource(conf):

print('from version.py: ',conf)

#manage.py

def main():

print('from manage.py')

#models.py

def register_models(engine):

print('from models.py: ',engine)

文件内容

从包中导入模块

(1)从包中导入模块有两种方式,但是无论哪种,无论在什么位置,都必须遵循一个原则:(凡是在导入时带点的,点的左边都必须是一个包),否则非法。

(2)对于导入后,在使用就没有这种限制,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)

(3)对比import item 和from item import name的应用场景:如果我们想直接使用name那么必须使用后者。

方式一:import

例如: 包名1.包名2.包名3.模块名

#在与包glance同级别的文件中测试

importglance.db.models

glance.db.models.register_models('mysql')"""执行结果:from models.py mysql"""

方式二:from ... import ...

例如:from 包名1.包名2 import 模块名

from 包名1.包名2.模块名 import 变量名/函数名/变量名

注意:需要注意的是from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法

#在与包glance同级别的文件中测试

from glance.db importmodels

models.register_models('mysql')"""执行结果:from models.py mysql"""

from glance.cmd importmanage

manage.main()"""执行结果:from manage.py"""

直接导入包

如果是直接导入一个包,那么相当于执行了这个包中的__init__文件

并不会帮你把这个包下面的其他包以及py文件自动的导入到内存

如果你希望直接导入包之后,所有的这个包下面的其他包以及py文件都能直接通过包来调用,那么需要你自己处理__init__文件。

__init__.py文件

不管是哪种方式,只要是第一次导入包或者是包的任何其他部分,都会依次执行包下的__init__.py文件;这个文件可以为空,但是也可以存放一些初始化包的代码。

绝对导入和相对导入

我们的最顶级包glance是写给别人用的,然后在glance包内部也会有彼此之间互相导入的需求,这时候就有绝对导入和相对导入两种方式:

绝对导入:以glance作为起始

相对导入:用. 或者.. 的方式作为起始(只能在一个包中使用,不能用于不同目录内)

绝对导入和绝对导入示例:

绝对导入:

既然导入包就是执行包下的__init__.py文件,那么尝试在啊glance的__init__.py文件中"import api",执行一下,貌似没有报错,在尝试下在包外导入,情况如何?

在包外创建一个test.py文件,在里面操作如下:importglance

glance.api

ModuleNotFoundError: No module named'api'原因:为什么还会报错?因为一个模块能不能被导入就看在sys.path中有没有路径,在哪里执行文件,sys.path永远记录该文件的目录。

(1)在glance的__init__.py文件中,sys.path的路径是:'E:\\Python练习\\包\\glance'所以能够找到同级的api

(2)但是在test文件中导入,此时sys.path的路径是:'E:\\李彦杰\\Python练习\\包'所以找不到不同层级的api,所以就会报No module name'api'解决办法一:

使用绝对路径(绝对路径为当前执行文件的目录)

(1)在glance包中的__init__.py中通过绝对路径导入:"from glance import api"(2)这样在test文件中执行,就能找到同层级的glance,再去里面找api

(3)同理,如果想使用api包中的模块,也要在api包中的__init__.py文件中导入"from glance.api import policy, veersions",

(4)现在在test文件中调用glance下的api下的policy模块就不会报错:importglance

glance.api.policy.get()

glance.api.versions.create_resource('测试')

执行结果:frompolicy.pyfromversions.py 测试

绝对导入的缺点:

如果以后包的路径发生了转移,包内的所有__init__.py文件中的绝对路径都需要改变

解决办法二:

使用相对导入

. 表示当前目录

.. 表示上一级目录

(1)在glance包中的__init__.py中通过相对路径的形式导入:

“from . importapi”

(2)同理在api包中的__init__.py中通过相对路径的形式导入:

“from . importpolicy,version”

(3)同样在test文件中调用glance下的api下的policy模块就不会报错:importglance

glance.api.policy.get()

glance.api.versions.create_resource('测试')

执行结果:frompolicy.pyfromversions.py 测试

相对导入的优点:

包发生路径转移,其中的相对路径都没有改变,所以不用逐个逐个修改。

相对导入的缺点:

但凡带着相对导入的文件,只能当做模块导入,不能作为一个脚本单独执行!!!

扩展知识:

同级目录下的包导入

需求:现在需要在bin下面的start文件中导入core目录下的main模块;怎么破?

project

├── bin#Subpackage for bin

├── __init__.py

└── start.py

├── core#Subpackage for core

├── __init__.py

└── main.py

#main.py文件中的内容:

deffunc():print("In main")

(1)、在start中直接导入,因为路径不对,所以直接报错:

import main #执行,报错ModuleNotFoundError: No module named 'main'

(2)、由上面报错我们知道肯定路径不对,那么我们想到直接将core路径加进去不就好了吗?是的,这样是可行的

importsys

path= 'E:\练习\包\core' #复制得到core的绝对路径

sys.path.append(path) #将core路径添加

import main #再次导入便不会报错

main.func() #执行结果:In main

(3)、上面的方法看似可行,但是还是有一个问题,如果我将project打包发给别人,或者我换个环境运行呢? 那么又得更改对应的path。不怎么合理,那么我们看下面的方法:

importsysprint(__file__)

ret= __file__.split('/')

base_path= '/'.join(ret[:-2])

sys.path.append(base_path)from core importmain

main.func()#In main

1、__file__ 可以得到当前文件的绝对路径,E:/练习/project/bin/start.py

2、__file__.split('/') 将当前文件的绝对路径进行处理,按照'/'分隔得到:['E:', '练习', 'project', 'bin', 'start.py']

3、'/'.join(ret[:-2]) 因为我们只需要拿到project项目的动态路径,所以进行切割,在jojn得到: E:/练习/project

4、sys.path.append(base_path) 再将得到的路径添加到sys.path中

5、from core import main 因为我们拿到的是project目录,所以导入是从当前路径的core包导入main模块

6、main.func() 最后再是模块名.方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php获取虚拟机ip,php如何获取用户的ip地址

直接上代码/*** 获取客户端IP地址*/function real_ip(){$ip $_SERVER[REMOTE_ADDR];if (isset($_SERVER[HTTP_X_FORWARDED_FOR]) && preg_match_all(#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s,$_SERVER[HTTP_X_FORWARDED_FOR], $matches)) {foreach ($matches[0] AS $xi…

sql distinct 去重复 (mysql)

DISTINCT 去重复 (运动扭伤腰。。。悲伤。。。 (▼ _ ▼) ) 首先,例如我们的表: 首先观察表: 其中第二行和第三行和第八行的name1的只是重复的,但第八行的age1确是12,与第二行和第三行不同…

如何5分钟上手使用OCR

随便打开一个Microsoft Visual Studio,新建一个WinForms项目,从下面列表中随便选择一个NET框架。net35;net40;net45;net451;net452;net46;net461;net462;net47;net471;net472;net48; netstandard2.0;netcoreapp3.1; net5.0;net6.0;创建完窗口后&#xff…

GDI与OpenGL与DirectX之间的区别

图形编程的几种技术对比: GDI,图形设备接口,MS开发的通用的windows系统图形编程接口,功能强涉及面广,一般的编程都用它。但是用来做多媒体开发就差强人意了 OPENGL是SGI开发的一套三维图形软件包,出现很早&…

HDU 5238 Calculator 线段树 中国剩余定理

题意: 给一个计算器,有一系列计算步骤,只有加,乘,幂三种运算。 有一种查询操作:查询初始值为\(x\)的时候,最终运算结果模\(29393\)的值。 有一种修改操作:可以修改第\(p\)个运算的运…

linux shell之把文本里面的;替换成\n格式输出

1 问题 一个文本里面很多中间很多;然后,现在需要把;替换成\n,然后换行打印出来 比如文件1.txt namechenyu;sexman;age27 我们可以用tr命题替换,第一个参数是需要替换的内容,第二个参数是将要替换的内容 2 实现 ca…

利用Excel VBA批量计算气象数据多个台站多年来春季和冬季降水量和平均气温

气象数据是地理数据的重要组成部分,存储量虽然不大,但是处理过程非常繁琐,长时序数据更不用说。本文总结了一个气象数据的基本处理方法。 如下图所示,气象数据的排列格式是区站号→年→月→降水量→平均气温,时间范围为1983~2012年,每一年都有台站数300多个,下面按区站…

VMware Workstation 12新建虚拟机

1、点击“创建新的虚拟机”2、选择“自定义”(初学选择典型也可以),下一步3、默认,直接下一步4、通常都是先创建虚拟机,等虚拟机创建完成后再来安装操作系统,若安装过程出现什么问题方便解决,故选择“稍后安装操作系统…

sql count用法_SQL学习笔记3:count(*)函数

1.count(*)函数用法COUNT(*) 函数返回表中的记录数,具体来说,返回值是一个数字。语法:返回表中所有记录的数量:SELECT COUNT(*) FROM table_name返回表中满足一定条件的记录的数量:SELECT COUNT(*) FROM table_name WH…

sql order by,desc和limit使用(mysql)

(。ŏ_ŏ) 首先我们来看一个表: 在此我们要进行排序,按降序排序,就是从大到小。然后我们只要查询前2条数据。 意思就是我们需要把这个表从大到小排序后,取前两条,那么我们就需要使用到order by 和desc …

Blazor University (13)组件 — 多线程渲染

原文链接:https://blazor-university.com/components/multi-threaded-rendering/多线程渲染由于 Blazor Server 应用程序中可用的线程不止一个,因此完全有可能不同的组件可以让不同的线程在其上执行代码。这在基于异步任务的操作中最常见。例如&#xff…

【Util】 时间天数增加,时间比较。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/inforstack/article/details/46516623 public static void main(String[] args) {try {DateFormat formatter new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Cale…

linux shell之$?和得到联合使用命令的结果

1 介绍 $?命令:可以得到上次执行命令的值,如果返回时0,说明执行成功,如果是其它数说明命令执行失败 联合使用命令:我们一般这样使用 value$(cat 1.txt | grep chenyu) echo $value 2 代码测试 #/bin/bashpwd"…

方法调用(车票练习)

第一步、创建一个类 //public class Tickete //{ //写一个Ticket类,有一个距离属性(本属性只读,在构造方法中赋值) //不能为负数,有一个价格属性,价格属性只读, //并且根据距离distance计算价格…

sql 之like 和通配符%,_(mysql)

(。ŏ_ŏ) like模糊查询,啥叫模糊查询? 例如:我们一个数据库里面存在在一个人叫做李二三四。我们忘记了他的名字,只记得他的姓名,那么我们就可以使用like加上通配符来查询出我们所要的结果;话说…

php邮件代码c语言,C语言实现邮件发送功能(SMTP)源码

【实例简介】C 语言编写的邮件发送器是SMTP协议的源代码和EXE执行程序均在里面使用VS2013开发环境生成,填写对应参数即可成功进行邮件发送,不用配置邮件服务器,只需一个支持SMTP协议的邮箱账号密码即可【实例截图】【核心代码】#include #inc…

【线性筛】【质因数分解】【约数个数定理】hdu6069 Counting Divisors

d(x)表示x的约数个数&#xff0c;让你求&#xff08;l,r<10^12,r-l<10^6,k<10^7&#xff09; #include<cstdio> using namespace std; #define MOD 998244353ll #define MAXP 1000100 typedef long long ll; ll x,y; int T,K; bool isNotPrime[MAXP10]; int num…

python本地库_Python学习第71课-本地建立repository仓库

【每天几分钟&#xff0c;从零入门python编程的世界&#xff01;】我们在本地建立一个repository(仓库)&#xff0c;这个repository(仓库)就是用来对我们的文件版本进行跟踪的。repository(仓库)就是通过git命令中的init命令创建的&#xff0c;想要在shell中让git命令生效&…

C#/.Net 不要再使用Aspose和iTextSharp啦!QuestPDF操作生成PDF更快更高效!

QuestPDFQuestPDF是一个开源的工具库&#xff0c;可以在.NET或者.Net Core中生成pdf文档它提供了一个布局引擎&#xff0c;设计时考虑到了完整的分页支持以及灵活性要求&#xff01;比市面上常见的Aspose和iTextSharp好用太多了&#xff01;GitHub地址安装Install-Package Ques…