[入门-5] 程序组织之模块和包

基础

逻辑组织和物理组织

  • 逻辑组织是模块,module
  • 物理组织是文件,file
  • 文件名=模块名.py
  • 导入的是模块或模块属性

默认搜索路径

  • 环境变量,PYTHONPATH
  • 脚本(解释器)启动后,也可以使用,sys.path (list)查看;
  • 使用sys.path.append(r’/var/opt/lib’)添加新的路径到末尾
  • 使用sys.path.insert()到指定位置
  • 使用sys.modules(dict)查看当前导入的模块,以及相应的位置
  • sys.modules().keys()

名称空间

  • 名称空间是名字和对象之间的映射关系
  • 作用域是用户代码哪些物理位置可以访问到这些名字
  • module.name,保证了不同module可以共用相同的函数,变量名称
  • 内建名称空间,全局名称空间,局部名称空间,局部名称空间是不断变化的,所以执行期间有2-3个活动的名称空间
  • Python解释器首先加载内建名称空间(__buildins__),随后加载执行模块的全局名称空间,上述会在模块开始执行后变为活动名称空间
  • 调用globals()查看全局变量
  • 调用locals()查看局部变量
    名称空间和作用域的含义,名称空间纯粹意义上就是一个变量名字到对象之间的映射字典,python和c,c++等语言不通,对于C来说,变量名字实际上是内存地址别名,对于python来说,名字就是名字,是通过名称空间建立到和对象的映射关系,改变一个名字实际上是重新绑定到其他对象,删除一个名字是解除和对象的绑定;

    作用域的含义是代码执行到哪些物理位置可以访问到这些名字,是否可以看得到这个变量名字。

    当访问一个名字的时候,解释器就会做名称查询,从局部名称空间,一层一层向上查找到内建名称空间,失败了就返回错误,这里面隐含着一件事,就是内层空间会覆盖外层空间,在局部空间找到了,就不会再向上查找了,相当于覆盖了全局变量,找到了之后会把变量加到局部名称空间中,初始值用外面的,但是赋值之后不会修改到外面的值。

无限制名称空间

#在任何需要放置数据的地方,都可以获取一个名称空间
def func():
    pass
func.__doc__='dfs'
func.version=2.0

class a:
    pass
a.x=9
a,y=10

导入模块

#导入模块
#可以一行导入多个模块,但是不推荐这么做
import os     #标准库模块
import urllib #第三方模块
import mymodule  #应用程序自定义模块

#导入模块属性
from module import classA, func, gName
from module import (A,B..)

#扩展导入
import module as NameModule
from module import classA as classB
#一般情况下不能使用from module import *,污染名称空间,除非极特殊情况!
  • 导入模块时,解释器会在默认搜索路径中寻找,找到了就会加载它,该过程遵循作用域原则,如果在本文件的顶层导入,就是导入模块的作用于就是全局的,如果在函数中导入,导入模块的作用域就局部的。
  • 模块第一次导入的时候,会被加载执行,即所有顶层代码都会被执行!包括全局变量以及类和函数的声明,如果有检查name的操作,也会执行。
  • 一个模块只被加载一次,无论被导入了多少次,这可以阻止多重导入时代码被多次执行
  • from module import var 可以把var导入当前的名称空间,这意味着不需要module.var,直接使用var就能访问
  • from module import var导入的时候,var会在局部名称空间,如果直接使用var的话,给它重新赋值的时候,不会影响被被导入模块module.var的值,只会改变本模块局部变量var,如果要改变被导入模块的值,需要使用module.var的方式赋值
  • 这里也引出了一个问题,跨模块的全局变量访问,要想要大家都直接去修改,就要用module.A来访问,还有个更好的办法是,共享的模块使用函数来访问。
#global_var.py

#!/usr/bin/python
g_lsName = ""

def set_g_lsName(sName)
    global g_lsName
    g_lsName = sNname
    return

del get_g_lsName()
    global g_lsName
    return g_lsName

__import__方法

  • 实际导入模块的方法,提供这个函数是为了特殊需求的用户可以覆盖它,实现自定义导入算法
__import__(modulename, globals=globals(), locals=locals(), fromlist=[])
sys = __import__('sys')

reload()方法

  • 重新导入一个已经导入的模块
  • 参数是模块名字本身,而不是字符串
  • reload(os) not reload(‘os’)
  • 模块导入的时候执加载一次,后续的import就不会再加载了,但是执行reload()可以重新加载

  • 包是有层级结构的,对应文件的目录结构
  • 包定义了一个由模块和子包组成的python应用程序执行环境
  • 和类,模块一样,包也使用.来访问元素
  • 每层目录下必须要有init.py文件,这是初始化模块,在from-import语句导入子包的时候需要使用它
import dirA.dirB.moduleA
dirA.dirB.moduleA.func()

from dirA.dirB import dirC
dirC.moduleA.func()

from dirA.dirB.dirC import func
func()

绝对导入和相对导入

  • 相对导入容易覆盖内建模块,现在的导入必须是绝对路径导入,这些名字必须通过Python路径即sys.path或是PYTHONPATH来访问
  • 允许报包名前置句点实现相对导入
from .dirB import module
from ..dirA import module
#

Reference

Python核心编程
http://shomy.top/2016/03/01/python-namespace-1/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值