• 模块


    1 什么是模块?

        一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。

    2 为何要使用模块?

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

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

    3.如何使用模块?

    3.1 import

    示例文件:spam.py,文件名spam.py,模块名spam

    复制代码
     1 #spam.py
     2 print('from the spam.py')
     3 
     4 money=1000
     5 
     6 def read1():
     7     print('spam->read1->money',money)
     8 
     9 def read2():
    10     print('spam->read2 calling read')
    11     read1()
    12 
    13 def change():
    14     global money
    15     money=0
    复制代码

    3.1.1 模块可以包含可执行的语句和函数的定义,这些语句的目的是初始化模块,它们只在模块名第一次遇到导入import语句时才执行(import语句是可以在程序中的任意位置使用的,且针对同一个模块很import多次,为了防止你重复导入,python的优化手段是:第一次导入后就将模块名加载到内存了,后续的import语句仅是对已经加载大内存中的模块对象增加了一次引用,不会重新执行模块内的语句),如下 

    复制代码
     1 #test.py
     2 import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py',当然其他的顶级代码也都被执行了,只不过没有显示效果.
     3 import spam
     4 import spam
     5 import spam
     6 
     7 '''
     8 执行结果:
     9 from the spam.py
    10 '''
    复制代码

    我们可以从sys.module中找到当前已经加载的模块,sys.module是一个字典,内部包含模块名与模块对象的映射,该字典决定了导入模块时是否需要重新导入。

    3.1.2 每个模块都是一个独立的名称空间,定义在这个模块中的函数,把这个模块的名称空间当做全局名称空间,这样我们在编写自己的模块时,就不用担心我们定义在自己模块中全局变量会在被导入时,与使用者的全局变量冲突

    复制代码
     1 #测试一:money与spam.money不冲突
     2 #test.py
     3 import spam 
     4 money=10
     5 print(spam.money)
     6 
     7 '''
     8 执行结果:
     9 from the spam.py
    10 1000
    11 '''
    复制代码
    复制代码
     1 #测试二:read1与spam.read1不冲突
     2 #test.py
     3 import spam
     4 def read1():
     5     print('========')
     6 spam.read1()
     7 
     8 '''
     9 执行结果:
    10 from the spam.py
    11 spam->read1->money 1000
    12 '''
    复制代码
    复制代码
     1 #测试三:执行spam.change()操作的全局变量money仍然是spam中的
     2 #test.py
     3 import spam
     4 money=1
     5 spam.change()
     6 print(money)
     7 
     8 '''
     9 执行结果:
    10 from the spam.py
    11 1
    12 '''
    复制代码

    3.1.3 总结:首次导入模块spam时会做三件事:

    1.为源文件(spam模块)创建新的名称空间,在spam中定义的函数和方法若是使用到了global时访问的就是这个名称空间。

    2.在新创建的命名空间中执行模块中包含的代码,见初始导入import spam

    1 提示:导入模块时到底执行了什么?
    2 
    3 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.
    4 事实上函数定义也是“被执行”的语句,模块级别函数定义的执行将函数名放入模块全局名称空间表,用globals()可以查看

    3.创建名字spam来引用该命名空间

    1 这个名字和变量名没什么区别,都是‘第一类的’,且使用spam.名字的方式可以访问spam.py文件中定义的名字,spam.名字与test.py中的名字来自两个完全不同的地方。

     3.1.4 为模块名起别名,相当于m1=1;m2=m1 

    1 import spam as sm
    2 print(sm.money)

        为已经导入的模块起别名的方式对编写可扩展的代码很有用,假设有两个模块xmlreader.py和csvreader.py,它们都定义了函数read_data(filename):用来从文件中读取一些数据,但采用不同的输入格式。可以编写代码来选择性地挑选读取模块,例如

    1 if file_format == 'xml':
    2     import xmlreader as reader
    3 elif file_format == 'csv':
    4     import csvreader as reader
    5 data=reader.read_date(filename)

    3.1.5 在一行导入多个模块

    1 import sys,os,re

    3.2 from ... import...

    3.2.1 对比import spam,会将源文件的名称空间'spam'带到当前名称空间中,使用时必须是spam.名字的方式

    而from 语句相当于import,也会创建新的名称空间,但是将spam中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了、

     1 from spam import read1,read2

    这样在当前位置直接使用read1和read2就好了,执行时,仍然以spam.py文件全局名称空间

     View Code

    如果当前有重名read1或者read2,那么会有覆盖效果。

     View Code

    需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系,如下:

    复制代码
     1 from spam import money,read1
     2 money=100 #将当前位置的名字money绑定到了100
     3 print(money) #打印当前的名字
     4 read1() #读取spam.py中的名字money,仍然为1000
     5 
     6 '''
     7 from the spam.py
     8 100
     9 spam->read1->money 1000
    10 '''
    复制代码

    3.2.2 也支持as

    1 from spam import read1 as read

    3.2.3 也支持导入多行

    1 from spam import (read1,
    2                   read2,
    3                   money)

    3.2.4 from spam import * 把spam中所有的不是以下划线(_)开头的名字都导入到当前位置,大部分情况下我们的python程序不应该使用这种导入方式,因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。而且可读性极其的差,在交互式环境中导入时没有问题。

    复制代码
     1 from spam import * #将模块spam中所有的名字都导入到当前名称空间
     2 print(money)
     3 print(read1)
     4 print(read2)
     5 print(change)
     6 
     7 '''
     8 执行结果:
     9 from the spam.py
    10 1000
    11 <function read1 at 0x1012e8158>
    12 <function read2 at 0x1012e81e0>
    13 <function change at 0x1012e8268>
    14 '''
    复制代码

    可以使用__all__来控制*(用来发布新版本)

    在spam.py中新增一行

    __all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字

    3.2.5 考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,

    有的同学可能会想到直接从sys.module中删除一个模块不就可以卸载了吗,注意了,你删了sys.module中的模块对象仍然可能被其他程序的组件所引用,因而不会被清楚。

    特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。

    如果只是你想交互测试的一个模块,使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename),这只能用于测试环境。

     aa.py的初始内容
     执行test.py

    3.3 把模块当做脚本执行 

    我们可以通过模块的全局变量__name__来查看模块名:
    当做脚本运行:
    __name__ 等于'__main__'

    当做模块导入:
    __name__=

    作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
    if __name__ == '__main__':

     View Code 

    执行

    1 #python fib.py <arguments>
    2 python fib.py 50 #在命令行
  • 相关阅读:
    HDOJ 1220 Cube
    LCIS(m*n) 最长公共上升子序列
    第二百九十七天 how can I 坚持
    第二百九十六天 how can I 坚持
    第二百九十五天 how can i 坚持
    第二百九十四天 how can I 坚持
    第二百九十三天 how can I 坚持
    第二百九十、一、二天 how can I 坚持
    第二百八十九天 how can I 坚持
    第二百八十八天 how can I坚持
  • 原文地址:https://www.cnblogs.com/zjltt/p/6933762.html
Copyright © 2020-2023  润新知