python 模块管理

要点概论:

1.引言

2. 用模块建立抽象层

3. 管理模块名称

4. 设置 PTH 文件(待补充)

5.附录

1. 引言

  python是个支持多范式的程序设计语言,无论采取过程式,函数式或面向对象,在构建程序时都应该思考以下几个重点。

  1)抽象层的封装与隔离

  2)对象的状态

  3)命名空间

  4)资源实体的组织方式,像源码文件,软件包等

  在python中,模块也提供了一种抽象层的封装与隔离,下面来了解以下如何善用模块建立最自然的抽象层

2.用模块建立抽象层

  一个 .py 文件就是一个模块,这使得模块称为python中最自然的抽象层。想要直到一个模块中有哪些名称,可以使用 dir() 函数。

  实际上,当 import 某个模块而使得指定的 .py 文件被加载时,python 解释器会为它创建一个 module 实例,并创建一个模块名称来引用它,

  dir() 实际上时查询模块名称引用的 module 实例上有哪些属性(Attribute)名称可以存取。

  PS:若调用 dir() 时未指定任何 module 实例,则会插叙当前所在模块的 module 实例上拥有的名称。

  下面我们来设计一个银行业务相关的简单程序,并把它定义在一个 bank.py 文件中:

# bank.py

def account(name,number,balance):
    return {'name':name,'number':number,'balance':balance}

def deposit(acct,amount):
    if amount <= 0:
        print('存款金额不能为负')
    else:
        acct['balance'] += amount

def withdraw(acct,amount):
    if amount > acct['balance']:
        print('金额不足')
    else:
        acct['balance'] -= amount

def desc(acct):
    return 'Account:' + str(acct)
bank.py

接下来再其他的 py 文件中 import bank:

import bank

acct = bank.account('zhaoyi','123-4567',1000)
bank.deposit(acct,500)
bank.withdraw(acct,200)

print(bank.desc(acct))

# Account:{'number': '123-4567', 'name': 'zhaoyi', 'balance': 1300}
import bank

  bank 这个名称不单只是用来避免命名空间的冲突,也时作为一种组织与思考相关功能的方式。

3. 管理模块名称

  大部分情况下模块都会被拿来作为命名空间。下面介绍一些引用模块的方式:

  1) from import 名称管理

     from import 变将被导入模块中名称引用的值赋给当前模块中创建的新名称,

例如,在 foo.py 中定义了一个 x 变量:

x = 10
foo.py

在另一个 main.py 文件中执行 from foo import x ,实际上会在 main 模块中创建一个 x 变量然后将 foo 中 x 的值 10 赋值给 main 中的 x 变量:

from foo import x

print(x)     # 10

x = 20

print(x)    #20

import foo

print(foo.x)    #10
main.py

简单来说,当执行 from foo import x 时,就是在模块中创建了新变量,而不是使用原本的 foo.x 变量,只是一开始两个变量引用同一个值。

但是,若引用了可变动对象,就要特别小心了。

例如,在foo.py中定义一个 l1 = [10,20]:

l1 = [10,20]
foo.py
from foo import l1

print(l1)       #[10, 20]
l1[0] = 15
print(l1)       #[15, 20]

import foo
print(foo.l1)   #[15, 20]
main.py

这是因为 l1 变量与 foo.l1 都引用了同一个列表(list)对象,因此通过 l1 变量修改索引 0 的元素使用 foo.l1 就会获取修改后的结果。

  

  2)限制 from import *

    在当前模块中,如果有些变量不想被 from import *创建同名变量(避免命名空间混乱),有两种方法,

第一种方法用下划线作为开头,例如:

x = 10
l1 = [10,20]
_y = 20
foo.py
from foo import *

print(x)    #10
print(l1)   #[10,20]
print(_y)   # NameError: name '_y' is not defined
main.py

另一种方法是定义一个 __all__ 列表,使用字符串列处可被 from import * 的名称,例如:

__all__ = ['x','l1']
x = 10
l1 = [10,20]
_y = 20
z = 30
foo.py
from foo import *

print(x)    #10
print(l1)   #[10,20]
print(z)   # NameError: name 'z' is not defined
main

需要注意的是:无论是下划线开头,还是未被列入 __all__ 列表的名称,只是限制不被 from import *,如果用户 import foo,那么依旧可以使用 foo.x 或 foo._y来存取。

import foo

print(foo.x)    # 10
print(foo._y)   # 20
main.py

  3)del 模块名称

    del 可以将已创建的变量删除。

    被 import 的模块名称或者 from import 创建的名称实际上就是个变量,因此可以使用 del 将模块名称或者 from import 的名称删除。

例如:

import foo
print(foo.x)    # 10
del foo
print(foo.x)    # name 'foo' is not defined

from foo import x
print(x)        # 10
del x
print(x)        # name 'x' is not defined
main.py

如果想模拟 import foo as qoo,那么可以如下方法实现:

import foo
qoo = foo
del foo
print(qoo.x)    # 10
print(foo.x)    # name 'foo' is not defined
main.py

  4)sys.modules

    del 用来删除指定的名称而不是删除名称引用的对象本身。

举例来说:

l1 = [1,2]
l2 = l1

del l1

print(l2)   # [1, 2]
print(l1)   # name 'l1' is not defined
main.py

   在上例中,虽然执行了 del l1,然而 l2还是引用着列表实例。

   也就是说,del 只是将该名称删除,而不是删除 module 实例。

想要知道当前已加载的 module 名称与实例有哪些,可以通过 sys.modules 【这是个字典对象,键的部分是模块名称,值的部分是 module 实例】,例如:

import sys
import foo

print('foo' in sys.modules) # True
print(foo.x)                 # 10
del foo
print(foo.x)                 # name 'foo' is not defined
print(sys.modules['foo'])   # 10
main.py

  上面的例子可以看到, del foo 删除了 foo名称,然而,我们还是可以通过 sys,module['foo'] 存取到 foo 原来引用的 module 实例。

  5)模块名称的作用域

    实际上引用模块可以出现在语句能出现的位置,例如 if...else区块或者函数之中,因此能根据不同的情况进行不同的 import。

当使用 import,import as,from import 时,创建的名称其实就是变量名称,因此根据使用 import,import as,from import 的位置所创建的名称也会有其作用域。例如:

def foo():
    import foo
    print(foo.x)

foo()           # 10
print(foo.x)    # AttributeError: 'function' object has no attribute 'x'
main.py

  

 4. 设置 PTH 文件(待补充)

5. 附录

  一个模块被 import 时发生的事情:

  1) 在 sys.path 寻找模块

  2) 加载,编译模块的程序代码

  3) 创建空的模块对象

  4) 在 sys,modules 中记录该模块

  5) 执行模块中的程序代码及相关定义

   

  

  

原文地址:https://www.cnblogs.com/HZY258/p/8456366.html