Python项目的代码要求:

高性能,封装性(可复用)、抽象

自己写程序的要求:

不单追求简单业务逻辑。更要考虑封装性

项目结构:

顶级结构:  包      文件夹,类似jar,dll等
二级结构:  模块    .py文件,单文件可包含多个类,也可以不定义类,但最好用类组织起来
三级结构:  类      
            函数、变量(类的特性)

包和模块的命名:

与文件夹和文件的名称相同

区分不同包的模块:使用命名空间

baoA.module
baoB.module

注意:

包可以包含字包
如果想让文件夹成为一个包,那么必须含有一个_init_.py文件
    __init__.py叫做init模块,如果需要引用,形式
    不是bao.__init__而是bao,用包的名称即 import bao 即可引入他

包的相互引入:

引入的第一种方式
    如果 import 包名,那么会引入执行该包的全部代码
    对于包内模块的引入:
        模块AB同级:
            如果A模块引用B模块定义的变量param
            那么需要在A模块内 import module_name
            即:在A模块内:import B; print(B.param),有严格的先后顺序
        模块AB不同级:
            加上包的命名空间即可:
            import bao.B; print(bao.B.param),
            精简:import bao.B as m; print(m.param),//缩短点引用
    注意:
        在python中一旦发生模块之间的import引用,就会在包下面生成pycache文件夹
        __pycacahe__文件夹和期内的.pyc文件是自动生成的,与py虚拟机相关
        在VSCODE中的配置页内的"files.exculed"中添加"__pycache__":true,则会隐藏文件

引入的第二种方式
    使用from..import..
        特点:可以引用单变量,也可以同import:form bao import B; print(bao.B.param)
        例如 from bao.B import param ; print(param)
        全部引入: 
            from bao.B import * ; 可以把B内变量全部引入,但是会混淆当前模块定义

    控制需要引入的变量:仅适用本方式
        例如在B模块中有三个变量,但只需import变量param,那么需要在
        B模块中第一行:添加模块内置属性 __all__ = ['param']
        此时使用 from bao.B import *; 时只能导入param变量

规范的引入:

首先明确,python内一行代码字符不超过80个
    from bao.B import a,b,c,d,e,f 如果需要换行,那么可以加反斜杠换行:
        from bao.B import a,b,c,\
        d,e,f
    或者使用括号,保证其连接性(适用场景很多):
        from bao.B import (a,b,c,
        d,e,f)

init.py的作用:

其相当于在全部代码前夹上init内的代码,引用包bao内的模块B时,会自动执行该包内的init模块
例如:
    引用包bao内的模块B时,自动执行bao内的init模块
__init__的功能:
    在init内,通过 __all__ = ['B']来控制此包内能够被引用的模块
    在init内,添加公共 import 的类库,
    例如在包common内的init模块中添加公共库之后,在其他代码中只需 import common即可批量添加类库

引入的注意事项:

包和模块不会重复导入,类似static代码块,只导入一次
避免循环导入
    例如在模块A内 import B,在模块B内 import A 会陷入循环引入,要避免!
    多模块间复杂引用时要避免因引用过多产生环链
关注 import 引入的内容
    一旦导入的是一个模块,则就会执行模块的全部代码
    无论在代码中重复引入多少次,引入的模块都只会执行一次
    搞清入口文件:运行test.py时,其实就是将其作为入口文件

模块的内置变量

dir()函数:返回当前模块内的全部变量
内置变量:
    __builtins__
    __cached__
    __doc__      
    __file__    
    __loader__
    __name__
    __package__
    __spec__
用户自定义变量:
    userA...

注意:

内置变量跟变量完全一样,内容可以被修改

使用打印输出变量信息:

print('name:'+__name__)     
print('pakage:'+__package__)
print('doc:'+__doc__)
print('file:'+__file__)

错误信息排查:

Traceback (most recent call last):
File "h:/mooc/test/a1.py", line 1, in <module>
    import test1.a1
File "h:\mooc\test\test1\a1.py", line 3, in <module
>
    print('doc:'+__doc__)
TypeError: Can't convert 'NoneType' object to str implicitly
解释:
    上述Traceback表示错误栈信息,会列出整个执行路径的全部出错信息,最后的Error是错误类型
    应该先看最后的错误类型,然后通过错误栈来定位错误。

内置变量打印结果:

name:test1.a                    模块的完整名称,带命名空间
pakage:test1                    模块所属的包名
doc:                            注释文件的注释信息
    我是开头的注释
file:h:\mooc\test\test1\a.py    当前模块的物理路径

对于打印未知字符串,可以使用容错处理

print("可能的NoneType类型:" + param ) 修改为:
print("可能的NoneType类型:" + (param or '空值'))

(区别与上面的普通模块输出)

如果一个py文件被当做入口文件:那么此文件的

__name__ = '__main__',其会被强制改变,不在为文件名
__package__ = 'NoneType'即,入口文件不属于任何包
__file__ = '执行时的路径',即使用python 1/2/3.py时,此变量为1/2/3.py值不确定

另外:

import sys
print(dir(sys)) 打印系统内置变量,比模块的内置变量更多

内置变量 name 的作用

判断当前模块是否是被作为入口文件:
    if __name__ == '__main__':
        print('是入口文件,单独执行')
    else:
        print('作为模块被调用')
上述代码在a.py中,分别用a1调用和单独执行a:注意路径区别
    a.py  在包test/test1下 
    a1.py 在包test下,代码是 import test1.a
H:\mooc\test\test1>python a.py 
或 H:\mooc\test>python test1\a.py
    是入口文件,单独执行
    name:__main__               
    pakage:没有上一层的包      //注意
    doc:
        我是开头的注释
    file:h:/mooc/test/test1/a.py
H:\mooc\test>python a1.py
    作为模块被调用
    name:test1.a              //注意
    pakage:test1
    doc:
        我是开头的注释
    file:h:\mooc\test\test1\a.py
将可执行的文件当做模块来调用: 
H:\mooc\test>python -m test1.a 
    是入口文件,单独执行
    name:__main__
    pakage:test1              //注意
    doc:
        我是开头的注释
    file:H:\mooc\test\test1\a.py
注意上述三中运行方式的区别!!!!

包和模块导入时的绝对和相对路径

顶级包,与入口文件的位置有关
顶级包是相对于入口文件以外的文件来说的,
对于一个项目,在入口文件中需要import 包路径.模块名
而包路径就关乎顶级包的正确确定

绝对引入:import 包路径.模块名

其中的包路径必须从顶级包开始

相对引入:使用

from .module    表示引入同级的模块
from ..module   表示引入上一层的模块
注意:
    import 方式不能使用 . 方式
    可以使用 from .module import x 的方式
        但是,入口文件不能使用 .module 相对引入
    另外,如果待引用模块位于入口文件的同一层。那么无法点引入,会报错
        错误:尝试引用一个超过顶级包的模块
相对引入的机制:
    使用内置变量__name__来找到模块,
    因此,入口文件的name是‘_main_’,
    所以如果想在‘入口文件这一层引入模块’,那么只能绝对引入
    如果在‘入口文件的上一层’,并使用 python -m module 仍然可以使用相对引入,
        因为这种方式,文件仍然是入口文件,但是__name__不会改变,故能够使用相对引入