您的位置:新葡亰496net > 奥门新萄京娱乐场 > 新葡亰496net面向进程编制程序,铁乐学python_day

新葡亰496net面向进程编制程序,铁乐学python_day

发布时间:2019-08-02 13:08编辑:奥门新萄京娱乐场浏览(72)

    初步认识

    安装完python后,python自带一部分模块,自带的模块又称作内置模块。其中一部分模块在路径Lib下。(这里的文件夹可以看做包,可以把多个模块放进一个包里)

    新葡亰496net 1

    从模块的来源来讲,可以分三种:内置模块、自定义模块(自己定义的)、第三方模块 例如下载网上的django模块。

    从模块的运行角度看,可以分两种:直接执行称自主模块,被导入才执行称非自主模块。

     一个类型为py的文件可以作为一个模块,模块名就是文件名。模块名可以作为全局变量使用。

    python的模块和C语言中的头文件以及Java中的包很类似,用来导入已经写好的其他代码程序

    模块

    1、什么是模块?

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

      1 使用python编写的代码

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

      3 包好一组模块的包

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

    2、为什么要使用模块?

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

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

    3、如何使用模块?

    • 方式一:import
    • 方式二:from ... import ...

    大部份内容摘自授课老师的博客

    一、协程函数

    使用

     在某路径建了module.py,复制下面代码

    def fib(n):    # write Fibonacci series up to n
        a, b = 0, 1
        while a < n:
            print(a, end=' ')
            a, b = b, a b
        print()
    
    def fib2(n):   # return Fibonacci series up to n
        result = []
        a, b = 0, 1
        while a < n:
            result.append(a)
            a, b = b, a b
        return result
    

    在该路径打开解释器,导入模块,使用模块里的某个函数。

    新葡亰496net 2

    如果需要在模块里用到其他模块,需要提前导入。

    一次导入n个模块的全部功能:import module1[, module2[,... moduleN]

    单独导入模块的某个功能:from modname import name1[, name2[, ... nameN]]

    导入模块的全部功能:from modname import * 好处是不需要模块名点出来就能用。

    新葡亰496net 3

    给模块起别名:在模块名后加 as 别名

    新葡亰496net 4

     

    模块属性:__name__

    1、因为当前moduly.py模块是被导入执行的,所以它的__name__属性是模块名称

    新葡亰496net 5

    2、修改module.py ,在第一行加入 print(__name__)

    解释器执行module.py模块,喔?这次是自主模块了。

    新葡亰496net 6

     

    dir函数,查看模块可以用的函数、属性等。

    新葡亰496net 7

     

    如果模块修改了,需要借助重新加载,否则找不到修改过的东西。

    import importlib; importlib.reload(modulename)

      Python模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用 python 标准库的方法。

    import

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

    新葡亰496net 8新葡亰496net 9

    name = "我是自定义模块的内容..."def func():    print("my_module: ", name)print("模块中打印的内容...")
    

    my_module

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

    # 用import导入my_module模块import my_module>>>模块中打印的内容... # 怎么回事,竟然执行了my_module模块中的print语句import my_moduleimport my_moduleimport my_moduleimport my_moduleimport my_module>>>模块中打印的内容... # 只打印一次
    

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

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

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

    # 本地文件name = "local file"def func():    print    # 本地文件有跟被导入模块同名的变量和函数,究竟用到的是哪个呢?import my_moduleprint(my_module.name)   # 根据结果可以看出,引用的是模块里面的namemy_module.func()        # 执行的是模块里面的func()函数>>>模块中打印的内容...我是自定义模块的内容...my_module:  我是自定义模块的内容...print             # 使用的是本地的name变量func()                  # 使用的是本地的func函数>>>local filelocal file
    

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

      1、先寻找模块

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

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

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

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

    新葡亰496net 10

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

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

    # 给my_module模块取别名import my_module as smprint>>>我是自定义模块的内容...print(my_module.name)   # 取了别名后,原来的模块名就不生效了>>>NameError: name 'my_module' is not defined
    

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

    # 按照先前的做法,写一个函数,根据用户传入的序列化模块,使用对应的方法def dump:    if method == 'json':        import json        with open('dump.txt', 'wb') as f:            json.dump('xxx', f)    elif method == 'pickle':        import pickle        with open('dump.txt', 'wb') as f:            pickle.dump('xxx', f)# 上面的代码冗余度很高,如果简化代码?通过模块取别名的方式,可以减少冗余def dump:    if method == 'json':        import json as m    elif method == 'pickle':        import pickle as m    with open('dump.txt', 'wb') as f:        m.dump('dump.txt', f)
    

    如何同时导入多个模块?

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

    import osimport sysimport time
    

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

    import os, sys, my_module
    

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

    # 根据PEP8规范import osimport djangoimport 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文件作为脚本执行的时候就能够打印出来,以模块被导入时,便不会打印出来。

    OS模块复习一二

    新葡亰496net 11

    >>> import os
    >>> os.getcwd()  # 获取当前所在目录
    'D:\PortableSoft\Python35'
    
    >>> os.chdir('d:\PortableSoft')  # 改变工作目录,相当于cd命令
    >>> os.getcwd()
    'd:\PortableSoft'
    
    >>> os.curdir  # 获取'.'字符串,相当于当前目录
    '.'
    >>> os.pardir # 获取'..'字符串,相当于上级(父目录)目录
    '..'
    
    >>> import os
    >>> os.sep
    '\'
    >>> os.linesep
    'rn'
    >>> os.pathsep
    ';'
    >>> os.name
    'nt'
    
    os.system('dir')  # 直接就运行完命令了
    print(os.popen('dir').read()) # 执行的输出有返回值
    
     驱动器 E 中的卷是 VM
     卷的序列号是 4AE6-716D
    
     E:Pythonday28 的目录
    
    2018-04-25  17:21    <DIR>          .
    2018-04-25  17:21    <DIR>          ..
    2018-04-25  17:11                 4 new.txt
    2018-04-25  17:21               323 OS模块.py
                   2 个文件            327 字节
                   2 个目录 62,048,944,128 可用字节
    

    新葡亰496net 12

    print(os.path)  # <module 'ntpath' from 'D:\PortableSoft\Python35\lib\ntpath.py'>
    print(os.path.abspath(os.curdir))           # E:Pythonday28
    print(os.path.split('E:Pythonday28'))   # ('E:\Python', 'day28')
    print(os.path.abspath(os.pardir))           # E:Python
    print(os.path.dirname('E:Pythonday28'))    # E:Python
    print(os.path.basename('E:Pythonday28'))  # day28
    print(os.path.exists('E:Pythonday28'))  # True
    print(os.path.exists('E:Pythonday29'))  # False
    print(os.path.join('E:Python', 'day28', 'OS模块.py'))  # E:Pythonday28OS模块.py
    print(os.path.getmtime('E:Pythonday28'))  # 1524649925.9140468 获取到的是时间戳,所以还需要转格式化字符串的时间
    res = os.path.getmtime('E:Pythonday28')
    print(time.strftime('%Y-%m-%d %X', time.gmtime(res)))  # 2018-04-25 09:57:58
    
    补充:os.walk
    os.walk输入一个路径名称,以yield的方式(其实是一个生成器)返回一个三元组 dirpath, dirnames, filenames
    
    例子:打印输出目录树
    
    import os
    def travelTree(currentPath, count):
        '''
        以树状的方式递归显示文件目录
        :param currentPath: 要显示的目录路径
        :param count: 要显示的目录层级
        :return: 没有返回值,直接递归打印输出格式化好的文件树
        '''
        # 判断传入进来的路径存不存在,不存在直接返回None
        if not os.path.exists(currentPath):
            return
        # 判断传入进来的路径是否为文件
        if os.path.isfile(currentPath):
            # 是文件则返回文件名
            fileName = os.path.basename(currentPath)
            # 打印输出定义好的 层级制表符 拼接 树状符号 再加文件名
            print('t' * count   '├── '   fileName)
        # 当路径是一个目录时
        elif os.path.isdir(currentPath):
            # 打印输出定义好的 层级制表符 拼接 树状符号 再加目录路径
            print('t' * count   '├── '   currentPath)
            # 将目录以列表方式放入一个列表中
            pathList = os.listdir(currentPath)
            # for循环并且递归重复前面操作
            for eachPath in pathList:
                travelTree(currentPath   '/'   eachPath, count   1)
    

    1 协程函数的定义

    协程函数就是使用了yield表达式形成的生成器

    实例:

    def eater(name):
        print('%s eat food' %name)
        while True:
            food = yield
        print('done')
    
    g = eater('Yim')
    print(g)
    
    #执行结果:
    <generator object eater at 0x000000000227FEB8>                  #证明g现在是一个生成器函数
    

    模块的路径

    在没有指定模块的路径时,导入时会去什么路径下找模块呢?

    1、当前py脚本的同级路径,即A脚本是ALib下,则会去ALib目录下找

    2、环境变量 path

    3、依赖于安装时初始化的一些路径,例如上面的Lib目录。

    这里有个默认查找模块路径讨论:

     

    官网参考:

     

    模块的导入

    模块的导入需要下面几个关键字

      from,import,as

    from ... import ...

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

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

    from my_module import name, funcprint     # 此时引用模块中的对象时,就不要再加上模块名了。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...'def func():    print("my_module: ", name)# 在其他文件中通过import *导入所有属性from my_module import *print>>>My module...func()>>>NameError: name 'func' is not defined
    

    拓展知识点:

      pyc文件与pyi文件 *

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

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

      模块的导入和修改*

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

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

      模块的循环使用 ****

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

      dir ***

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

    什么是模块?

    常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
    但其实import加载的模块分为四个通用类别: 
      1 使用python编写的代码(.py文件)
      2 已被编译为共享库或DLL的C或C 扩展
      3 包好一组模块的包
      4 使用C编写并链接到python解释器的内置模块

    2 协程函数的赋值

    第一阶段:next()初始化函数,让函数暂停在yield位置

    第二阶段:send()给yield传值

    next()和send()都是让函数在上次暂停的位置继续执行。next是让函数初始化,send会给yield赋值并触发下一次代码执行

    实例:

    def eater(name):
        print('%s start to eat food' %name)
        while True:
            food = yield
            print('%s eat %s' %(name,food))
    
    e = eater('Yim')
    
    next(e)                             #初始化,等同于e.send(None)
    e.send('米饭')                      #给yield传值
    e.send('大饼')
    
    #执行结果
    Yim start to eat food
    Yim eat 米饭
    Yim eat 大饼
    
    def eater(name):
        print('%s start to eat food' %name)
        food_list = []
        while True:
            food = yield food_list
            food_list.append(food)
            print('%s eat %s' %(name,food))
    
    e = eater('Yim')
    
    next(e)                  #初始化
    print(e.send('米饭'))          #1、给yield传值   2、继续往下执行,直到再次碰到yield,然后暂停并且把yield后的返回值当做本次调用的返回值
    print(e.send('大饼'))
    
    #执行结果
    Yim start to eat food
    Yim eat 米饭
    ['米饭']
    Yim eat 大饼
    ['米饭', '大饼']
    

    import 语句

    想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:

    import module1[, module2[,... moduleN]

    当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入
    搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support,需要把命令放在脚本的顶端:
    support.py 文件代码为:

    # Filename: support.py
    
    def print_func( par ):
        print ("Hello : ", par)
        return
    

    test.py 引入 support 模块:

    # Filename: test.py
    
    # 导入模块
    import support
    
    # 现在可以调用模块里包含的函数了 
    support.print_func("Runoob") # Hello :  Runoob
    

    调用模块的格式为: 模块名.方法

      注:为什么必须加上模块名调用呢?   

    因为可能存在这样一种情况:在多个模块中含有相同名称的函数,此时如果只是通过函数名来调用,解释器无法知道到底要调用哪个函数。所以如果像上述这样引入模块的时候,调用函数必须加上模块名

    一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。

    当我们使用import语句的时候,Python解释器是怎样找到对应的文件的呢?

    这就涉及到Python的搜索路径,搜索路径是由一系列目录名组成的,Python解释器就依次从这些目录中去寻找所引入的模块。
    这看起来很像环境变量,事实上,也可以通过定义环境变量的方式来确定搜索路径。

    搜索顺序是:

    • 当前目录
    • 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。
    • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/
    • 模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

      搜索路径是在Python编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在sys模块中的path变量,做一个简单的实验,在交互式解释器中,输入以下代码:

    >>> import sys
    >>> sys.path
    ['', 'D:\Python\python36.zip', 'D:\Python\DLLs', 'D:\Python\lib', 'D:\Python', 'D:\Python\lib\site-packages']
    >>> 
    

      sys.path 输出是一个列表,其中第一项是空串'',代表当前目录(若是从一个脚本中打印出来的话,可以更清楚地看出是哪个目录),亦即我们执行python解释器的目录(对于脚本的话就是运行的脚本所在的目录)。

      因此若像我一样在当前目录下存在与要引入模块同名的文件,就会把要引入的模块屏蔽掉。

      了解了搜索路径的概念,就可以在脚本中修改sys.path来引入一些不在搜索路径中的模块。如使用sys.path.append添加自定义的位置

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

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

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

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

      注意:

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

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

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

    示例环境如下:

    新葡亰496net 13新葡亰496net 14

    import osos.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
    

    创建目录代码新葡亰496net 15新葡亰496net 16

    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
    

    目录结构新葡亰496net 17新葡亰496net 18

    #文件内容#policy.pydef get():    print('from policy.py')#versions.pydef create_resource:    print('from version.py: ',conf)#manage.pydef main():    print('from manage.py')#models.pydef register_models:    print('from models.py: ',engine)
    

    文件内容

    为何要使用模块?

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

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

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

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

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

    3 用装饰器初始化协程函数

    def init(func):
        def wrapper(*args,**kwargs):
            res = func(*args,**kwargs)
            next(res)
            return res
        return wrapper
    
    @init
    def eater(name):
        print('%s start to eat food' %name)
        food_list = []
        while True:
            food = yield food_list
            food_list.append(food)
            print('%s eat %s' %(name,food))
    
    e = eater('Yim')
    print(e.send('米饭'))
    print(e.send('大饼'))
    

     

    from…import 语句

      Python的from语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:

    from modname import name1[, name2[, ... nameN]]

    例如,要导入模块fib的fibonacci函数,使用如下语句:

        from fib import fibonacci
    

    注:不会把整个fib模块导入到当前的命名空间中,它只会将fib里的fibonacci单个引入

    • from … import *

    把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

    from modname import *

    注意
    这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。

    从包中导入模块

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

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

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

    方式一:import

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

    # 在与包glance同级别的文件中测试import glance.db.modelsglance.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 import modelsmodels.register_models('mysql')"""执行结果:from models.py mysql"""from glance.cmd import managemanage.main()"""执行结果:from manage.py"""
    

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

    1.为源文件(导入的module模块)创建新的名称空间,在当中定义的函数和方法若是使用到了global时访问的就是这个名称空间。
    2.在新创建的命名空间中执行模块中包含的代码;

    导入模块时到底执行了什么?
    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.创建名字用导入的module名来引用该命名空间
    这个名字和变量名没什么区别,都是‘第一类的’,且使用导入的module名字的方式可以访问该py文件中定义的名字,被导入的py内的.名字与文件中的名字来自两个完全不同的地方。

    二、 面向过程编程

    面向过程的编程思想:流水线式的编程思想,在设计程序时,需要把整个流程设计出来

    优点:

      体系结构更清晰

      简化程序的复杂度

    缺点:

      可扩展性差

    应用场景:

      Linux内核、git、httpd、shell脚本

    实例:

    # grep -rl 'error' /dir
    
    import os
    
    #初始化装饰器
    def init(func):
        def wrapper(*args,**kwargs):
            g=func(*args,**kwargs)
            next(g)
            return g
        return wrapper
    
    #1、找到所有文件的绝对路径 --os.walk
    @init
    def search(target):
        while True:
            filepath=yield
            g=os.walk(filepath)
            for pardir,_,files in g:
                for file in files:                      #对最后一个元素进行遍历,这些都是文件
                    abspath=r'%s%s' %(pardir,file)
                    target.send(abspath)
    
    #2、打开文件 --open
    @init
    def opener(target):
        while True:
            abspath=yield                           #  接收search传递的路径
            with open(abspath,'rb') as f:
                target.send((abspath,f))            # send多个用元组的方式,为了把文件的路径传递下去
    
    #3、循环读取每一行内容 --for line in f
    @init
    def cat(target):
        while True:
            abspath,f=yield #(abspath,f)
            for line in f:
                res=target.send((abspath,line))     # 同时传递文件路径和每一行的内容
                if res:break
    
    #4、过滤关键字 --if 'error' in line
    @init
    def grep(pattern,target):           # # patter是过滤的参数
        tag=False                       #为了去掉重复的文件路径,因为一个文件中存在多个error关键字
        while True:
            abspath,line=yield tag
            tag=False
            if pattern in line:
                target.send(abspath)    # 传递有相应内容的文件路径
                tag=True
    
    #5、打印该行属于的文件名
    @init
    def printer():
        while True:
            abspath=yield
            print(abspath)
    
    g = search(opener(cat(grep('os'.encode('utf-8'), printer()))))
    g.send(r'F:PythonCode')
    

     

    From…import...as

    as是为函数或模块重命名

    >>> import time as Text
    >>> import time as tt
    >>> time.sleep(1)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    NameError: name 'time' is not defined
    >>> tt.sleep(1)
    >>> from time import sleep as sp
    >>> sleep(1)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    NameError: name 'sleep' is not defined
    >>> sp(1)
    

    直接导入包

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

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

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

    __init__.py文件

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

    绝对导入和相对导入

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

    绝对导入:以glance作为起始

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

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

    绝对导入:    既然导入包就是执行包下的__init__.py文件,那么尝试在啊glance的__init__.py文件中"import api",执行一下,貌似没有报错,在尝试下在包外导入,情况如何?    在包外创建一个test.py文件,在里面操作如下:    import glance    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    同理,如果想使用api包中的模块,也要在api包中的__init__.py文件中导入"from glance.api import policy, veersions",    (4)现在在test文件中调用glance下的api下的policy模块就不会报错:        import glance        glance.api.policy.get()        glance.api.versions.create_resource('测试')        执行结果:            from policy.py            from versions.py 测试绝对导入的缺点:如果以后包的路径发生了转移,包内的所有__init__.py文件中的绝对路径都需要改变解决办法二:    使用相对导入        . 表示当前目录        .. 表示上一级目录    (1)在glance包中的__init__.py中通过相对路径的形式导入:     “from . import api”    (2)同理在api包中的__init__.py中通过相对路径的形式导入:     “from . import policy,version”    (3)同样在test文件中调用glance下的api下的policy模块就不会报错:        import glance        glance.api.policy.get()        glance.api.versions.create_resource('测试')        执行结果:            from policy.py            from versions.py 测试相对导入的优点:    包发生路径转移,其中的相对路径都没有改变,所以不用逐个逐个修改。相对导入的缺点:    但凡带着相对导入的文件,只能当做模块导入,不能作为一个脚本单独执行!!!
    

    扩展知识:

      同级目录下的包导入

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

    project├── bin                 #Subpackage for bin    ├── __init__.py    └── start.py├── core                #Subpackage for core    ├── __init__.py    └── main.py
    
    # main.py文件中的内容:def func():    print("In main")
    
    、在start中直接导入,因为路径不对,所以直接报错:
    
    import main # 执行,报错ModuleNotFoundError: No module named 'main'
    
    、由上面报错我们知道肯定路径不对,那么我们想到直接将core路径加进去不就好了吗?是的,这样是可行的
    
    import syspath = 'E:练习包core'   # 复制得到core的绝对路径sys.path.append     # 将core路径添加import main         # 再次导入便不会报错main.func()         # 执行结果:In main
    
    、上面的方法看似可行,但是还是有一个问题,如果我将project打包发给别人,或者我换个环境运行呢?   那么又得更改对应的path。不怎么合理,那么我们看下面的方法:
    
    import sysprint(__file__)ret = __file__.split('/')base_path = '/'.join(ret[:-2])sys.path.append(base_path)from core import mainmain.func()     # In main
    
     1、__file__ 可以得到当前文件的绝对路径,E:/练习/project/bin/start.py
    
     2、__file__.split 将当前文件的绝对路径进行处理,按照'/'分隔得到:['E:', '练习', 'project', 'bin', 'start.py']
    
     3、'/'.join 因为我们只需要拿到project项目的动态路径,所以进行切割,在jojn得到: E:/练习/project
    
     4、sys.path.append(base_path) 再将得到的路径添加到sys.path中
    
     5、from core import main   因为我们拿到的是project目录,所以导入是从当前路径的core包导入main模块
    
     6、main.func()  最后再是模块名.方法。
    

    为模块起别名:

    为模块名起别名,相当于json=seq;pickle=seq

    示范用法一:
    有两中sql模块mysql和oracle,根据用户的输入,选择不同的sql功能

    #mysql.py
    def sqlparse():
        print('from mysql sqlparse')
    #oracle.py
    def sqlparse():
        print('from oracle sqlparse')
    
    #test.py
    db_type=input('>>: ')
    if db_type == 'mysql':
        import mysql as db
    elif db_type == 'oracle':
        import oracle as db
    
    db.sqlparse() 
    
    示范用法二: 
    为已经导入的模块起别名的方式对编写可扩展的代码很有用,
    假设有两个模块xmlreader.py和csvreader.py,
    它们都定义了函数read_data(filename):用来从文件中读取一些数据,但采用不同的输入格式。
    可以编写代码来选择性地挑选读取模块,例如
    
    if file_format == 'xml':
         import xmlreader as reader
    elif file_format == 'csv':
         import csvreader as reader
    data=reader.read_date(filename)
    
    from ... import...
    对比import my_module,会将源文件的名称空间'my_module'带到当前名称空间中,使用时必须是my_module.名字的方式。
    而from 语句相当于import,也会创建新的名称空间,
    但是from是将my_module中的名字直接导入到当前的名称空间中,
    在当前名称空间中,直接使用名字就可以了。
    
    例:from math import pi
    
    这样在当前位置直接使用pi就好了,执行时,仍然回math文件全局名称空间寻找名字pi。
    需要特别强调的一点是:python中的变量赋值不是一种存储操作,而只是一种绑定关系。
    from同样支持as,起别名。
    
    另外
    from my_module import * 把my_module中所有不是以下划线(_)开头的名字都导入到当前位置,
    大部分情况下我们的python程序不应该使用这种导入方式,
    因为*你不知道你导入什么名字,很有可能会覆盖掉你之前已经定义的名字。
    而且可读性极其的差,在交互式环境中导入时没有问题。
    
    在my_module.py中新增一行
    __all__=['money','read1'] 
    #这样在另外一个文件中用from my_module import * 导入的是列表中规定的两个名字。
    

    三、函数的递归调用

    在调用一个函数的过程中,直接或间接的调用了函数本身,就叫递归调用

    执行有两个阶段:递推和回溯

    递归的效率低,需要在进入下一次递归时保留当前的状态,解决方法是尾递归,即在函数的最后一步(而非最后一行)调用自己,但是python又没有尾递归,且对递归层级做了限制

    1. 必须有一个明确的结束条件

    2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

    3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)

    #直接
    def func():
        print('from func')
        func()
    
    func()
    
    
    #间接
    def foo():
        print('from foo')
        bar()
    
    def bar():
        print('from bar')
        foo()
    
    foo()
    
    # salary(5)=salary(4) 300
    # salary(4)=salary(3) 300
    # salary(3)=salary(2) 300
    # salary(2)=salary(1) 300
    # salary(1)=100
    #
    # salary(n)=salary(n-1) 300     n>1
    # salary(1) =100                       n=1
    
    def salary(n):
        if n == 1:
            return 100
        return salary(n-1) 300
    
    print(salary(5))    
    

     

    深入模块

      模块除了方法定义,还可以包括可执行的代码。这些代码一般用来初始化这个模块。这些代码只有在第一次被导入时才会被执行。

      每个模块有各自独立的符号表,在模块内部为所有的函数当作全局符号表来使用。

      所以,模块的作者可以放心大胆的在模块内部使用这些全局变量,而不用担心把其他用户的全局变量搞花。

      从另一个方面,当你确实知道你在做什么的话,你也可以通过 modname.itemname 这样的表示法来访问模块内的函数。

      模块是可以导入其他模块的。在一个模块(或者脚本,或者其他地方)的最前面使用 import 来导入一个模块,当然这只是一个惯例,而不是强制的。被导入的模块的名称将被放入当前操作的模块的符号表中。

    模块的加载与修改

    考虑到性能的原因,每个模块只被导入一次,放入字典sys.modules中,
    如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块,
    有的同学可能会想到直接从sys.modules中删除一个模块不就可以卸载了吗,
    注意了,你删了sys.modules中的模块对象仍然可能被其他程序的组件所引用,因而不会被清除。
    特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。

    如果只是你想交互测试的一个模块,使用 importlib.reload(), 
    e.g. import importlib; importlib.reload(modulename),这只能用于测试环境。
    
    把模块当做脚本执行 
    我们可以通过模块的全局变量__name__来查看模块名:
    
    当做脚本运行:
    __name__ 等于'__main__'
    
    当做模块导入:
    __name__= 模块名
    
    作用:用来控制.py文件在不同的应用场景下执行不同的逻辑
    if __name__ == '__main__':
    
    模块搜索路径
    python解释器在启动时会自动加载一些模块,可以使用sys.modules查看。
    
    在第一次导入某个模块时(比如my_module),
    会先检查该模块是否已经被加载到内存中(当前执行文件的名称空间对应的内存),如果有则直接引用;
    如果没有,解释器则会查找同名的内建模块,如果还没有找到就从sys.path给出的目录列表中依次寻找my_module.py文件。
    
    所以总结模块的查找顺序是:内存中已经加载的模块->内置模块->sys.path路径中包含的模块.
    
    sys.path的初始化的值来自于:
    The directory containing the input script (or the current directory when no file is specified).
    PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
    The installation-dependent default.
    
    需要特别注意的是:我们自定义的模块名不应该与系统内置模块重名。虽然每次都说,但是仍然会有人不停的犯错。 
    在初始化后,python程序可以修改sys.path,路径放到前面的优先于标准库被加载。
    1 >>> import sys
    2 >>> sys.path.append('/a/b/c/d')
    3 >>> sys.path.insert(0,'/x/y/z') #排在前的目录,优先被搜索
    
    注意:搜索时按照sys.path中从左到右的顺序查找,位于前的优先被查找,
    sys.path中还可能包含.zip归档文件和.egg文件,python会把.zip归档文件当成一个目录去处理。
    
    至于.egg文件是由setuptools创建的包,这是按照第三方python库和扩展时使用的一种常见格式,
    .egg文件实际上只是添加了额外元数据(如版本号,依赖项等)的.zip文件。
    需要强调的一点是:只能从.zip文件中导入.py,.pyc等文件。
    使用C编写的共享库和扩展块无法直接从.zip文件中加载(此时setuptools等打包系统有时能提供一种规避方法),
    且从.zip中加载文件不会创建.pyc或者.pyo文件,因此一定要事先创建他们,来避免加载模块是性能下降。
    

    官网链接:
    搜索路径:
    当一个命名为my_module的模块被导入时,解释器首先会从内建模块中寻找该名字,找不到,则去sys.path中找该名字。

    四、模块

    如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了。为此 Python 提供了一个办法,把这些定义存放在文件中,为一些脚本或者交互式的解释器实例使用,这个文件被称为模块。

    模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是Python标准库的方法

    __name__属性 ##

      一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用**__name__属性来使该程序块仅在该模块自身运行时执行**。

    if __name__ == '__main__':
       print('程序自身在运行')
    else:
       print('我来自另一模块')
    

    注:每个模块都有一个__name__属性,当其值是'main'时,表明该模块自身在运行,否则是被引入。

    sys.path从以下位置初始化:

    1)执行文件所在的当前目录
    2)PTYHONPATH(包含一系列目录名,与shell变量PATH语法一样)
    3)依赖安装时默认指定的

    注意:在支持软连接的文件系统中,执行脚本所在的目录是在软链接之后被计算的,
    换句话说,包含软链接的目录不会被添加到模块的搜索路径中。

    在初始化后,我们也可以在python程序中修改sys.path,执行文件所在的路径默认是sys.path的第一个目录,
    在所有标准库路径的前面。这意味着,当前目录是优先于标准库目录的,
    需要强调的是:我们自定义的模块名不要跟python标准库的模块名重复。

    end
    2018-4-27

    1 import语句

    import加载的模块分为四个通用类别:

    1. 使用Python编写的代码(.py文件)
    2. 已被编译为共享库或DLL的C或C 扩展
    3. 包好一组模块的包
    4. 使用C编写并链接到Python解释器的内置模块

    import语法:

           import module1[, module2[,... moduleN]

    当解释器遇到import语句,如果模块在当前的搜索路径就会被导入,搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support,需要把命令放在脚本的顶端:

    support.py 文件代码为:

    def print_func( par ):
        print ("Hello : ", par)
      return
    

    test.py引入support模块:

    import support              #导入模块
    
    support.print_func('Yim')   #现在可以调用模块里包含的函数了
    
    #执行结果
    Hello :  Yim
    

    还可以给模块起一个别名:

    import support as s1
    
    s1.print_func('Yim')
    

    一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行(可以使用sys.modules查看验证):

    import support
    import support
    import support
    
    support.print_func('Yim')
    
    #执行结果:
    Hello :  Yim
    

    dir() 函数

      内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回:

    >>> import os
    >>> import sys
    >>> dir()
    ['__builtins__', '__doc__', '__name__', 'os', 'sys']
    >>> dir(os)
    ['DirEntry', 'F_OK', 'MutableMapping', 'O_APPEND', 'O_BINARY', 'O_CREAT', 'O_EXCL', 'O_NOINHERIT', 'O_RANDOM', 'O_RDONLY', 'O_RDWR', 'O_SEQUENTIAL', 'O_SHORT_LIVED', 'O_TEMPORARY', 'O_TEXT', 'O_TRUNC', 'O_WRONLY', 'P_DETACH', 'P_NOWAIT', 'P_NOWAITO', 'P_OVERLAY', 'P_WAIT', 'PathLike', 'R_OK', 'SEEK_CUR', 'SEEK_END', 'SEEK_SET', 'TMP_MAX', 'W_OK', 'X_OK', '_Environ', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_execvpe', '_exists', '_exit', '_fspath', '_get_exports_list', '_putenv', '_unsetenv', '_wrap_close', 'abc', 'abort', 'access', 'altsep', 'chdir', 'chmod', 'close', 'closerange', 'cpu_count', 'curdir', 'defpath', 'device_encoding', 'devnull', 'dup', 'dup2', 'environ', 'errno', 'error', 'execl', 'execle', 'execlp', 'execlpe', 'execv', 'execve', 'execvp', 'execvpe', 'extsep', 'fdopen', 'fsdecode', 'fsencode', 'fspath', 'fstat', 'fsync', 'ftruncate', 'get_exec_path', 'get_handle_inheritable', 'get_inheritable', 'get_terminal_size', 'getcwd', 'getcwdb', 'getenv', 'getlogin', 'getpid', 'getppid', 'isatty', 'kill', 'linesep', 'link', 'listdir', 'lseek', 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', 'pathsep', 'pipe', 'popen', 'putenv', 'read', 'readlink', 'remove', 'removedirs', 'rename', 'renames', 'replace', 'rmdir', 'scandir', 'sep', 'set_handle_inheritable', 'set_inheritable', 'spawnl', 'spawnle', 'spawnv', 'spawnve', 'st', 'startfile', 'stat', 'stat_float_times', 'stat_result', 'statvfs_result', 'strerror', 'supports_bytes_environ', 'supports_dir_fd', 'supports_effective_ids', 'supports_fd', 'supports_follow_symlinks', 'symlink', 'sys', 'system', 'terminal_size', 'times', 'times_result', 'truncate', 'umask', 'uname_result', 'unlink', 'urandom', 'utime', 'waitpid', 'walk', 'write']
    >>> dir(sys)
    ['__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'set_asyncgen_hooks', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']
    >>> 
    

    2 from…import*语句

    优点:使用源文件内的名字时无需加前缀,使用方便

    缺点:容易与当前文件的名称空间内的名字混淆

    把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:

    from modname import *               #不推荐使用
    

    下面只导入support模块里面的print_func函数:

    from support import print_func      #可以用逗号分隔,写上多个函数名
    
    print_func('Yim')                   #直接执行print_func函数
    

    也可以起别名:

    from support import print_func as p1
    
    p1('Yim')
    

    可以使用__all__来控制*,修改support.py文件:

    __all__ = [print_func]                  #可以在列表内添加多个函数名
    
    def print_func( par ):
        print ("Hello : ", par)
        return
    

    test.py文件如下:

    from support import *
    
    print_func('Yim')                       #执行结果报错,NameError: name 'print_func' is not defined
    

    标准模块

      Python 本身带着一些标准的模块库,这些模块直接被构建在解析器里,这些虽然不是一些语言内置的功能,但是他却能很高效的使用,甚至是系统级调用也没问题。

      这些组件会根据不同的操作系统进行不同形式的配置,比如 winreg 这个模块就只会提供给 Windows 系统。

    3 模块的搜索路径

    搜索路径是由一系列目录名组成的,Python解释器就依次从这些目录中去寻找所引入的模块

    搜索路径是在Python编译或安装的时候确定的,安装新的库应该也会修改。搜索路径被存储在sys模块中的path变量

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

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

    import sys
    
    print(sys.path)
    
    #执行结果:
    ['F:\Python\Code\模块', 'F:\Python', 'C:\Python36\python36.zip', 'C:\Python36\DLLs', 'C:\Python36\lib', 'C:\Python36', 'C:\Python36\lib\site-packages']
    

    在脚本中修改sys.path,引入一些不在搜索路径中的模块

    import sys
    
    print(sys.path)
    
    sys.path.append('F:\Python\Code\不常用模块')
    # sys.path.insert(0,'F:\Python\Code\不常用模块')        #也可以使用insert,排在前的目录会优先被搜索
    
    print(sys.path)
    
    #执行结果
    ['F:\Python\Code\模块', 'F:\Python\2017-18s', 'C:\Python36\python36.zip', 'C:\Python36\DLLs', 'C:\Python36\lib', 'C:\Python36', 'C:\Python36\lib\site-packages']
    ['F:\Python\Code\模块', 'F:\Python\2017-18s', 'C:\Python36\python36.zip', 'C:\Python36\DLLs', 'C:\Python36\lib', 'C:\Python36', 'C:\Python36\lib\site-packages', 'F:\Python\Code\不常用模块']
    

    以下是官方文档:

    #官网链接:https://docs.python.org/3/tutorial/modules.html#the-module-search-path
    搜索路径:
    当一个命名为spam的模块被导入时
        解释器首先会从内建模块中寻找该名字
        找不到,则去sys.path中找该名字
    
    sys.path从以下位置初始化
        1 执行文件所在的当前目录
        2 PYTHONPATH(包含一系列目录名,与shell变量PATH语法一样)
        3 依赖安装时默认指定的
    
    注意:在支持软连接的文件系统中,执行脚本所在的目录是在软连接之后被计算的,换句话说,包含软连接的目录不会被添加到模块的搜索路径中
    
    在初始化后,我们也可以在python程序中修改sys.path,执行文件所在的路径默认是sys.path的第一个目录,在所有标准库路径的前面。这意味着,当前目录是优先于标准库目录的,需要强调的是:我们自定义的模块名不要跟python标准库的模块名重复,除非你是故意的
    

      包是一种管理 Python 模块命名空间的形式,采用"点模块名称"。
      比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B 。就好像使用模块的时候,你不用担心不同模块之间的全局变量相互影响一样,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况。
      这样不同的作者都可以提供 NumPy 模块,或者是 Python 图形库。

      不妨假设你想设计一套统一处理声音文件和数据的模块(或者称之为一个"包")。
      现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如: .wav,:,:,),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。
      并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所你还需要一组怎么也写不完的模块来处理这些操作。

      这里给出了一种可能的包结构(在分层的文件系统中):

    sound/                          顶层包
          __init__.py               初始化 sound 包
          formats/                  文件格式转换子包
                  __init__.py
                  wavread.py
                  wavwrite.py
                  aiffread.py
                  aiffwrite.py
                  auread.py
                  auwrite.py
                  ...
          effects/                  声音效果子包
                  __init__.py
                  echo.py
                  surround.py
                  reverse.py
                  ...
          filters/                  filters 子包
                  __init__.py
                  equalizer.py
                  vocoder.py
                  karaoke.py
                  ...
    

      在导入一个包的时候,Python 会根据 sys.path 中的目录来寻找这个包中包含的子目录。
      目录只有包含一个叫做 init.py 的文件才会被认作是一个包(在python2中是这样,python3中已经不要求了),主要是为了避免一些滥俗的名字(比如叫做 string)不小心的影响搜索路径中的有效模块。
      最简单的情况,**放一个空的 :file:__新葡亰496net面向进程编制程序,铁乐学python_day28_模块学习3。init__.py就可以了**。当然这个文件中也可以包含一些初始化代码或者为(将在后面介绍的) __all__变量赋值。

      用户可以每次只导入一个包里面的特定模块,比如:

    import sound.effects.echo
    

    这将会导入子模块:sound.effects.echo。 他必须使用全名去访问:

    sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
    

    还有一种导入子模块的方法是:

    from sound.effects import echo
    

    这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:

    echo.echofilter(input, output, delay=0.7, atten=4)
    

    还有一种变化就是直接导入一个函数或者变量:

    from sound.effects.echo import echofilter
    

    同样的,这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:

    echofilter(input, output, delay=0.7, atten=4)
    

      注意当使用from package import item这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量
      import语法会首先把item当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,恭喜,一个:exc:ImportError 异常被抛出了。
      反之,如果使用形如import item.subitem.subsubitem这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。

    4 __name__属性

    一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。

    if __name__ == '__main__':                      #文件当做脚本运行时,__name__ 等于'__main__'
       print('程序自身在运行')
    else:
       print('我来自另一模块')
    
    #执行结果
    程序自身在运行 
    
    #交互式,导入模块
    >>> import support
    我来自另一模块
    

    说明: 每个模块都有一个__name__属性,当其值是'__main__'时,表明该模块自身在运行,否则是被引入。

    常用实例:

    def func1():
        print('from func1')
    
    def func2():
        print('from func2')
    
    if __name__ == '__main__':
       func1()
       func2()
    

     

    from sound.effects import *

      Python 会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。但是很不幸,这个方法在 Windows平台上工作的就不是非常好,因为Windows是一个大小写不区分的系统。
      在这类平台上,没有人敢担保一个叫做 ECHO.py 的文件导入为模块 echo 还是 Echo 甚至 ECHO。

    为了解决这个问题,只能包作者提供一个精确的包的索引了

    导入语句遵循如下规则:
      如果包定义文件 init.py 存在一个叫做** all** 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。

      如果 **all 没有定义*,那么使用from sound.effects import 这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包sound.effects和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码)。

      通常我们并不主张使用*这种方法来导入模块,因为这种方法经常会导致代码的可读性降低。不过这样倒的确是可以省去不少敲键的功夫,而且一些模块都设计成了只能通过特定的方法导入。

    五、包

    包是一种管理 Python 模块命名空间的形式,采用"点模块名称",比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B

    无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,这都是关于包才有的导入语法

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

    强调:

    1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
    2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块

    有一个包结构如下:

    glance/                     #顶层包
    ├── __init__.py        #初始化 glance 包
    ├── api
    │   ├── __init__.py
    │   ├── policy.py
    

    导入包里的子模块:

    import glance.api.policy
    

    必须使用全名去访问:

    glance.api.policy.func()
    

    还有一种导入模块的方法是:

    from glance.api import policy               #从模块中导入一个指定的部分到当前命名空间中
    

    它不需要那些冗长的前缀,所以可以这样使用:

    policy.func()
    

    还有一种就是直接导入一个函数或者变量:

    from glance.api.policy import func
    

    可以直接使用func()函数:

    func()
    

    1 导入包实例

    包结构如下:

    glance/                     #顶层包
    run.py                      # 执行文件
    ├── __init__.py        #初始化 glance 包
    ├── api
    │   ├── __init__.py
    │   ├── policy.py     
    

    导入包:

    #1、run.py用全名访问func(),内容如下:
    import glance
    glance.api.policy.func()
    # glance/__init__.py如下:
    import glance.api                           #也可以用from glance import api
    # glance/api/__init__.py如下:
    import glance.api.policy                    #也可以用from glance.api import policy
    
    #2、run.py直接访问func(),内容如下:
    import glance
    glance.func()
    # glance/__init__.py如下:
    from glance.api.policy import func          #不能用import glance.api.policy.func
    # glance/api/__init__.py可以不用写
    

    当使用from package import item这种形式的时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。

    import语法会首先把item当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,恭喜,一个:exc:ImportError 异常被抛出了。

    反之,如果使用形如import item.subitem.subsubitem这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。

    注意事项:

    1. 关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则
    2. 对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)
    3. 对比import item 和from item import name的应用场景:如果我们想直接使用name那必须使用后者。

    2 绝对导入和相对导入

    以上面的例子是绝对导入的方式

    绝对导入:以glance作为起始

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

    实例:

    run.py直接访问func(),内容如下:
    import glance
    glance.func()
    # glance/__init__.py如下:
    from .api.policy import func        #1、这样的好处是:就算包名glance被更改也不会有影响,只需改run.py内的import …2、..表示上级目录,可以导入上级目录中的其他模块
    

    特别需要注意的是:

    • 可以用import导入内置或者第三方模块(已经在sys.path中),但是要绝对避免使用import来导入自定义包的子模块(没有在sys.path中),应该使用from... import ...的绝对或者相对导入
    • 包的相对导入只能用from的形式

     

    六、软件开发规范

     新葡亰496net 19

    bin:存放执行脚本
    conf:存放配置文件
    core:存放核心逻辑
    db:存放数据库文件
    lib:存放自定义的模块与包
    log:存放日志
    

    start.py内容:

    import os
    import sys
    
    # print(os.path.abspath(__file__))                       #获取当前文件的绝对路径,F:softbintest.py
    # print(os.path.dirname(os.path.abspath(__file__)))       #获取当前文件所在的目录,F:softbin
    # print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))      #获取当前文件所在的目录的上级目录,F:soft
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(BASE_DIR)                                   #将soft这个包的路径加到环境变量
    
    from core import core
        ……                      #导入其他模块
    
    if if __name__ == '__main__':
        ……                      #执行
    

     

    本文由新葡亰496net发布于奥门新萄京娱乐场,转载请注明出处:新葡亰496net面向进程编制程序,铁乐学python_day

    关键词: