制作wordpress静态首页,semseo,短视频素材库免费下载无水印,全自动网站制作系统一 模块介绍 1、什么是模块#xff1f; #常见的场景#xff1a;一个模块就是一个包含了一组功能的python文件,比如spam.py#xff0c;模块名为spam#xff0c;可以通过import spam使用。#在python中#xff0c;模块的使用方式都是一样的#xff0c;但其实细说的话#x…一 模块介绍 1、什么是模块 #常见的场景一个模块就是一个包含了一组功能的python文件,比如spam.py模块名为spam可以通过import spam使用。#在python中模块的使用方式都是一样的但其实细说的话模块可以分为四个通用类别
使用python编写的.py文件
已被编译为共享库或DLL的C或C扩展
把一系列模块组织到一起的文件夹注文件夹下有一个__init__.py文件该文件夹称之为包
使用C编写并链接到python解释器的内置模块 2、为何要使用模块 #1、从文件级别组织程序更方便管理
随着程序的发展功能越来越多为了方便管理我们通常将程序分成一个个的文件这样做程序的结构更清晰方便管理。这时我们不仅仅可以把这些文件当做脚本去执行还可以把他们当做模块来导入到其他的模块中实现了功能的重复利用#2、拿来主义提升开发效率
同样的原理我们也可以下载别人写好的模块然后导入到自己的项目中使用这种拿来主义可以极大地提升我们的开发效率#ps
如果你退出python解释器然后重新进入那么你之前定义的函数或者变量都将丢失因此我们通常将程序写到文件中以便永久保存下来需要时就通过python test.py方式去执行此时test.py被称为脚本script。 3、以spam.py为例来介绍模块的使用文件名spam.py,模块名spam #spam.py
print(from the spam.py)money1000def read1():print(spam模块,money)def read2():print(spam模块)read1()def change():global moneymoney0 spam.py 二 使用模块之import 1、import的使用 #模块可以包含可执行的语句和函数的定义这些语句的目的是初始化模块它们只在模块名第一次遇到导入import语句时才执行import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入python的优化手段是第一次导入后就将模块名加载到内存了后续的import语句仅是对已经加载到内存中的模块对象增加了一次引用不会重新执行模块内的语句如下 #test.py
import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次from the spam.py,当然其他的顶级代码也都被执行了,只不过没有显示效果.
import spam
import spam
import spam
执行结果
from the spam.pyps我们可以从sys.module中找到当前已经加载的模块sys.module是一个字典内部包含模块名与模块对象的映射该字典决定了导入模块时是否需要重新导入。 2、在第一次导入模块时会做三件事重复导入会直接引用内存中已经加载好的结果 #1.为源文件(spam模块)创建新的名称空间在spam中定义的函数和方法若是使用到了global时访问的就是这个名称空间。#2.在新创建的命名空间中执行模块中包含的代码见初始导入import spam提示:导入模块时到底执行了什么In fact function definitions are also ‘statements’ that are ‘executed’; the execution of a module-level function definition enters the function name in the module’s global symbol table.事实上函数定义也是“被执行”的语句模块级别函数定义的执行将函数名放入模块全局名称空间表用globals()可以查看#3.创建名字spam来引用该命名空间这个名字和变量名没什么区别都是‘第一类的’且使用spam.名字的方式可以访问spam.py文件中定义的名字spam.名字与test.py中的名字来自两个完全不同的地方。 3、被导入模块有独立的名称空间 每个模块都是一个独立的名称空间定义在这个模块中的函数把这个模块的名称空间当做全局名称空间这样我们在编写自己的模块时就不用担心我们定义在自己模块中全局变量会在被导入时与使用者的全局变量冲突 复制代码
#test.py
import spam
money10
print(spam.money)
执行结果
from the spam.py
1000复制代码 测试一:money与spam.money不冲突 #test.py
import spam
def read1():print()
spam.read1()
执行结果:
from the spam.py
spam-read1-money 1000
测试二read1与spam.read1不冲突 测试二read1与spam.read1不冲突 #test.py
import spam
money1
spam.change()
print(money)
执行结果
from the spam.py
测试三执行spam.change()操作的全局变量money仍然是spam中的 测试三执行spam.change()操作的全局变量money仍然是spam中的 4、为模块名起别名 为已经导入的模块起别名的方式对编写可扩展的代码很有用 1 import spam as sm
2 print(sm.money) 有两中sql模块mysql和oracle根据用户的输入选择不同的sql功能 #mysql.py
def sqlparse():print(from mysql sqlparse)
#oracle.py
def sqlparse():print(from oracle sqlparse)#test.py
db_typeinput(: )
if db_type mysql:import mysql as db
elif db_type oracle:import oracle as dbdb.sqlparse() View Code 假设有两个模块xmlreader.py和csvreader.py它们都定义了函数read_data(filename):用来从文件中读取一些数据但采用不同的输入格式。可以编写代码来选择性地挑选读取模块 if file_format xml:import xmlreader as reader
elif file_format csv:import csvreader as reader
datareader.read_date(filename) View Code 5、在一行导入多个模块 1 import sys,os,re 三 使用模块之from ... import... 1、from...import...的使用 1 from spam import read1,read2 2、from...import 与import的对比 #唯一的区别就是使用from...import...则是将spam中的名字直接导入到当前的名称空间中所以在当前名称空间中直接使用名字就可以了、无需加前缀spam.#from...import...的方式有好处也有坏处好处使用起来方便了坏处容易与当前执行文件中的名字冲突 验证一当前位置直接使用read1和read2就好了执行时仍然以spam.py文件全局名称空间 #测试一导入的函数read1执行时仍然回到spam.py中寻找全局变量money
#test.py
from spam import read1
money1000
read1()执行结果:
from the spam.py
spam-read1-money 1000
#测试二:导入的函数read2执行时需要调用read1(),仍然回到spam.py中找read1()
#test.py
from spam import read2
def read1():print()
read2()
执行结果:
from the spam.py
spam-read2 calling read
spam-read1-money 1000View Code 验证二如果当前有重名read1或者read2那么会有覆盖效果。 #测试三:导入的函数read1被当前位置定义的read1覆盖掉了
#test.py
from spam import read1
def read1():print()
read1()执行结果:
from the spam.pyView Code 验证三导入的方法在执行时始终是以源文件为准的 from spam import money,read1
money100 #将当前位置的名字money绑定到了100
print(money) #打印当前的名字
read1() #读取spam.py中的名字money,仍然为1000
from the spam.py
spam-read1-money 1000View Code 3、也支持as 1 from spam import read1 as read 4、一行导入多个名字 from spam import read1,read2,money 5、from...import * #from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置#大部分情况下我们的python程序不应该使用这种导入方式因为*你不知道你导入什么名字很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差在交互式环境中导入时没有问题。from spam import * #将模块spam中所有的名字都导入到当前名称空间
print(money)
print(read1)
print(read2)
print(change)
执行结果:
from the spam.py
function read1 at 0x1012e8158
function read2 at 0x1012e81e0
function change at 0x1012e8268View Code 可以使用__all__来控制*用来发布新版本在spam.py中新增一行 __all__[money,read1] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字 四 模块的重载 (了解) 考虑到性能的原因每个模块只被导入一次,放入字典sys.module中如果你改变了模块的内容你必须重启程序python不支持重新加载或卸载之前导入的模块 有的同学可能会想到直接从sys.module中删除一个模块不就可以卸载了吗注意了你删了sys.module中的模块对象仍然可能被其他程序的组件所引用因而不会被清楚。 特别的对于我们引用了这个模块中的一个类用这个类产生了很多对象因而这些对象都有关于这个模块的引用。 如果只是你想交互测试的一个模块使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename)这只能用于测试环境。 def func1():print(func1) aa.py的初始内容 1 import time,importlib
2 import aa
3
4 time.sleep(20)
5 # importlib.reload(aa)
6 aa.func1() 执行test.py 五 py文件区分两种用途:模块与脚本 #编写好的一个python文件可以有两种用途 一脚本一个文件就是整个程序用来被执行 二模块文件中存放着一堆功能用来被导入使用 #python为我们内置了全局变量__name__ 当文件被当做脚本执行时__name__ 等于__main__ 当文件被当做模块导入时__name__等于模块名 #作用用来控制.py文件在不同的应用场景下执行不同的逻辑 if __name__ __main__: #fib.pydef fib(n): # write Fibonacci series up to na, b 0, 1while b n:print(b, end )a, b b, abprint()def fib2(n): # return Fibonacci series up to nresult []a, b 0, 1while b n:result.append(b)a, b b, abreturn resultif __name__ __main__:import sysfib(int(sys.argv[1]))#执行python fib.py arguments
python fib.py 50 #在命令行 View Code 六 模块搜索路径 模块的查找顺序是内存中已经加载的模块-内置模块-sys.path路径中包含的模块 #官网链接https://docs.python.org/3/tutorial/modules.html#the-module-search-path
搜索路径
当一个命名为spam的模块被导入时解释器首先会从内建模块中寻找该名字找不到则去sys.path中找该名字sys.path从以下位置初始化
执行文件所在的当前目录
PTYHONPATH包含一系列目录名与shell变量PATH语法一样
依赖安装时默认指定的注意在支持软连接的文件系统中执行脚本所在的目录是在软连接之后被计算的换句话说包含软连接的目录不会被添加到模块的搜索路径中在初始化后我们也可以在python程序中修改sys.path,执行文件所在的路径默认是sys.path的第一个目录在所有标准库路径的前面。这意味着当前目录是优先于标准库目录的需要强调的是我们自定义的模块名不要跟python标准库的模块名重复除非你是故意的傻叉。 详细的 七 编译python文件了解 为了提高加载模块的速度强调强调强调提高的是加载速度而绝非运行速度。python解释器会在__pycache__目录中下缓存每个模块编译后的版本格式为module.version.pyc。通常会包含python的版本号。例如在CPython3.3版本下spam.py模块会被缓存成__pycache__/spam.cpython-33.pyc。这种命名规范保证了编译后的结果多版本共存。 Python检查源文件的修改时间与编译的版本进行对比如果过期就需要重新编译。这是完全自动的过程。并且编译的模块是平台独立的所以相同的库可以在不同的架构的系统之间共享即pyc使一种跨平台的字节码类似于JAVA火.NET,是由python虚拟机来执行的但是pyc的内容跟python的版本相关不同的版本编译后的pyc文件不同2.5编译的pyc文件不能到3.5上执行并且pyc文件是可以反编译的因而它的出现仅仅是用来提升模块的加载速度的不是用来加密的。 #python解释器在以下两种情况下不检测缓存
#1 如果是在命令行中被直接导入模块则按照这种方式每次导入都会重新编译并且不会存储编译后的结果python3.3以前的版本应该是这样python -m spam.py#2 如果源文件不存在那么缓存的结果也不会被使用如果想在没有源文件的情况下来使用编译后的结果则编译后的结果必须在源目录下
sh-3.2# ls
__pycache__ spam.py
sh-3.2# rm -rf spam.py
sh-3.2# mv __pycache__/spam.cpython-36.pyc ./spam.pyc
sh-3.2# python3 spam.pyc
spam#提示
1.模块名区分大小写foo.py与FOO.py代表的是两个模块
2.你可以使用-O或者-OO转换python命令来减少编译模块的大小-O转换会帮你去掉assert语句-OO转换会帮你去掉assert语句和__doc__文档字符串由于一些程序可能依赖于assert语句或文档字符串你应该在在确认需要的情况下使用这些选项。
3.在速度上从.pyc文件中读指令来执行不会比从.py文件中读指令执行更快只有在模块被加载时.pyc文件才是更快的4.只有使用import语句是才将文件自动编译为.pyc文件在命令行或标准输入中指定运行脚本则不会生成这类文件因而我们可以使用compieall模块为一个目录中的所有模块创建.pyc文件模块可以作为一个脚本使用python -m compileall编译Python源
python -m compileall /module_directory 递归着编译
如果使用python -O -m compileall /module_directory -l则只一层命令行里使用compile()函数时自动使用python -O -m compileall详见https://docs.python.org/3/library/compileall.html#module-compileall详细的 详细的 八 包介绍 1、什么是包 #官网解释
Packages are a way of structuring Python’s module namespace by using “dotted module names”
包是一种通过使用‘.模块名’来组织python模块名称空间的方式。#具体的包就是一个包含有__init__.py文件的文件夹所以其实我们创建包的目的就是为了用文件夹将文件/模块组织起来#需要强调的是1. 在python3中即使包下没有__init__.py文件import 包仍然不会报错而在python2中包下一定要有该文件否则import 包报错2. 创建包的目的不是为了运行而是被导入使用记住包只是模块的一种形式而已包的本质就是一种模块 3、注意事项 #1.关于包相关的导入语句也分为import和from ... import ...两种但是无论哪种无论在什么位置在导入时都必须遵循一个原则凡是在导入时带点的点的左边都必须是一个包否则非法。可以带有一连串的点如item.subitem.subsubitem,但都必须遵循这个原则。但对于导入后在使用时就没有这种限制了点的左边可以是包,模块函数类(它们都可以用点的方式调用自己的属性)。#2、import导入文件时产生名称空间中的名字来源于文件import 包产生的名称空间的名字同样来源于文件即包下的__init__.py导入包本质就是在导入该文件#3、包A和包B下有同名模块也不会冲突如A.a与B.a来自俩个命名空间 4、上课流程 实验一准备执行文件为test.py内容#test.pyimport aaa同级目录下创建目录aaa,然后自建空__init__.py(或者干脆建包)需求验证导入包就是在导入包下的__init__.py解决先执行看结果再在__init__.py添加打印信息后重新执行2、实验二准备基于上面的结果需求aaa.xaaa.y解决在__init__.py中定义名字x和y3、实验三准备在aaa下建立m1.py和m2.py#m1.pydef f1():print(from 1)#m2.pydef f2():print(from 2)需求aaa.m1 #进而aaa.m1.func1()aaa.m2 #进而aaa.m2.func2()
解决在__init__.py中定义名字m1和m2,先定义一个普通变量再引出如何导入模块名强调:环境变量是以执行文件为准4、实验四准备在aaa下新建包bbb需求aaa.bbb解决在aaa的__init__.py内导入名字bbb5、实验五准备在bbb下建立模块m3.py#m3.pydef f3():print(from 3)需求aaa.bbb.m3 #进而aaa.bbb.m3.f3()
解决是bbb下的名字m3因而要在bbb的__init__.py文件中导入名字m3from aaa.bbb import m36、实验六准备基于上面的结果需求:aaa.m1()aaa.m2()aaa.m3()进而实现aaa.f1()aaa.f2()aaa.f3()先用绝对导入再用相对导入解决在aaa的__init__.py中拿到名字m1、m2、m3包内模块直接的相对导入强调包的本质包内的模块是用来被导入的而不是被执行的用户无法区分模块是文件还是一个包我们定义包是为了方便开发者维护7、实验七将包整理当做一个模块移动到别的目录下操作sys.path View Code 九 包的使用 1、示范文件 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)包所包含的文件内容文件内容 文件内容 执行文件与示范文件在同级目录下 2、包的使用之import 1 import glance.db.models
2 glance.db.models.register_models(mysql) 单独导入包名称时不会导入包中所有包含的所有子模块如 #在与glance同级的test.py中
import glance
glance.cmd.manage.main()
执行结果
AttributeError: module glance has no attribute cmd 解决方法 1 #glance/__init__.py
2 from . import cmd
3
4 #glance/cmd/__init__.py
5 from . import manage 执行 1 #在于glance同级的test.py中
2 import glance
3 glance.cmd.manage.main() 3、包的使用之from ... import ... 需要注意的是from后import导入的模块必须是明确的一个不能带点否则会有语法错误如from a import b.c是错误语法 1 from glance.db import models
2 models.register_models(mysql)
3
4 from glance.db.models import register_models
5 register_models(mysql) 4、from glance.api import * 在讲模块时我们已经讨论过了从一个模块内导入所有*此处我们研究从一个包导入所有*。 此处是想从包api中导入所有实际上该语句只会导入包api下__init__.py文件中定义的名字我们可以在这个文件中定义__all___: 1 #在__init__.py中定义
2 x10
3
4 def func():
5 print(from api.__init.py)
6
7 __all__[x,func,policy] 此时我们在于glance同级的文件中执行from glance.api import *就导入__all__中的内容versions仍然不能导入。 练习 #执行文件中的使用效果如下请处理好包的导入
from glance import *get()
create_resource(a.conf)
main()
register_models(mysql) #在glance.__init__.py中
from .api.policy import get
from .api.versions import create_resourcefrom .cmd.manage import main
from .db.models import register_models__all__[get,create_resource,main,register_models] View Code 5、绝对导入和相对导入 我们的最顶级包glance是写给别人用的然后在glance包内部也会有彼此之间互相导入的需求这时候就有绝对导入和相对导入两种方式 绝对导入以glance作为起始 相对导入用.或者..的方式最为起始只能在一个包中使用不能用于不同目录内 例如我们在glance/api/version.py中想要导入glance/cmd/manage.py 1 在glance/api/version.py
2
3 #绝对导入
4 from glance.cmd import manage
5 manage.main()
6
7 #相对导入
8 from ..cmd import manage
9 manage.main() 测试结果注意一定要在于glance同级的文件中测试 1 from glance.api import versions 6、包以及包所包含的模块都是用来被导入的而不是被直接执行的。而环境变量都是以执行文件为准的 比如我们想在glance/api/versions.py中导入glance/api/policy.py有的同学一抽这俩模块是在同一个目录下十分开心的就去做了它直接这么做 1 #在version.py中
2
3 import policy
4 policy.get() 没错我们单独运行version.py是一点问题没有的运行version.py的路径搜索就是从当前路径开始的于是在导入policy时能在当前目录下找到 但是你想啊你子包中的模块version.py极有可能是被一个glance包同一级别的其他文件导入比如我们在于glance同级下的一个test.py文件中导入version.py如下 1 from glance.api import versions2 3 4 执行结果:5 ImportError: No module named policy6 7 8 9 分析:
10 此时我们导入versions在versions.py中执行
11 import policy需要找从sys.path也就是从当前目录找policy.py,
12 这必然是找不到的
13 7、包的分发了解 https://packaging.python.org/distributing/ 十 软件开发规范 #star.py
import sys,os
BASE_DIRos.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)from core import srcif __name__ __main__:src.run()
#settings.py
import osBASE_DIRos.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PATHos.path.join(BASE_DIR,db,db.json)
LOG_PATHos.path.join(BASE_DIR,log,access.log)
LOGIN_TIMEOUT5
logging配置# 定义三种日志输出格式
standard_format [%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d] \[%(levelname)s][%(message)s] #其中name为getlogger指定的名字
simple_format [%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s
id_simple_format [%(levelname)s][%(asctime)s] %(message)s# log配置字典
LOGGING_DIC {version: 1,disable_existing_loggers: False,formatters: {standard: {format: standard_format},simple: {format: simple_format},},filters: {},handlers: {#打印到终端的日志console: {level: DEBUG,class: logging.StreamHandler, # 打印到屏幕formatter: simple},#打印到文件的日志,收集info及以上的日志default: {level: DEBUG,class: logging.handlers.RotatingFileHandler, # 保存到文件formatter: standard,filename: LOG_PATH, # 日志文件maxBytes: 1024*1024*5, # 日志大小 5MbackupCount: 5,encoding: utf-8, # 日志文件的编码再也不用担心中文log乱码了},},loggers: {#logging.getLogger(__name__)拿到的logger配置: {handlers: [default, console], # 这里把上面定义的两个handler都加上即log数据既写入文件又打印到屏幕level: DEBUG,propagate: True, # 向上更高level的logger传递},},
}#src.py
from conf import settings
from lib import common
import timeloggercommon.get_logger(__name__)current_user{user:None,login_time:None,timeout:int(settings.LOGIN_TIMEOUT)}
def auth(func):def wrapper(*args,**kwargs):if current_user[user]:intervaltime.time()-current_user[login_time]if interval current_user[timeout]:return func(*args,**kwargs)name input(name: )password input(password: )dbcommon.conn_db()if db.get(name):if password db.get(name).get(password):logger.info(登录成功)current_user[user]namecurrent_user[login_time]time.time()return func(*args,**kwargs)else:logger.error(用户名不存在)return wrapperauth
def buy():print(buy...)auth
def run():print(
购物
查看余额
转账)while True:choice input(: ).strip()if not choice:continueif choice 1:buy()#db.json
{egon: {password: 123, money: 3000}, alex: {password: alex3714, money: 30000}, wsb: {password: 3714, money: 20000}}#common.py
from conf import settings
import logging
import logging.config
import jsondef get_logger(name):logging.config.dictConfig(settings.LOGGING_DIC) # 导入上面定义的logging配置logger logging.getLogger(name) # 生成一个log实例return loggerdef conn_db():db_pathsettings.DB_PATHdicjson.load(open(db_path,r,encodingutf-8))return dic#access.log
[2017-10-21 19:08:20,285][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:08:32,206][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:08:37,166][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:39,535][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:40,797][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:08:47,093][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:09:01,997][MainThread:10900][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:09:05,781][MainThread:10900][task_id:core.src][src.py:24][ERROR][用户名不存在]
[2017-10-21 19:09:29,878][MainThread:8812][task_id:core.src][src.py:19][INFO][登录成功]
[2017-10-21 19:09:54,117][MainThread:9884][task_id:core.src][src.py:19][INFO][登录成功] View Code 转载于:https://www.cnblogs.com/luckchao/p/8270483.html