Python之模块高级话题

本文大纲:

1. 在模块中隐藏数据

有两个模块分别是:
a.py
b.py
现在要在b.py中导入模块a.py。当我们在b.py中导入a.py时,Python会导出a.py顶层所赋值的所有变量名。有时我们会有这样的需求,只要导入a.py中的部分变量名,不用全部导入,这时该怎么做呢?这时就引入我们今天讲的第一点在模块中隐藏数据

1.1 最小化 from * 的破坏:_X__all__

当我们使用 from * 在b.py导入a.py模块时,from * 会把a.py全部的变量名都复制过去,有些变量名不是我们需要的,如果a.py和b.py有同名的变量名,a.py的变量名还会覆盖b.py的变量名。
在a.py文件内的变量名前面放置单下划线,可以防止使用 from * 导入模块时,将其中的变量名复制过去。例如: _name, _age,_address ...

也可以在模块顶层把变量名的字符串列表赋值给变量 __all__,以达到类似于 _X 的隐藏效果。例如:
__all__ = ["score", "class", "school"]

_X__all__ 的区别

  • from * 会把列在 __all__ 列表中的这些变量名复制出来
  • __all__ 指出要复制的变量名,而 _X 是指出不被复制的变量名
  • Python会先找模块内的 __all__ 列表,如果没有定义的话, from * 就会复制出开头没有单下划线的所有变量名。
  • __all___X 只对 from * 语句这种形式有效,它并不是私有声明。

启用新版本的语言特性 __future__
Python中的每个新版本都会增加一些新功能,或者在原来版本的基础上做一些修改。有的在当前版本运行正常的代码,可能到了下个新版本就运行不正常了。我们可以使用 __future__ 模块,把下一个版本的新特性引入到当前版本,这样就可以在当前版本测试新版本的特性了。例如:

from __future__ import featurename

混合用法模式: __name____main__
可以把这个文件作为模块导入,并以独立程序的形式运行。每个模块都会有一个 __name__ 属性,Python会自动设置该属性。

  • 如果文件是以顶层文件执行,在启动时,__name__ 就会设置为字符串"__main__"。
  • 如果文件被导入, __name__ 就会改设成客户端所了解的模块名。

结果就是模块可以检测自己的 __name__ ,来确定它是在执行还是在导入。
下面是一个名为 runme.py 的模块文件。当此文件以程序执行时,就会调用该函数的代码,注意看print(__name__)的结果:

def tester():
    print("Hello World!")
    print(__name__)

if __name__ == '__main__':
    tester()

运行结果:

Hello World!
__main__

下面创建一个 test.py 文件,runme.py以模块的形式导入使用,注意看print(name)的结果:

import test

test.tester()

运行结果:

Hello World!
test

一个模块的 __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 < y
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))

这个脚本在末端的最后两个print语句是这个程序自我测试的代码。但是这种写法有一个问题,每次这个文件被另一个文件当做模块导入时,都会调用最后两个print语句并输出结果,这对用户体验来说很不好。现做如下改进:

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 < y
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))
posted @ 2021-02-22 14:08  狸帅  阅读(90)  评论(0编辑  收藏  举报