第24章  高级模块话题

本章研究一些模块相关的高级概念,

1.数据隐藏技巧

2.通过__future__模块启用新的语言特性

3.__name__使用模式变量

4.过渡性模块重载

5.由名称字符串的导入

6.探索总结模块设计的话题,发现模块相关的常见错误

1.数据隐藏的技巧:

在模块中隐藏数据,python模块会导出其文件顶层所赋值的所有变量名。

没有对某一个变量名进行声明,使其在模块内可间或不可见这种概念。是没有防止客户端修改模块内变量名的方法的

python中,可以通过破坏模块名称是这个模块不能工作,但是没有这样做的。

最小化from*的破坏:_X和__all__:

在特定的情况下,把下划线放在变量名前面(例如:_X),

可以防止客户端使用from*语句导入模块名时,把其中的哪些变量名复制出去。

from*会把所有变量名复制出去,导入者可能得到超出它所需的部分(包括会覆盖导入者内的变量名的变量名)。

下划线不是“私有”的声明,我们仍可以使用其他导入形式看见并修改这类变量名,如 import。

我们可以在模块顶层把变量名的字符串列表赋值给变量__all__,已达到,隐藏命名的效果,例如:

__all__=["Error","encode","decode"]

使用此功能时,from*语句只会列__all__列表中出现的这些变量名的复制出来。

与_X惯例相反,__all__是指出要复制的变量名,而_X是指出不被复制的变量名。

python会首先寻找__all__列表,如果没有定义的话,from*就会复制出开头没有单下划线的所有变量名。

像_X一样,__all__只对from*语句有效,并不是私有声明。

2.通过__future__模块启用新的语言特性:

启用以后的语言特性,可能破坏现有代码语言方面的变动会不断引进。

一开始,是以选用扩展功能的方式出现的,默认是关闭的,可以通过下面的语句开启:

from __future__ import featurename

这个语句一般应该出现在模块文件的顶层(也许docstring之后)

因为这是以每个模块为基础,开启特殊的代码编译。

3.__name__使用模式变量:

混合用法模式:__name__和__main__,是一个特殊的与模块相关的技巧,

可以把文件作为模块导入,并独立式程序的形式运行。

每个模块都有个名为__name__的内置属性,python会自动设置该属性:

a.如果文件是以顶层程序文件执行,在启动时,__name__就会设置为字符串“__main__".

b.如果文件被导入,__name__就会改为射程客户端所了解的模块名。

结果就是模块可以检测自己的__name__,来确定他是在执行还是在导入。

例如:我们建立一个模块文件,名为runme.py,它只导出一个名为tester的函数。

def tester():

print("It's Christmas in Heaven...")

if __name__=='__main__':

tester()

这个模块定义了一个函数,让用户可以正常的导入并使用:

>>>import runme

>>>runme.tester()

It's Christmas in Heaven...

然而,这个模块也在末尾包含了档次文件以程序执行时,就会调用该函数的代码:

我们点开runme.py这个模块,会立刻调用该函数:

It's Christmas in Heaven...

实际上一个模块的__name__变量充当一个使用模式标志允许它编写成一个可导入的库和一个顶层脚本。

__name__测试时最常见的自我测试代码。

我们可以在文件末尾加一个__name__测试,把测试模块导出的程序代码放在模块中。

编写既可以作为命令行工具也可以作为工具库使用的文件时,__name__技巧非常好用。

以__name__进行单元测试:

例:我们编写一个脚本,从一组传进来的参数中计算出其最小值。

def minmax(test ,*args):

res=args[0]

for arg in args[1:]:

if(test(arg,res)):

res=arg

return res

def lessthan(x,y):

return x

def grtrthan(x,y):

return x>y

print(minmax(lessthan,4,2,1,5,6,3))

print(minmax(grtrthan,4,2,1,5,6,3))

这个脚本在末端包含了自我测试程序代码。

所以不用每次执行时,都得在交互模式命令行中重新输入搜友代码就可以惊醒测试

然而,这样写法的问题在于,每次这个文件被另一个文件作为工具导入时,

就会出现调用自我测试调用所得到的输出,现在我们用__name__来进行改进:

print('I am :',__name__)

def minmax(test ,*args):

res=args[0]

for arg in args[1:]:

if(test(arg,res)):

res=arg

return res

def lessthan(x,y):

return x

def grtrthan(x,y):

return x>y

if __name__=='__main__':

print(minmax(lessthan,4,2,1,5,6,3))

print(minmax(grtrthan,4,2,1,5,6,3))

在顶层打印__name__的值,目的是跟踪他的值。

当该文件作为顶层文件时,名字为__name__,所以运行结果为:

I am :__name__

1

6

但是我们导入这个文件时,就会:

>>>import min

I am : min

>>>min.minmax(min.lessthan.'s','p','a','m')

'a'

使用带有__name__的命令行参数:

例子见书P597

修改模块搜索路径:

之前我们知道通过环境变量python path以及可能的.pth路径文件进行定制。

现在我们介绍,python程序本身是如何修改搜索路径的。

修改sys.path(内置模块sys的path属性)的内置列表。

sys.path在程序启动时就会进行初始化,但在那之后,可以随意对其元素进行删除,附加和重设。

>>>import sys

>>>sys.payh

#我的电脑中出现了:

['', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\DLLs',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages']

>>> sys.path.append('C:\\sourcedir')

>>> import string

>>> sys.path

['', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\DLLs',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages',

'C:\\sourcedir']            #加了一个

>>>

一但做了这类修改,就会对python程序中将要导入的地方产生影响因为所有导入和文件都共享了同一个sys.path列表,

这个列表可以任意修改:

sys.path.append("")增加

sys.path=[r'd:\temp']#重置目录

但是注意,我们如果删除一些重要目录时,就无法获取一些关键性工具了,

如上面的例子sys.path=[]就无法获取string模块

另:sys方法设置只会在python会话或程序(进程)中才会存续,如果python结束,就不会保留下来,

而python path和.pth文件路径配置是保存在操作系统中,所以更为全局一点

import语句和from语句的as扩展:

书中P599-P600

模块是对象:元程序:

例子见书P601

4.过渡性模块重载:

当我们重载一个模块时,python只重新载入特殊模块的文件,它不会自动重载那些为了导入要重载文件的模块。

例如:

如果要重载模块A,并且A导入模块B和C,重载只适用于A,而不适用于B和C。

A中导入B和C的语句在重载的时候重新运行,

为了都重载,要写很多个reload(),这会使代码复杂,工程量大,所以,我们有一个更好的办法:

编写一个通用的工具来自动进行过渡性重载,

通过扫描模块的__dict__属性并检查每一项的type以找到要重新载入的嵌套模块。

这个工具函数应该递归的调用自己。

下面举一个例子:

模块reloadall.py有一个reload_all函数来自动的重载一个模块,以及该模块导入的每个模块等,

所有通往每个导入链条最低端的通路都被考虑到。

他使用字典来记录已经重载的模块,递归的遍历导入链条,以及标准库的types模块,

该模块直接为内置类型预定义type结果。

访问字典的技术在这里用来在导入是递归或冗余的时候避免循环,因为模块对象可以是一个字典键

"""

reloadall.py:transitively relaod nested modules

"""

import types

from imp import reload

def status(module):

print('reloading'+module.__name__)

def transitive_reload(module,visited):

if not module in visited:

status(module)

reload(module)

visited[module]=None

for attrobj in module.__dict__.values():

if type(attrobj)==types.ModuleType:

transitive_reload(attrobj,visited)

def reload_all(*args):

visited={}

for arg in args:

if type(arg)==types.ModuleType:

transitive_reload(arg,visited)

if __name__=='__main__':

import reloadall

reload_all(reloadall)

#输出:

reloading reloadall

reloading types

要使用这一工具,导入其reload_add 函数并将一个已经载入的模块的名称传递给它。

当文件独立的运行,其自测试代码将会测试自己,

它必须导入自己,因为他自己的名字并没有 在没有一个导入的文件中定义。

下面是这个模块对于python3.0中没写标准库模块工作的情况。

注意,os是如何由tkinter导入的,但tkinter在os之前已经导入了sys。

>>> from reloadall import reload_all        #首先我想调用我这里的模块

Traceback (most recent call last):

File "", line 1, in        #不行

ModuleNotFoundError: No module named 'reloadall'

>>> import sys

>>> sys.path

['', 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\python37.zip',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\DLLs',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37',

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages']

#发现没有这个目录

>>> sys.path.append('C:\\Users\\Administrator\\PycharmProjects\\untitled\\venv')    #手动添加目录

>>> from reloadall import reload_all        #重新调用模块  成功

>>> import os, tkinter                      #调用模块

>>>

>>> reload_all(os)                          #使用该函数

reloading os

reloading abc

reloading sys

reloading stat

reloading ntpath

reloading genericpath

>>>

>>> reload_all(tkinter)                      #使用该函数

reloading tkinter

reloading enum

reloading sys

reloading _tkinter

reloading tkinter.constants

reloading re

reloading sre_compile

reloading _sre

reloading sre_parse

reloading functools

reloading _locale

reloading copyreg

>>>

例二:见书P606

5.用名称字符串导入模块:

程序在运行时以一个字符串的形式获取想到导入的模块名称:

>>> import "string"

File "", line 1

import "string"

^

SyntaxError: invalid syntax

python 期待的不是一个字符串,而是一个变量名称

直接把该字符赋值给一个变量名称也是无效的:

x="string"

import x    #此时会找x.py文件

Error!

为了解决这个问题,我们需要使用特殊工具,从运行时生成一个字符串来动态载入一个模块。

例:

>>> modname="string"

>>> exec("import "+modname)

>>> string

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib\\string.py'>

调用成功!

exec唯一的,真正的缺点时,每次运行时它必须编译import语句,

如果他运行多次,如果使用内置的__import__函数来从一个名称字符串载入的话,代码可能会运行的更快。

效果时类似的,但是,__import__运行模块对象,因此,在这里将其赋给一个名称以保存他:

>>> modname="string"

>>> string=__import__(modname)

>>> string

'C:\\Users\\Administrator\\AppData\\Local\\Programs\\Python\\Python37\\lib\\string.py'>

6.探索总结模块设计的话题,发现模块相关的常见错误:

模块设计理念:

a.总是在python的模块内编写代码

b.模块的耦合性要降到最低:全局变量

c.最大模块的粘合性:统一目标

d.模块应该少去修改其他模块的变量

模块陷阱:

顶层代码的语句次序的重要性:

书P608

from复制变量名,而不是连接

书P609

from*会让变量语义模糊

书P610

reload不会影响from导入

书P610

reload,from以及交互模式测试

书P611

递归形式的from导入无法工作

书P612

python中每个模块都有一个名称、通过特殊变量_【有书共读01】《python学习手册》读书笔记十八...相关推荐

  1. python带我起飞_【有书共读】python带我起飞读书笔记05

    4.6 tuple(元组)类型 tuple(元组)可以理解为list(列表)的只读版.与list不同的是,元组的元素不能修改. 4.6.1 tuple 与 list 的对比 #空元素 t=()    ...

  2. python中模块是什么意思_Python中的模块是什么?3分钟搞懂Python中的模块问题

    Python 中的模块是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句,模块让你能够有逻辑地组织你的 Python 代码段.把相关的代码分配到一个模块里能 ...

  3. python sys模块作用_浅谈Python中的模块

    模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...

  4. python中的模块和包

    模块 一 什么是模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能. 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使 ...

  5. Python中各个模块的介绍和使用

    北京 | 高性能计算之GPU CUDA课程11月24-26日3天密集学习 快速带你晋级阅读全文> 作者,许胜利,Python开发工程师,任职于上海某财富管理有限公司. 在Python中有一个概念 ...

  6. python怎么调用另一个py文件的变量,Python中py文件引用另一个py文件变量的方法

    Python中py文件引用另一个py文件变量的方法 最近自己初学Python,在编程是遇到一个问题就是,怎样在一个py文件中使用另一个py文件中变量,问题如下: demo1代码 import requ ...

  7. 【python教程】(4)python中的模块

    往期回顾: [Python教程](1):认识python,环境安装以及第一个程序 [python教程](2)python中的数据类型 [python教程](3)python中的函数 python之所以 ...

  8. 关于python中requests模块导入问题-python中requests模块的使用方法

    本文实例讲述了python中requests模块的使用方法.分享给大家供大家参考.具体分析如下: 在HTTP相关处理中使用python是不必要的麻烦,这包括urllib2模块以巨大的复杂性代价获取综合 ...

  9. python哪里下载import包-详解python中的模块及包导入

    python中的导入关键字:import 以及from import 1.import import一般用于导入包以及模块. 不过有个小问题: (1)当导入的是模块的时候是可以直接可以使用模块内的函数 ...

最新文章

  1. 自学是一门艺术:踏上数据科学、人工智能和机器学习的自学之路
  2. pthread_detach 常规使用记录
  3. 今年大事:年终汇算清缴,你是退还是补?惊喜还是惊吓?
  4. bzoj千题计划219:bzoj1568: [JSOI2008]Blue Mary开公司
  5. 计算机基础知识关于进制,计算机基础知识-- 进制和编码
  6. python 常量_python学习丨变量与常量
  7. boost::graph模块实现二分图算法的测试程序
  8. Node Sass does not yet support your current environment解决
  9. Operating System-进程间互斥的方案-保证同一时间只有一个进程进入临界区(3)- TSL指令...
  10. win10系统如何解除端口占用
  11. html5的文件操作系统,目录 - 基本操作 - DirectoryEntry《 HTML5:文件系统 》
  12. Python判断一个数是否为质数
  13. UBUNTU 编译安装GEOS
  14. 12、【易混淆概念集】-第六章3 资源平衡 VS 资源平滑 进度压缩 制定进度计划 定义活动 里程碑清单
  15. 7.03maven和网络
  16. 对接环信踩坑记(环信客服+IMSDk即时通信)
  17. windows server2019远程连接win7旗舰版服务器出现内部错误
  18. 6、Hello World官网教程(TX2)第一部分
  19. 【AutoCAD For Mac 手动删除步骤】
  20. MATLAB台大郭彦甫老师课程笔记:第一课:基本操作与矩阵输入

热门文章

  1. IT行业未来几年比较有前景的10个岗位
  2. 【笔记】unity 用Helios3D制作全景VR视频
  3. 如何使用flyway
  4. 如何在Minitab Workspace中使用头脑风暴工具?
  5. ssh_crm:用户注册、登陆校验拦截器、员工拜访客户功能
  6. python iphone 文件传输_【Dpt-rp1】从iphone发送pdf到sony Dpt-rp1教程 懂python的进
  7. Android 联想,雷电,mumu,游戏饭(长尾)游戏联运SDK接入
  8. 【USACO1.1_4】★Broken Necklace 破碎的项链
  9. Download the React DevTools for a better development experience
  10. android自定义金额输入键盘_Android自定义软键盘的实现