目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块)

3.4 模块

本节介绍模块的概念以及如何使用跨多个文件的函数。

模块和导入

任何一个 Python 源文件都是一个模块。

  1. # foo.py
  2. def grok(a):
  3. ...
  4. def spam(b):
  5. ...

import 语句加载并执行一个模块。

  1. # program.py
  2. import foo
  3. a = foo.grok(2)
  4. b = foo.spam('Hello')
  5. ...

命名空间

模块是命名值的集合,有时也称为命名空间。名称是源文件中定义的所有全局变量和函数。导入之后,模块名称用作前缀。因此,称为命名空间。

  1. import foo
  2. a = foo.grok(2)
  3. b = foo.spam('Hello')
  4. ...

模块名直接绑定到文件名(foo -> foo.py)。

全局定义

填充模块命名空间的内容是定义在全局(global)作用域中任何内容。考虑定义了相同变量 x 的两个模块。

  1. # foo.py
  2. x = 42
  3. def grok(a):
  4. ...
  1. # bar.py
  2. x = 37
  3. def spam(a):
  4. ...

在本例中,x 指向不同的变量。一个是 foo.x,另一个是 bar.x。不同的模块可以使用相同的名称并且这些名称不会相互冲突。

模块是隔离的。

把模块当做环境

对于所有定义在模块里面的代码而言,模块构成一个封闭的环境。

  1. # foo.py
  2. x = 42
  3. def grok(a):
  4. print(x)

全局变量始终绑定到封闭模块(相同文件),每个源文件都是它自己的小宇宙。

模块执行

导入模块时,模块中的所有语句依次执行(execute),直到到达文件末尾。模块命名空间的内容是所有的全局名称,这些名称在执行过程结束时仍然被定义。如果有脚本语句在全局作用域中执行任务(如打印,创建文件等),您将看到它们在导入模块时运行。

import as 语句

可以在导入模块时更改其名称:

  1. import math as m
  2. def rectangular(r, theta):
  3. x = r * m.cos(theta)
  4. y = r * m.sin(theta)
  5. return x, y

它的作用与普通导入相同,仅仅是重命名模块而已。

from import语句

from import语句从模块中选出符号并使它们在局部可访问。

  1. from math import sin, cos
  2. def rectangular(r, theta):
  3. x = r * cos(theta)
  4. y = r * sin(theta)
  5. return x, y

这允许使用模块的某些部分,而不必输入模块前缀。对于经常使用的名称,这非常有用。

导入说明

有关导入的各种变化不改变模块的工作方式。

  1. import math
  2. # vs
  3. import math as m
  4. # vs
  5. from math import cos, sin
  6. ...

具体来说,import 始终执行整个文件并且模块仍然是隔离的环境。

import module as 语句只局部地更改名称。在后台,from math import cos, sin 语句仍加载全部的数学模块。当导入完成后,它仅仅将模块中的 cossin 名称复制到局部命名空间中。

模块加载

每个模块仅加载和执行一次。注意:重复导入仅返回先前所加载模块的引用

sys.modules 是所有已加载模块的字典。

  1. >>> import sys
  2. >>> sys.modules.keys()
  3. ['copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'encodings.encodings', 'posixpath', ...]
  4. >>>

注意:当修改模块的源代码后,如果重复import语句会产生一个常见的困惑。由于模块缓存 sys.modules,重复导入总是返回之前加载的模块——即使更改已经发生。将修改后的代码加载到 Python 中最安全的方式是退出然后重启解释器。

定位模块

搜索模块时,Python 从路径列表(sys.path)中查询。

  1. >>> import sys
  2. >>> sys.path
  3. [
  4. '',
  5. '/usr/local/lib/python36/python36.zip',
  6. '/usr/local/lib/python36',
  7. ...
  8. ]

当前工作目录通常是第一个。

模块搜索路径

如前所述,sys.path 包含搜索路径。可以根据需要手动调整 。

  1. import sys
  2. sys.path.append('/project/foo/pyfiles')

也可以通过环境变量添加搜索路径。

  1. % env PYTHONPATH=/project/foo/pyfiles python3
  2. Python 3.6.0 (default, Feb 3 2017, 05:53:21)
  3. [GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)]
  4. >>> import sys
  5. >>> sys.path
  6. ['','/project/foo/pyfiles', ...]

在大部分情况下,没必要手动调整模块搜索路径。但是,如果尝试导入的 Python 代码位于特殊位置,或者无法从当前工作目录轻松访问,那么就需要手动调整搜索路径了。

练习

因为本练习涉及模块,所以确保在适当的环境中运行 Python 至关重要。模块经常给编程新手带来问题,这些问题与当前工作目录相关或者与 Python 路径设置相关。对于本课程,假定您是在 Work/ 目录下编写所有的代码。为了获得最佳结果,应该确保也是在 Work/ 目录下运行解释器。否则,需要确保 practical-python/Work 已添加到 sys.path

练习 3.11:模块导入

在第 3 节中,我们创建了一个通用目标函数 parse_csv() 用于解析 CSV 数据文件的内容。

现在,我们来看看如何在其它程序中使用该函数。首先,启动一个新的 shell 窗口,进入到放置所有文件的目录中。我们将要导入它们。

启动 Python 交互模式。

  1. bash % python3
  2. Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
  3. [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
  4. Type "help", "copyright", "credits" or "license" for more information.
  5. >>>

当Python 交互模式启动后,尝试导入某些之前编写的程序。应该能看到输出和以前一样。强调一下,导入模块会运行模块中的代码。

  1. >>> import bounce
  2. ... watch output ...
  3. >>> import mortgage
  4. ... watch output ...
  5. >>> import report
  6. ... watch output ...
  7. >>>

如果没有代码运行,可能是因为在错误的目录下运行了 Python。现在,尝试导入 fileparse 模块并获取有关该模块的帮助。

  1. >>> import fileparse
  2. >>> help(fileparse)
  3. ... look at the output ...
  4. >>> dir(fileparse)
  5. ... look at the output ...
  6. >>>

尝试使用 fileparse 模块来读取一些数据:

  1. >>> portfolio = fileparse.parse_csv('Data/portfolio.csv',select=['name','shares','price'], types=[str,int,float])
  2. >>> portfolio
  3. ... look at the output ...
  4. >>> pricelist = fileparse.parse_csv('Data/prices.csv',types=[str,float], has_headers=False)
  5. >>> pricelist
  6. ... look at the output ...
  7. >>> prices = dict(pricelist)
  8. >>> prices
  9. ... look at the output ...
  10. >>> prices['IBM']
  11. 106.11
  12. >>>

尝试导入一个函数,以便不用再包含模块名:

  1. >>> from fileparse import parse_csv
  2. >>> portfolio = parse_csv('Data/portfolio.csv', select=['name','shares','price'], types=[str,int,float])
  3. >>> portfolio
  4. ... look at the output ...
  5. >>>

练习 3.12:使用库模块

在第 2 节中,编写了 report.py 程序用来生成像下面这样的股票报告:

  1. Name Shares Price Change
  2. ---------- ---------- ---------- ----------
  3. AA 100 9.22 -22.98
  4. IBM 50 106.28 15.18
  5. CAT 150 35.46 -47.98
  6. MSFT 200 20.89 -30.34
  7. GE 95 13.48 -26.89
  8. MSFT 50 20.89 -44.21
  9. IBM 100 106.28 35.84

使用该程序并对其进行修改,以便使用 fileparse 模块中的函数完成所有输入文件的处理。为此,将 fileparse 作为模块导入,并修改 read_portfolio()read_prices() 函数以便使用 parse_csv() 函数。

在本练习开始时,请使用交互示例作为指南。之后,应该能够获得与之前完全相同的输出。

练习 3.14:使用更多的库导入

在第 1 节中,编写了一个读取股票投资组合和计算费用的程序 pcost.py

  1. >>> import pcost
  2. >>> pcost.portfolio_cost('Data/portfolio.csv')
  3. 44671.15
  4. >>>

请修改 pcost.py 文件,以便它能够使用 report.read_portfolio() 函数。

说明

当完成练习后,您应该拥有三个程序。包含通用目的函数 parse_csv()fileparse.py 程序。用于生成报告,且包含 read_portfolio()read_prices() 函数的 report.py 程序。最后,利用 report.py 程序中编写的read_portfolio() 函数去计算股票投资组合费用的 pcost.py 程序。

目录 | 上一节 (3.3 错误检查) | 下一节 (3.5 主模块)

注:完整翻译见 https://github.com/codists/practical-python-zh

翻译:《实用的Python编程》03_04_Modules的更多相关文章

  1. 翻译:《实用的Python编程》InstructorNotes

    实用的 Python 编程--讲师说明 作者:戴维·比兹利(David Beazley) 概述 对于如何使用我的课程"实用的 Python 编程"进行教学的问题,本文档提供一些通用 ...

  2. 翻译:《实用的Python编程》README

    欢迎光临 大约 25 年前,当我第一次学习 Python 时,发现 Python 竟然可以被高效地应用到各种混乱的工作项目上,我立即被震惊了.15 年前,我自己也将这种乐趣教授给别人.教学的结果就是本 ...

  3. 翻译:《实用的Python编程》05_02_Classes_encapsulation

    目录 | 上一节 (5.1 再谈字典) | 下一节 (6 生成器) 5.2 类和封装 创建类时,通常会尝试将类的内部细节进行封装.本节介绍 Python 编程中有关封装的习惯用法(包括私有变量和私有属 ...

  4. 翻译:《实用的Python编程》04_02_Inheritance

    目录 | 上一节 (4.1 类) | 下一节 (4.3 特殊方法) 4.2 继承 继承(inheritance)是编写可扩展程序程序的常用手段.本节对继承的思想(idea)进行探讨. 简介 继承用于特 ...

  5. 翻译:《实用的Python编程》01_02_Hello_world

    目录 | 上一节 (1.1 Python) | 下一节 (1.3 数字) 1.2 第一个程序 本节讨论有关如何创建一个程序.运行解释器和调试的基础知识. 运行 Python Python 程序始终在解 ...

  6. 翻译:《实用的Python编程》03_03_Error_checking

    目录 | 上一节 (3.2 深入函数) | 下一节 (3.4 模块) 3.3 错误检查 虽然前面已经介绍了异常,但本节补充一些有关错误检查和异常处理的其它细节. 程序是如何运行失败的 Python 不 ...

  7. 翻译:《实用的Python编程》03_05_Main_module

    目录 | 上一节 (3.4 模块) | 下一节 (3.6 设计讨论) 3.5 主模块 本节介绍主程序(主模块)的概念 主函数 在许多编程语言中,存在一个主函数或者主方法的概念. // c / c++ ...

  8. 翻译:《实用的Python编程》04_01_Class

    目录 | 上一节 (3.6 设计讨论) | 下一节 (4.2 继承) 4.1 类 本节介绍 class 语句以及创建新对象的方式. 面向对象编程(OOP) 面向对象编程是一种将代码组织成对象集合的编程 ...

  9. 翻译:《实用的Python编程》05_00_Overview

    目录 | 上一节 (4 类和对象) | 下一节 (6 生成器) 5. Python 对象的内部工作原理 本节介绍 Python 对象的内部工作原理.来自其它语言的程序员通常会发现 Python 的类概 ...

随机推荐

  1. 【bzoj 1190】梦幻岛宝珠(DP)

    这题是在01背包问题的基础上,扩充了重量,需要用时间换空间. 思路: 1.仔细看题,注意到重量wi为a*2^b(a<=10,b<=30),很容易想到要按 b 分开做背包的DP.接下来的重点 ...

  2. Buy the Ticket HDU - 1133 大数dp

    题意: 演唱会门票售票处,那里最开始没有零钱.每一张门票是50元,人们只会拿着100元和50元去买票,有n个人是拿着50元买票,m个人拿着100元去买票. n+m个人按照某个顺序按序买票,如果一个人拿 ...

  3. Codeforces Round #646 (Div. 2) E. Tree Shuffling dfs

    题意: 给你n个节点,这n个节点构成了一颗以1为树根的树.每一个节点有一个初始值bi,从任意节点 i 的子树中选择任意k个节点,并按他的意愿随机排列这些节点中的数字,从而产生k⋅ai 的成本.对于一个 ...

  4. 02、Scrapy 安装、目录结构及启动

    1.从豆瓣源去快速安装Scrapy开发环境 C:\Users\licl11092>pip install -i https://pypi.douban.com/simple/ scrapy 2. ...

  5. Python——控制鼠标键盘

    一.安装包 pip install pynput 二.引用包 from pynput import mouse,keyboard 三.控制鼠标 from pynput.mouse import But ...

  6. 爬虫入门四 re

    title: 爬虫入门四 re date: 2020-03-14 16:49:00 categories: python tags: crawler 正则表达式与re库 1 正则表达式简介 编译原理学 ...

  7. CodeForces - 13E(分块)

    Little Petya likes to play a lot. Most of all he likes to play a game «Holes». This is a game for on ...

  8. ZOJ 3430 Detect the Virus(AC自动机 + 模拟)题解

    题意:问你主串有几种模式串.但是所有串都是加密的,先解码.解码过程为:先把串按照他给的映射表变成6位数二进制数,然后首尾衔接变成二进制长串,再8位8位取变成新的数,不够的补0.因为最多可能到255,所 ...

  9. Python求二维数组中某列的最大值

    主要运用np.amax() import numpy as np help(np.amax) a = np.arange(9).reshape((3, 3)) max_all = np.amax(a) ...

  10. Flutter & App

    Flutter & App Android & iOS https://flutter.dev/docs/deployment/flavors https://flutter.dev/ ...