ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

day20 模块的导入、包和软件目录规范

2020-03-29 15:56:19  阅读:180  来源: 互联网

标签:__ py day20 导入 模块 import foo


目录

1. 模块的导入

1.1 一个python文件有两种用途

  1. 被当成程序运行
  2. 被当做模块导入

1.2 二者的区别是什么?

以文件foo为例:

1、当foo.py被运行时,__name__的值为'__main__'
2、当foo.py被当做模块导入时,__name__的值为'foo'

print('模块foo==>')

# __all__=['x',] # 控制*代表的名字有哪些
x=1
def get():
    print(x)

def change():
    global x
    x=0

def say():
    print('我还活在内存中呢。。。。')
if __name__ == '__main__':
    print('文件被执行')
    get()
    change()
else:
    # 被当做模块导入时做的事情
    print('文件被导入')
    pass

对于import导入的模块来说

1.3 import导入方式的优缺点

impot导入模块在使用时必须加前缀"模块."
优点:肯定不会与当前名称空间中的名字冲突
缺点:加前缀显得麻烦

1.4 from...impot...语句

导入中的三个过程

  1. 产一个模块的名称空间
  2. 运行foo.py将运行过程中产生的名字都丢到模块的名称空间去
  3. 在当前名称空间拿到一个名字,该名字与模块名称空间中的某一个内存地址
from foo import x # x=模块foo中值的内存地址
from foo import get
from foo import change

print(x)
print(get)
print(change)
x=333333333
print(x)
get()
change()
get()

print(x)
from foo import x # x=新地址
print(x)

对于from导入的模块来说

1.5 from...impot...的优缺点

from...impot...导入模块在使用时不用加前缀

优点:代码更精简

缺点:容易与当前名称空间混淆

from foo import x # x=模块foo中值1的内存地址
x=1111

from…import的注意事项

  • 一行导入多个名字(不推荐)
  • 一次性导入模块中的所有名字可以使用: *
  • 可以对导入的模块起别名
from foo import x,get,change
from foo import get as g
name='egon'
from foo import *
print(name)

from socket import *
'''
了解知识: * 导入时是访问对应模块的__all__的值,是一个列表
__all__=['x',] # 控制*代表的名字有哪些
'''

1.6 模块的搜索路径优先级

无论是import还是from...import在导入模块时都涉及到查找问题

优先级
1、内存(内置模块)
2、硬盘:按照sys.path中存放的文件的顺序依次查找要导入的模块

# 值为一个列表,存放了一系列的对文件夹
# 其中第一个文件夹是当前执行文件所在的文件夹
>>> import sys
>>> sys.path
['', 'E:\\Python\\Python38\\python38.zip', 'E:\\Python\\Python38\\DLLs', 'E:\\Python\\Python38\\lib', 'E:\\Python\\Python38', 'E:\\Python\\Python38\\lib\\site-packages']
>>

sys.path中的第一个路径通常为空,代表执行文件所在的路径,所以在被导入模块与执行文件在同一目录下时肯定是可以正常导入的,而针对被导入的模块与执行文件在不同路径下的情况,为了确保模块对应的源文件仍可以被找到,需要将源文件foo.py所在的路径添加到sys.path中,假设foo.py所在的路径为/pythoner/projects/

import sys
sys.path.append(r'/pythoner/projects/') #临时添加
#找foo.py就把foo.py的文件夹添加到环境变量中,获取文件的绝对路径,再添加
import foo #无论foo.py在何处,我们都可以导入它了

了解:sys.modules查看已经加载到内存中的模块

import sys
import foo # foo=模块的内存地址
del foo

def func():
    import foo # foo=模块的内存地址

func()

# print('foo' in sys.modules)
print(sys.modules)

1.7 编写一个规范的模块

#!/usr/bin/env python #通常只在类lunix环境有效,作用是可以使用脚本名来执行,而无需直接调用解释器。

"The module is used to..." #模块的文档描述

import sys #导入模块

x=1 #定义全局变量,如果非必须,则最好使用局部变量,这样可以提高代码的易维护性,并且可以节省内存提高性能

class Foo: #定义类,并写好类的注释
    'Class Foo is used to...'
    pass

def test(): #定义函数,并写好函数的注释
    'Function test is used to…'
    pass

if __name__ == '__main__': #主程序
    test() #在被当做脚本执行时,执行此处的代码

1.8 函数知识的补充

类型提示 Type hinting(最低 Python 为 3.5)

#Python是一种强类型的动态语言
#可以:+类型,规定传入值的类型,本质上:后是添加的提示信息,可以根据需要填写
#->int 规定返回值的类型
#虽然规定了传入类型,但实际上还是可以传入其他类型的,传入值的规范
def register(name:str,age:int,hobbbies:tuple)->int:
 print(name)
 print(age)
 print(hobbbies)
 return 111

register(1,'aaa',[1,])
#可以添加默认值,默认值在类型后面添加
def register(name:str='egon',age:int=18,hobbbies:tuple=(1,2))->int:
 print(name)
 print(age)
 print(hobbbies)
 return 111
register()
res=register('egon',18,('play','music'))

1585325998024

2. 包

2.1 什么是包

包就是一个包含有__init__.py文件的文件夹

2.2 为何要有包

包的本质是模块的模块的一种形式,包是用来被当做模块导入

2.3 怎么使用包

import mmm
print(mmm.x)
print(mmm.y)
mmm.say()

from mmm import x

导入包的三个步骤

1、产生一个名称空间
2、运行包下的_init_.py文件,将运行过程中产生的名字都丢到1的名称空间中
3、在当前执行文件的名称空间中拿到一个名字mmm,mmm指向1的名称空间

强调
1.关于包相关的导入语句也分为import和from ... import ...两种在导入时都必须遵循一个原则:

凡是在导入时带点的,点的左边都必须是一个包,否则非法。
2、包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
3、import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的_init_.py,导入包本质就是在导入该文件

2.4 绝对导入与相对导入

# 绝对导入,以包的文件夹作为起始来进行导入
#pool下的__init__.py
from pool import versions


# 相对导入:仅限于包内使用,不能跨出包(包内模块之间的的导入,推荐使用相对导入)
# .:表示当前文件夹
# ..:表示上一层文件夹
# 局限性:.不能超出foo之外

#pool下的__init__.py
from . import versions
'''
强调:
1、相对导入不能跨出包,所以相对导入仅限于包内模块之间相互导入
2、绝对导入是没有任何限制的,所以绝对导入是一种通用的导入方式
'''

#针对包内部模块之间的相互导入推荐使用相对导入,需要特别强调:
'''
1、相对导入只能在包内部使用,用相对导入不同目录下的模块是非法的

2、无论是import还是from-import,但凡是在导入时带点的,点的左边必须是包,否则语法错误
'''

from 包 import *

'''
在使用包时同样支持from pool.futures import * ,
毫无疑问*代表的是futures下__init__.py中所有的名字,通用是用变量__all__来控制*代表的意思
'''
#futures下的__init__.py
__all__=['process','thread']

'''
包内部的目录结构通常是包的开发者为了方便自己管理和维护代码而创建的,
这种目录结构对包的使用者往往是无用的,此时通过操作__init__.py可以“隐藏”包内部的目录结构,
降低使用难度,比如想要让使用者直接使用
'''
import pool

pool.check()
pool.ProcessPoolExecutor(3)
pool.ThreadPoolExecutor(3)

# 需要操作pool下的__init__.py
from .versions import check
from .futures.process import ProcessPoolExecutor
from .futures.thread import ThreadPoolExecutor

3. 软件开发的目录规范

为了提高程序的可读性与可维护性,我们应该为软件设计良好的目录结构,这与规范的编码风格同等重要。软件的目录规范并无硬性标准,只要清晰可读即可,假设你的软件名为foo,推荐目录结构如下

3.1 软件目录结构

Foo/ 
|-- core/ # 存放业务逻辑相关代码
|   |-- core.py
|
|-- api/ # 存放接口文件,接口主要用于为业务逻辑提供数据操作。
|   |-- api.py 
|
|-- db/ # 放操作数据库相关文件,主要用于与数据库交互
|   |-- db_handle.py
|
|-- lib/ # 存放程序中常用的自定义模块
|   |-- common.py
|
|-- conf/ # 存放配置文件
|   |-- settings.py
|
|-- run.py # 程序的启动文件,一般放在项目的根目录下,因为在运行时会默认将运行文件所在的文件夹				sys.path的第一个路径,这样就省去了处理环境变量的步骤
|-- setup.py # 安装、部署、打包的脚本。
|-- requirements.txt # 存放软件依赖的外部Python包列表
|-- README # 项目说明文件

3.2 软件说明README

关于README的内容,这个应该是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。它需要说明以下几个事项:

'''
1、软件定位,软件的基本功能;

2、运行代码的方法: 安装环境、启动命令等;

3、简要的使用说明;

4、代码目录结构说明,更详细点可以说明软件的基本原理;

5、常见问题说明。
'''

标签:__,py,day20,导入,模块,import,foo
来源: https://www.cnblogs.com/Henry121/p/12592683.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有