序
接前面一路过来牛刀小试,实操检验,也收集不少资料,来自csdn,python Documentation,c语言中文网,菜鸟教程,笨方法等等,集基础之大成,整合在一起,免去搜寻的麻烦,作为学习pythonr打基础之用!如有不足之处,共勉!!!本文虽然啰嗦,旨在不同人不同理解,但是总能找到能懂的地方!!!
生活苦短,我用python!!!修缮不足,共勉共进!!!
一、前言
Python简介
Python 是一种解释型语言: 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。
Python 是交互式语言: 这意味着,您可以在一个 Python 提示符 >>> 后直接执行代码。
Python 是面向对象语言: 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。
Python 是初学者的语言:Python 对初级程序员而言,是一种伟大的语言,它支持广泛的应用程序开发,从简单的文字处理到 WWW 浏览器再到游戏。
1. python2和python3 的区别有哪些?
python2和python3分别是python的两个版本
【1】print方法
python2既可以使用小括号的方式,也可以使用一个空格来分隔打印内容,比如 print ‘hi’;
python3使用print必须要用小括号包含打印内容,比如print(“hi”)
【2】编码
python2中使用ASCII编码,需要更改更改字符集(添加coding:utf-8)才能正常支持中文
python3中使用utf-8,支持中文
【3】除法运算
python2中 / 除法规则是整除,结果为整数,把小数部分完全忽略掉,要想真除需要转为浮点数再除
//整数相除,与/相同,取整
python3 / 是真除,会得到小数
// 是地板除,取整
【4】数据类型
python2整型有长整形和整型
python3只有整型,范围是无限大
【5】python3中有f格式化,python2用%格式化
python2:
yourname = 'Hongyu'
hisname = 'lijiang'
print 'You are %s , he is %s .', %( yourname, hisname)
python3:
yourname = 'Hongyu'
hisname = 'lijiang'
print(f'You are {
yourname}, he is {
hisname}.')
【6】range方法
python3中没有xrange方法,只有range方法
python2中range(1,10)返回列表,python3返回range可迭代对象,节约内存
【7】市场差异
python2:官方通知python2 2020开始不再维护,但企业很多代码都是python2,python2有很大的用户基群故会出现历史遗留问题,需要很长时间的迁移过度到python3
python3:最新版本,但目前市场使用量不大
【8】字符串
python2中Unicode表示字符串序列,str表示字节序列
python3中str表示字符串序列,byte表示字节序列
【9】input
在Python2中raw_input()和input( ),两个函数都存在,其中区别为:
1)raw_input():将所有输入作为字符串看待,返回字符串类型
2)input():只能接收"数字"的输入,在对待纯数字输入时具有自己的特性,它返回所输入的数字的类型(int, float )
在Python3中raw_input()和input( )进行了整合,去除了raw_input(),仅保留了input()函数,其接收任意任性输入,将所有输入默认为字符串处理,并返回字符串类型。
【10】异常处理
1)Python2中捕获异常的语法为except exc, var,Python3中捕获异常的语法为except exc as var,使用语法except (exc1, exc2) as var可以同时捕获多种类别的异常。 Python 2.6已经支持这两种语法。
2)在Python2时代,所有类型的对象都是可以被直接抛出的,在Python3时代,只有继承自BaseException的对象才可以被抛出。
3)Python2中触发异常可以用raise IOError, "file error"或raise IOError(“file error”)两种方式,Python3中触发异常只能用raise IOError("file error”)。
4)异常StandardError 被Python3废弃,统一使用Exception
5)在Python2时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在Python3中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。
【11】比较符
Python2 中任意两个对象都可以比较,11 < 'test’返回True
Python3中只有同一数据类型的对象可以比较,11 < 'test’报错,需要调用正则判断
import re
11 < int('test') if re.compile('^[0-9]+$').match('test') else 0
【12】包的定义
Python2:文件夹中必须有 __init __
.py文件
Python3:不需要有 __init __
.py文件
【13】打开文件
Python2中使用file( … ) 或 open(…)
Python3中只能使用open(…)
【14】 Python3 对 Unicode 字符的原生支持。
Python2 中使用 ASCII 码作为默认编码方式导致 string 有两种类型 str 和 unicode,Python3 只支持 unicode 的 string。Python2 和 Python3 字节和字符对应关系为:
python2 | python3 | 表现 | 转换 | 作用 |
---|---|---|---|---|
str | bytes | 字节 | encode | 存储 |
unicode | str | 字符 | decode | 显示 |
【15】Python3 采用的是绝对路径的方式进行 import
Python2 中相对路径的 import 会导致标准库导入变得困难(想象一下,同一目录下有 file.py,如何同时导入这个文件和标准库 file)。Python3 中这一点将被修改,如果还需要导入同一目录的文件必须使用绝对路径,否则只能使用相关导入的方式来进行导入。
【16】 Python2 中存在老式类和新式类的区别,Python3 统一采用新式类。新式类声明要求继承 object,必须用新式类应用多重继承。
【17】 Python3 使用更加严格的缩进。Python2 的缩进机制中,1 个 tab 和 8 个 space 是等价的,所以在缩进中可以同时允许 tab 和 space 在代码中共存。这种等价机制会导致部分 IDE 使用存在问题。
Python3 中 1 个 tab 只能找另外一个 tab 替代,因此 tab 和 space 共存会导致报错:
TabError:
inconsistent use of tabs and spaces in indentation.
【18】第三方工具包差异
【19】工具安装问题
2. 八大应用领域:
- 人工智能
- 计算与数据分析
- 自动化运维
- 云计算
- 游戏开发
- 网络爬虫
- web开发
- 网络编程
3.Python 特点:
-
易于学习:Python有相对较少的关键字,结构简单,和一个明确定义的语法,学习起来更加简单。
-
易于阅读:Python代码定义的更清晰。
-
易于维护:Python的成功在于它的源代码是相当容易维护的。
-
一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和 Macintosh兼容很好。
-
互动模式:互动模式的支持,您可以从终端输入执行代码并获得结果的语言,互动的测试和调试代码片断。
-
可移植:基于其开放源代码的特性,Python已经被移植(也就是使其工作)到许多平台。
-
可扩展:如果你需要一段运行很快的关键代码,或者是想要编写一些不愿开放的算法,你可以使用C或C++完成那部分程序, 然后从你的Python程序中调用。
-
数据库:Python提供所有主要的商业数据库的接口。
-
GUI编程:Python支持GUI可以创建和移植到许多系统调用。
-
可嵌入: 你可以将Python嵌入到C/C++程序,让你的程序的用户获得"脚本化"的能力。
4.Python缺点
-
运行速度,有速度要求的话,用 C++ 改写关键部分吧。
-
国内市场较小(国内以 Python 来做主要开发的,目前只有一些 web2.0 公司)。但时间推移,目前很多国内软件公司,尤其是游戏公司,也开始规模使用他。
-
中文资料匮乏(好的 Python 中文资料屈指可数,现在应该变多了)。托社区的福,有几本优秀的教材已经被翻译了,但入门级教材多,高级内容还是只能看英语版。
-
构架选择太多(没有像 C# 这样的官方 .net 构架,也没有像 ruby 由于历史较短,构架开发的相对集中。Ruby on Rails 构架开发中小型web程序天下无敌)。不过这也从另一个侧面 说明, python比较优秀,吸引的人才多,项目也多。
5. Python优点:
- 语法简洁,容易从类C语言转型,可以快速上手。
- 代码优雅,容易阅读。
- 使用方便,有大量的内置类型和模块,以及第三方模块。
- 思想和风格保持一致性,很多代码的思路都相通,很少出现格外突兀的诧异。
二、Python基础语法
1. 编程和执行python
Python中默认的编码格式是 ASCII 格式;python2.x 脚本加上 # -- coding: UTF-8 --或者 # coding=utf-8 Windows下,会出现乱码,解决办法:
,string.decode(“utf-8”).encode(“gbk”)即可;
Python3.X 源码文件默认使用utf-8编码,所以可以正常解析中文,无需指定 UTF-8 编码。
print语法:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
参数
-
objects – 复数,表示可以一次输出多个对象。输出多个对象时,需要用 , 分隔。
-
sep – 用来间隔多个对象,默认值是一个空格。
-
end – 用来设定以什么结尾。默认值是换行符 \n,我们可以换成其他字符串。
-
file – 要写入的文件对象。
-
flush – 输出是否被缓存通常决定于 file,但如果 flush 关键字参数为 True,流会被强制刷新。
返回值无。
注意:
在Windows系统上,没有“可执行模式”的概念。 Python安装程序自动将 .py 文件与 python.exe相关联,这样双击Python文件就会将其作为脚本运行。 扩展也可以是 .pyw ,在这种情况下,会隐藏通常出现的控制台窗
口。
【1】 交互式编程
交互式编程不需要创建脚本文件,是通过 Python 解释器的交互模式进来编写代码。
用例:
>>> print("Hello, Python!")
【2】脚本式编程
所谓脚本,就是你写的 .py 程序。
通过脚本参数调用解释器开始执行脚本,直到脚本执行完毕。当脚本执行完成后,解释器不再有效。
新建脚本:test.py
print("Hello, Python!")
写好上面的代码,然后保存。
注意:
windows下,脚本必须建在可执行的根目录。否则,不可执行,解决办法:cd path path为脚本所在目录。比如说:我的在H:\test\test.py ,那么:
> H:
> cd test
>python
OK,可以了。执行下面的:
用例:
> python test.py
让我们尝试另一种方式来执行 Python 脚本。修改 test.py 文件,如下所示:
实例:
#!/usr/bin/env python
print ("Hello, Python!")
在BSD等类Unix系统上,Python脚本可以直接执行,就像shell脚本一样,第一行添加:
#!/usr/bin/env python3.10,(假设解释器位于用户的 PATH )脚本的开头,并将文件设置为可执行。 #! 必须是文件的前两个字符。在某些平台上,第一行必须以Unix样式的行结尾(‘\n’)结束,而不是以Windows(‘\r\n’)行结尾。请注意,散列或磅字符 ‘#’ 在Python中代表注释开始。
这里,假定您的Python解释器在/usr/bin目录中,可以使用 chmod 命令为脚本提供可执行模式或权限。
$ chmod +x test.py
windows下,执行脚本:
- 编写bat (windows批处理脚本)记事本新建test.bat.内容:
@echo off
:start H:
::1脚本所在盘符,盘符后跟半角英文:
cd test
::2脚本所在目录,可以看到脚本
call python test.py
::3在批处理执行过程中调用另一个批处理,启用python并打开test.py
pause
编写好后,右键单击打开即可。
- 将python脚本打包成.exe文件
首先安装PyInstaller,网址:http://www.pyinstaller.org/
在cmd窗口下使用指令 pip install pyinstaller进行安装。安装好之后,打开命令提示符/shell 窗口,导航到 .py 文件所在的目录,然后使用以下命令pyinstaller your_program.py构建应用程序:
pyinstaller H:\test\test.py --distpath H:\dist
distpath意思是打包后的目录,在该目录中找到test.exe双击即可。
注意:
Python2.x 中使用 Python3.x 的 print 函数,
如果 Python2.x 版本想使用 Python3.x 的 print 函数,可以导入 __future__
包,
该包禁用 Python2.x 的 print 语句,采用 Python3.x 的 print 函数:
实例:
>>> list =["a", "b", "c"]
>>> print list # python2.x 的 print 语句
['a', 'b', 'c']
>>> from __future__ import print_function # 导入 __future__ 包
>>> print list # Python2.x 的 print 语句被禁用,使用报错
File "<stdin>", line 1
print list
^
SyntaxError: invalid syntax
>>> print (list) # 使用 Python3.x 的 print 函数
['a', 'b', 'c']
>>>
Python3.x 与 Python2.x 的许多兼容性设计的功能可以通过 __future__
这个包来导入。
2. Python 标识符
-
在 Python 里,标识符由字母、数字、下划线组成。
-
在 Python 中,所有标识符可以包括英文、数字以及 下划线(_),但不能以数字开头。
-
Python 中的标识符是区分大小写的。
-
以下划线开头的标识符是有特殊意义的。以单下划线开头 _foo 的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用 from xxx import * 而导入。
-
以双下划线开头的 __foo 代表类的私有成员,以双下划线开头和结尾的
__foo__
代表。
Python 里特殊方法专用的标识,如__init__
() 代表类的构造函数。 -
Python 可以同一行显示多条语句,方法是用分号 ; 分开。
3. Python 保留字符
and exec not
assert finally or
break for pass
class from print
continue global raise
def if return
del import try
elif in while
else is with
except lambda yield
4. 同一行显示多条语句
Python可以在同一行中使用多条语句,语句之间使用分号(;)分割。
5. 多行语句
Python语句中一般以新行作为语句的结束符。但是我们可以使用斜杠( \)将一行的语句分为多行显示。
6. 多个语句构成代码组
缩进相同的一组语句构成一个代码块,我们称之代码组。像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。
我们将首行及后面的代码组称为一个子句(clause)。
7. 行和缩进
Python 的代码块不使用大括号 {} 来控制类,函数以及其他逻辑判断。python 最具特色的就是用缩进来写模块。
缩进的空白数量是可变的,但是所有代码块语句必须包含相同的缩进空白数量,这个必须严格执行。
IndentationError: unindent does not match any outer indentation level错误表明,
你使用的缩进方式不一致,有的是 tab 键缩进,有的是空格缩进,改为一致即可。
如果是 IndentationError: unexpected indent 错误, 则 python 编译器是在告诉你"Hi,老兄,你的文件里格式不对了,可能是tab和空格没对齐的问题",所有 python 对格式要求非常严格。
因此,在 Python 的代码块中必须使用相同数目的行首缩进空格数。
建议你在每个缩进层次使用 单个制表符 或 两个空格 或 四个空格 , 切记不能混用。
8. Python 引号
Python 可以使用引号( ’ )、双引号( " )、三引号( ‘’’ 或 “”" ) 来表示字符串,引号的开始与结束必须是相同类型的。其中三引号可以由多行组成,编写多行文本的快捷语法,常用于文档字符串,在文件的特定地点,被当做注释。
9. Python注释
程序里的注释是很重要的。它们可以用自然语言告诉你某段代码的功能是什么。在你想要临时移除一段代码时,你还可以用注解的方式将这段代码临时禁用。python中单行注释采用 # 开头。
#处于字符串内部,所以它就是引号结束前的字符串中的一部分,这时它只是一个普通字符,而不代表 注解的意思。
10. Python空行
函数之间或类的方法之间用空行分隔,表示一段新的代码的开始。类和函数入口之间也用一行空行分隔,
以突出函数入口的开始。
空行与代码缩进不同,空行并不是Python语法的一部分。书写时不插入空行,Python解释器运行也不会出错。
但是空行的作用在于分隔两段不同功能或含义的代码,便于日后代码的维护或重构。
记住:空行也是程序代码的一部分。
11. 等待用户输入
python2.7----> raw_input(“你要说的内容,enter退出,其它键显示…”)
python3.x----> input(“你要说的内容,enter退出,其它键显示…”)
12. print 输出
print 默认输出是换行的,如果要实现不换行需要在变量末尾加上逗号 , 跟上。
13. 命令行参数
很多程序可以执行一些操作来查看一些基本信息,Python 可以使用 -h 参数查看各参数帮助信息。
例如:
- 在命令行运行 python test.py one two three
- argparse 模块提供了一种更复杂的机制来处理命令行参数。
- python top.py --lines=5 testa.txt testb.txt 在命令行运行时,该脚本会将 args.lines 设为 5 并将 args.filenames 设为 [‘testa.txt’, ‘testb.txt’]。
这里只作简单的了解,详细的慢慢探索吧…
三、 数字、字符串和文本
Python 内置数据类型
数值类型: int, float, complex
文本类型: str
序列类型: list, tuple, range
映射类型: dict
集合类型: set, frozenset
布尔类型: bool
二进制类型: bytes, bytearray, memoryview
1. 数值类型:数字(number)
每一种编程语言都包含处理数字和进行数学计算的方法。那么都有哪些数字类型呢?
Python 支持四种不同的数值类型:
- int 整型(Int) - 通常被称为是整型或整数,
是正或负整数,不带小数点。 - long 长整型(long integers) - 无限大小的整数,
整数最后是一个大写或小写的L。 - float 浮点型(floating point real values) -浮点型
由整数部分与小数部分组成,浮点型也可以使用科学 计数法表示(2.5e2 = 2.5 x 102 = 250) - complex 复数(complex numbers) - 复数
由实数部分(real)和虚数部分(imag)构成,
复数的虚部以j或者J作为后缀,具体格式为:
a + bj,或者complex(a,b)表示,复数的实部a 和虚 部b都是浮点型。 - random 内置模块,可用于生成随机数。
|------|-----------------------|------------|-------------|
| int | long | float | complex |
|------|-----------------------|------------|-------------|
| 10 | 51924361L | 0.0 | 3.14j |
|------|-----------------------|------------|-------------|
|100 | -0x19323L | 15.20 | 45.j |
|------|-----------------------|------------|-------------|
|-786 | 0122L | -21.9 | 9.322e-36j |
|------|-----------------------|------------|-------------|
|080 | 0xDEFABCECBDAECBFBAEl | 32.3+e18 | .876j |
|------|-----------------------|------------|-------------|
|-0490 | 535633629843 | -90. | -.6545+0J |
|------|-----------------------|------------|-------------|
|-0x260| -052318172735L | -32.54e100 | 3e+26J |
|------|-----------------------|------------|-------------|
|0x69 | -4721885298529L | 70.2-E12 | 4.53e-7j |
|------|-----------------------|------------|-------------|
长整型也可以使用小写"L",但是还是建议您使用大写"L",避免与数字"1"混淆。Python使用"L"来显示长整型。
Python 还支持其他数字类型,例如 Decimal 或 Fraction。Python 还内置支持 复数,后缀 j 或 J 用于表示虚数(例如 3+5j )。
Python支持复数,复数由实数部分和虚数部分构成,可以用a + bj,或者complex(a,b)表示,复数的实部a和虚部b都是浮点型。
Python 全面支持浮点数;混合类型运算数的运算会把整数转换为浮点数。
Python Number 类型转换
int(x [,base ]) 将x转换为一个整数
long(x [,base ]) 将x转换为一个长整数
float(x ) 将x转换到一个浮点数
complex(real [,imag ]) 创建一个复数
str(x ) 将对象 x 转换为字符串
repr(x ) 将对象 x 转换为表达式字符串
eval(str ) 用来计算在字符串中的有效Python
表达式, 并返回一个对象
tuple(s ) 将序列 s 转换为一个元组
list(s ) 将序列 s 转换为一个列表
chr(x ) 将一个整数转换为一个字符
unichr(x ) 将一个整数转换为Unicode字符
ord(x ) 将一个字符转换为它的整数值
hex(x ) 将一个整数转换为一个十六进制字符串
oct(x ) 将一个整数转换为一个八进制字符串
2. 文本类型:字符串(string)
字符串通常是指你想要展示给别人的、或者是你想要从程序里“导出”的一小段字符。字符串是Python 中最常用的数据类型。
字符串或串(String)是由数字、字母、下划线组成的一串字符。字符串是对数据的封装。
字符串有多种表现形式,我们可以使用双引号 ( ‘’ 或 “” ) 来识别和创建字符串。
在很多应用场景中,我们需要将字符串和数字拼接在一起,而 Python 不允许直接拼接数字和字符串,所以我们必须先将数字转换成字符串。可以借助 str() 和 repr() 函数将数字转换为字符串。
语法:
str(obj)
repr(obj)
二选一,其中obj 表示要转换的对象,它可以是数字、列表、元组、字典等多种类型的数据。
str() 和 repr() 函数虽然都可以将数字转换成字符串,但它们之间是有区别的:
1)str() 用于将数据转换成适合人类阅读的字符串形式。
2)repr() 用于将数据转换成适合解释器阅读的字符串形式(Python 表达式的形式),适合在开发和调试阶段使用;如果没有等价的语法,则会发生 SyntaxError 异常。
从本质上讲,字符串是由多个字符构成的,字符之间是有顺序的,这个顺序号就称为索引(index)。Python 允许通过索引来操作字符串中的单个或者多个字符,比如获取指定索引处的字符,返回指定字符的索引值等。
- 转义序列 (escape sequences)
在需要在字符中使用特殊字符时,python 用反斜杠 \ 转义字符。如下表:
转义字符 描述
\(在行尾时) 续行符
\\ 反斜杠符号
\' 单引号
\" 双引号
\a 响铃
\b 退格(Backspace)
\e 转义
\f 换页
\n 换行
\N{} Unicode数据库中的字符名,其中name是它的名字,仅Unicode适用
\ooo 值为8进制ooo的字符
\oyy 八进制数,y 代表 0~7 的字符,例如:\012 代表换行。
\other 其它的字符以普通格式输出
\r 回车
\t 横向制表符
\v ASCⅡ垂直(纵向)制表符
\uxxxx 值为16位十六进制xxxx的字符
\Uxxxxxxxx 值为32位十六进制xxxx的字符
\xyy 十六进制数,以 \x 开头,yy代表的字符,例如:\x0a代表换行
\000 空
如果不希望前置 \ 的字符转义成特殊字符,可以使用 原始字符串,在引号前添加 r 即可。
- 字符串格式化
Python2.6 开始,新增了一种格式化字符串的函数str.format(),它增强了字符串格式化的功能。还有在字符串前加前缀 f 或 F的 f’str’ 或者 f"str"手动格式化字符串:字符串对象的 str.rjust() 方法通过在左侧填充空格,对给定宽度字段中的字符串进行右对齐。
同类方法还有 str.ljust() 和 str.center() 。这些方法不写入任何内容,只返回一个新字符串,如果输入的字符串太长,它们不会截断字符串,而是原样返回;虽然这种方式会弄乱列布局,但也比另一种方法好,后者在显示值时可能不准确(如果真的想截断字符串,可以使用 x.ljust(n)[:n] 这样的切片操作 。)
另一种方法是 str.zfill() ,该方法在数字字符串左边填充零,且能识别正负号。
旧式字符串格式化方法:
符 号 描述
%c 格式化字符及其ASCII码
%s 格式化字符串
%d 格式化整数
%u 格式化无符号整型
%o 格式化无符号八进制数
%x 格式化无符号十六进制数
%X 格式化无符号十六进制数(大写)
%f 格式化浮点数字,可指定小数点后的精度
%e 用科学计数法格式化浮点数
%E 作用同%e,用科学计数法格式化浮点数
%g %f和%e的简写
%G %F 和 %E 的简写
%p 用十六进制数格式化变量的地址
格式化操作符辅助指令:
符号 功能
* 定义宽度或者小数点精度
- 用做左对齐
+ 在正数前面显示加号( + )
<sp> 在正数前面显示空格
# 在八进制数前面显示零('0'),在十六进制前面显示'0x' 或者'0X'(取决于用的是'x'还是'X')
0 显示的数字前面填充'0'而不是默认的空格
% '%%'输出一个单一的'%'
(var) 映射变量(字典参数)
m.n. m 是显示的最小总宽度,n 是小数点后的位数(如果可用的话)
- 三引号 (triple-quotes)
字符串字面值可以包含多行。 一种实现方式是使用三重引号:“”“…”“” 或 ‘’‘…’‘’。 字符串中将自动包括行结束符,但也可以在换行的地方添加一个 \ 来避免此情况。
Python 中三引号可以将复杂的字符串进行赋值和注释。
Python 三引号允许一个字符串跨多行,字符串中可以包含换行符、制表符以及其他特殊字符。
三引号的语法是一对连续的单引号或者双引号(通常都是成对的用)。
- Unicode 字符串
Python 中定义一个 Unicode 字符串和定义一个普通字符串一样简单:
输入执行:
>>> u'Hello World !'
输出结果:
u'Hello World !'
引号前小写的"u"表示这里创建的是一个 Unicode 字符串。如果你想加入一个特殊字符,可以使用Python 的 Unicode-Escape 编码。如下例所示:
输入执行:
>>> u'Hello\u0020World !'
输出结果:
u'Hello World !'
被替换的 \u0020 标识表示在给定位置插入编码值为 0x0020 的 Unicode 字符(空格符)。
3. 文本类型:中文文本
@@ 如果要保持文本原样输出,我们只需要用引号"文本"或’文本’就可以了。
那么没引号呢?下面介绍:
计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。
ASCII编码和Unicode编码的区别:
ASCII编码是1个字节,而Unicode编码通常是2个字节,举例如下:
字母 A 用ASCII编码是十进制的65,二进制的01000001;
字符 0 用ASCII编码是十进制的48,二进制的00110000,注意字符 '0' 和整数 0 是不同的;
汉字 中 已经超出了ASCII编码的范围,用Unicode编码是十进制的20013,二进制的01001110 00101101。
如果把ASCII编码的 A 用Unicode编码,只需要在前面补0就可以,因此, A 的Unicode 编码是 00000000 01000001。
windows python2.7 的环境,中文编码默认使用 gbk: 许多模块返回的、或使用的字符串是 unicode,故而需要转码。
例如,xxx 模块 tmp_fun() 返回的字符串是 unicode 字符,而另一个模块 yyy 模块 fun_tmp() 返回的字符串是 gbk 字符,我们现在需要判断两个返回值是否相等。可以使用如下两种方式进行判断。
import xxx
import yyy
if tmp_fun()==fun_tmp().decode("gbk"):
print "eq"
'''
decode("gbk")作用为将gbk编码转为unicode编码
'''
或者
import xxx
import yyy
if tmp_fun().encode("gbk")==fun_tmp()
print "eq"
'''
encode("gbk")作用为将unicode编码转为gbk编码
'''
四、变量(variable)
变量只不过是用来指代某个东西的名字。程序员通过使用变量名可以让他们的程序读起来更像英语。
而且因为程序员的记性都不怎么地,变量名可以让他们更容易记住程序的内容。
1. 变量的命名(name)或赋值(assignment)
例子:
cars = 100
space_in_a_car = 4.0
drivers = 30
passengers = 90
cars_not_driven = cars - drivers
cars_driven = drivers
carpool_capacity = cars_driven * space_in_a_car
average_passengers_per_car = passengers / cars_driven
print("There are", cars, "cars available.")
print("There are only", drivers, "drivers available.")
print("There will be", cars_not_driven, "empty cars today.")
print("We can transport", carpool_capacity, "people today.")
print("We have", passengers, "to carpool today.")
print("We need to put about", average_passengers_per_car, "in each car.")
等号 = 用来给变量赋值。或者说命名也可以!!!每个变量都拥有独一无二的名字,通过变量的名字就能找到变量中的数据。
等号 = 运算符左边是一个变量名,等号 = 运算符右边是存储在变量中的值。
Python 中的变量赋值不需要类型声明。
每个变量在使用前首先都必须赋值,其次变量赋值以后该变量才会被创建。
每个变量在内存中创建,都包括变量的标识,名称和数据这些信息。
多个对象指定多个变量用逗号(comma),隔开,例如:
a, b, c = 36, 'car', "hello, world!"
变量是存放数据值的容器。
备注:给变量、常量、函数、语句块等起的名字被称之为“标识符”。
变量名命名规则:name = value
-
变量名通常由字母,数字,下划线组成,但不能以数字开头;
-
变量名不能包含空格,但可使用下划线来分隔其中的单词;
-
不能以python中的关键字命名;
-
变量名应既简短又具有描述性;
-
慎用易混淆的字符:小写字母l和大写字母O,因给他们可能被人错看成数字1和0,中英标点符号也易混淆;
-
变量名要区分大小写;
-
推荐使用驼峰型(GuessAge或guessAge)和下划线(guess_age)来命名;
-
常量通常使用大写来定义。
驼峰命名法详解:
当变量名是由二个或多个单词组成时,还可以利用驼峰命名法来命名。
小驼峰式命名法:
第一个单词以小写字母开始,后续单词的首字母大写。
例如:firstName、lastName
大驼峰式命名法:
每一个单词的首字母都采用大写字母。
例如:FirstName、LastName、CamelCase
2. 标准数据类型
变量是存储在内存中的值,这就意味着在创建变量时会在内存中开辟一个空间。
基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中。
变量是没有类型的。因此,变量可以指定(定义)不同的数据类型,这些变量可以存储数字或字符等。
在内存中存储的数据可以有多种类型。
这里介绍六个标准的数据类型,举例赋值:
1. Numbers (数字) a = 1.05
2. String (字符串) str = "我在学python。"
3. List (列表) list = [258, 369, 'nomi', 'jion']
4. Tuple (元组) tuple = (258, 369, 'nomi', 'jion')
5. Dictionary(字典) dic = {258, 369, 'nomi', 'jion'}
6. set (集合) set = {258, 369, 'nomi', 'jion'}
这里明确了解变量是怎么样子,其它的我们简单了解就可以了,后续会有详细的介绍。
变量赋值简单粗暴不需要声明类型, 灵活多变,非常好用。
数字数据类是不可改变的数据类型,改变数字数据类型会分配一个新的对象。
字符串用 “” 或 ‘’ 标识。
列表用 “[ ]” 标识的数组。
元组用 “( )” 标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。
字典用 “{ }” 标识。字典由索引 key 和它对应的值 value 组成。
集合用 “{ }” 标识。集合并非字典,字面表达意思不一样,只是同样使用了{}而已。
关于类型不多作介绍,更多数据类型可参考:
https://docs.python.org/zh-cn/3/library/stdtypes.html#context-manager-types
3. 变量作用域
一个程序的所有的变量并不是在哪个位置都可以访问的。访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序你可以访问哪个特定的变量名称。两种最基本的变量作用域如下:
- 全局变量:定义在函数外的拥有全局作用域
- 局部变量:定义在函数内部的变量拥有一个局部作用域局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
全局变量想作用于函数内,需加 global:
- global—将变量定义为全局变量。可以通过定义为全局变量,实现在函数内部改变变量值。
- 一个global语句可以同时定义多个变量,如 global x, y, z。
用例:
global = 0 # 这是一个全局变量
# 可写函数说明
def sum( arg1, arg2 ):
#返回2个参数的和."
global = arg1 + arg2 # global在这里是局部变量.
print("函数内是局部变量 : ", global)
return global
#调用sum函数
sum( 10, 20 )
print "函数外是全局变量 : ", global
五、 运算符
Python语言支持以下类型的运算符:
1. 算术运算符
2. 比较(关系)运算符
3. 赋值运算符
4. 逻辑运算符
5. 位运算符
6. 成员运算符
7. 身份运算符
8. 三目运算符
各类运算符介绍:
1. 算术运算符
以下假设变量: a=10,b=20:
运算符 描述 实例
+ 加 - 两个对象相加 a + b 输出结果 30
- 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -10
* 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200
/ 除 - x除以y b / a 输出结果 2
% 取模 - 返回除法的余数 b % a 输出结果 0
** 幂 - 返回x的y次幂 a**b 为10的20次方, 输出结果 :100000000000000000000
// 取整除 - 返回商的整数部分(向下取整) >>> 9//2
4
>>> -9//2
-5
注意:Python2.x 里,整数除整数,只能得出整数。如果要得到小数部分,把其中一个
数改成浮点数即可。
2. 比较运算符
以下假设变量a为10,变量b为20:
运算符 描述 实例
== 等于 - 比较对象是否相等 (a == b) 返回 False。
!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 True。
<> 不等于 - 比较两个对象是否不相等。python3 已废弃。 (a <> b) 返回 True。这个运算符类似 != 。
> 大于 - 返回x是否大于y (a > b) 返回 False。
< 小于 - 返回x是否小于y。所有比较运算符返回1表示真,
返回0表示假。这分别与特殊的变量 True 和 False 等价。(a < b) 返回 True。
>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。
<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 True。
3. 赋值运算符
以下假设变量a为10,变量b为20:
运算符 描述 实例
= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c **= a 等效于 c = c ** a
//= 取整除赋值运算符 c //= a 等效于 c = c // a
4. 位运算符
按位运算符是把数字看作二进制来进行计算的。Python中的按位运算法则如下:
下表中变量 a 为 60,b 为 13,二进制格式如下:
a = 0011 1100
b = 0000 1101
-----------------
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011
运算符 描述 实例
& 按位与运算符:参与运算的两个值,如果两个相应位都为1,
则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100
| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 (a | b) 输出结果 61 , 二进制解释: 0011 1101
^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 , 二进制解释: 0011 0001
~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,
把0变为1 。~x 类似于 -x-1 (~a ) 输出结果 -61 , 二进制解释: 1100 0011,在一个有符号二进制数的补码形式。
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的
数字指定了移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 , 二进制解释: 1111 0000
>> 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,
>> 右边的数字指定了移动的位数 a >> 2 输出结果 15 , 二进制解释: 0000 1111
5. Python逻辑运算符
Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20:
运算符 逻辑表达式 描述 实例
and x and y 布尔"与" - 如果 x 为 False,
x and y 返回 False,
否则它返回 y 的计算值。 (a and b) 返回 20。
or x or y 布尔"或" - 如果 x 是非 0,
它返回 x 的计算值,否则它
返回 y 的计算值。 (a or b) 返回 10。
not not x 布尔"非" - 如果 x 为 True,
返回 False 。如果 x 为 False,
它返回 True。 not(a and b) 返回 False
在 python 中我们会用到下面的术语(字符或者词汇)来定义事物的真(True)或者假(False)。计算机的逻辑就是在程序的某个位置检查这些字符或者变量组合在一起表达的结果是真是假。
• and 与
• or 或
• not 非
• != (not equal) 不等于
• == (equal) 等于
• >= (greater-than-equal) 大于等于
• <= (less-than-equal) 小于等于
• True 真
• False 假
布尔真值表
NOT | True ? |
---|---|
not False | True |
not True | False |
OR | True ? |
---|---|
True or False | True |
True or True | True |
False or True | True |
False or False | False |
AND | True ? |
---|---|
True and False | False |
True and True | True |
False and True | False |
False and False | False |
NOT OR | True ? |
---|---|
not (True or False) | False |
not (True or True) | False |
not (False or True) | False |
not (False or False) | True |
NOT | ANDTrue ? |
---|---|
not (Trueand False) | True |
not (Trueand True) | False |
not (Falseand True) | True |
not (Falseand False) | True |
!= | True ? |
---|---|
1 != 0 | True |
!= | True ? |
---|---|
1 != 1 | False |
0 != 1 | True |
0 != 0 | False |
== | True ? |
---|---|
1 == 0 | False |
1 == 1 | True |
0 == 1 | False |
0 == 0 | True |
布尔表达式练习:
1. True and True
2. False and True
3. 1 == 1 and 2 == 1
4. "test" == "test"
5. 1 == 1 or 2 != 1
6. True and 1 == 1
7. False and 0 != 0
8. True or 1 == 1
9. "test" == "testing"
10. 1 != 0 and 2 == 1
11. "test" != "testing"
12. "test" == 1
13. not (True and False)
14. not (1 == 1 and 0 != 1)
15. not (10 == 1 or 1000 == 1000)
16. not (1 != 10 or 3 == 4)
17. not ("testing" == "testing" and "Zed" == "Cool Guy")
18. 1 == 1 and not ("testing" == 1 or 1 == 0)
19. "chunky" == "bacon" and not (3 == 4 or 3 == 3)
20. 3 == 3 and not ("testing" == "testing" or "Python" == "Fun")
- 看看自己做对了多少?
6. 成员运算符
除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。
运算符 描述 实例
in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。
not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 ,如果 x 不在 y 序列中返回 True。
- 身份运算符
身份运算符用于比较两个对象的存储单元。
运算符 描述 实例
is is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则 返回 True,否则返回 False
is not is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(a) != id(b)。如果引用的不是同一个对象则返回结果True,否则返回 False。
注: id() 函数用于获取对象内存地址。
脚本模式 is 和==
结果是一样的。is 只是传递的指针,判断是否指向同一个地址块,这样 is 两边的参数指向内存中同个地址块。而==
则是仅仅判断值相同。is 关键字判断两个小一点数,的确和==
运算符一样,结果同为 true,但是这个小一点数取值到底小到多少,上限多少,经过测试,当数小于等于 256 时,两者结果相同,大于 256 后,is 判断结果就为 false 了。猜测:256 刚好为 8 为二进制数,是一个字节,所以可以归纳为当数可以用一个字节来表示时,is 和==
结果相同,当数超过一个字节时, 按不同对象来对待,python 为不同数分配了不同内存,不同数为不同的对象,只是值相同而已,is 结果为 false,==
依然为 true。python 创建了一个小型整型池来存放这些可以用一个字节表示的数,这样做避免了为小点数值重复分配内存,也即重复创建对象,而是直接引用已经存在的对象,
提高了语言运行性能。
8. 三目运算符
我们从一个具体的例子切入。假设现在有两个数字,我们希望获得其中较大的一个,那么可以使用if else 语句,例如:
if a>b:
max = a;
else:
max = b;
但是 Python 提供了一种更加简洁的写法,如下所示:
max = a if a>b else b
类似于其它编程语言中三目运算符 ?: 的写法。Python 是一种极简主义的编程语言,它没有引入?: 这个新的运算符,而是使用已有的 if else 关键字来实现相同的功能。
9. Python运算符优先级
从最高到最低优先级的所有运算符:
运算符 描述
'expression,...' 字符串转换
{key:datum,...} 字典显示
[expression,...] 列表显示
(experession,...) 绑定或元组显示
f(arguments...) 函数调用
x[index:index] 寻址段
x[index] 下标
x.attribute 属性参考
** 指数 (最高优先级)
~ + - 按位翻转, 一元加号和减号 (最后两个的方法名为 +@ 和 -@)
* / % // 乘,除,取模和取整除
+ - 加法减法
>> << 右移,左移运算符
& 位 'AND'与
^ 位异或运算符
| 位或运算符
<= < > >= 比较运算符
<> == != 等于运算符
= %= /= 赋值运算符
//= -= += 赋值运算符
*= **= 赋值运算符
is is not 身份运算符
in not in 成员运算符
not bool(布尔)非 逻辑运算符
and bool(布尔)与 逻辑运算符
or bool(布尔)或 逻辑运算符
lambda Lambda 表达式(优先级最低)
六、数据的接收和输出
python2.x读取键盘输入raw_input([prompt])
python3.x读取键盘输入input([prompt]),但是可以接收表达式,并将运算结果返回。
一般软件做的事情主要就是下面几条:
- 接受人的输入。
- 改变输入。
- 打印出改变了的输入
python2.x:
print "How old are you?",
age = raw_input()
print "How tall are you?",
height = raw_input()
print "How much do you weigh?",
weight = raw_input()
print "So, you're %r old, %r tall and %r heavy." % (
age, height, weight)
python3.x:
print("How old are you?", end=' ')
age = input()
print("How tall are you?", end=' ')
height = input()
print("How much do you weigh?", end=' ')
weight = input()
print(f"So, you're {
age} old, {
height} tall and {
weight} heavy.")
键盘键入:
How old are you? 18
How tall are you? 165
How much do you weight? 50
打印出的输出结果:
So, you're 18 old, 165 tall and 50 heavy.
一次同时输入多个数据:
a, b = map(int,input('以逗号隔开: ').split(","))
print(type(a))
x = a + b
print(x)
要输入12和38这两个数据:
a = 12
b = 38
x = 50.0
以逗号隔开: 12,39
<class 'int'>
51
上面python3.x简化如下,达到提示别人的目的:
age = input("How old are you? ")
height = input("How tall are you? ")
weight = input("How much do you weigh? ")
print(f"So, you're {
age} old, {
height} tall and {
weight} heavy.")
键盘键入,打印出的输出结果:
How old are you? 18
How tall are you? 165
How much do you weight? 50
So, you're 18 old, 165 tall and 50 heavy.
七、函数(function)
def fib(n): # write Fibonacci series up to n
"""Print a Fibonacci series up to n."""
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
# Now call the function we just defined:
fib(int(input("请输入你要键入的数字:>")))
请输入你要键入的数字:>2000
输出:
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Python 提供了一个功能,即允许我们将常用的代码以固定的格式封装(包装)成一个独立的模块,
只要知道这个模块的名字就可以重复使用它,这个模块就叫做函数(Function)。
函数可以做三样事情:
- 它们给代码片段命名,就跟“变量”给字符串和数字命名一样。
- 它们可以接受参数。
- 通过使用 #1 和 #2,它们可以让你创建“微型脚本”或者“小命令”。
函数是把组织好的,可重复使用的,用来实现单一,或相关联功能的代码段封装起来。提高应用的模块性,和代码的重复利用率。
你已经知道Python提供了许多内置函数,比如print(),input()。但你也可以自己创建函数,这被叫做用户自定义函数。
python函数有两类:
- 内置函数
- 自定义函数:将实现特定功能的代码定义成一个函数。
自定义使用 def 新建函数。
将实现特定功能的代码定义成一个函数,每次当程序需要重复实现该功能时,只要执行(调用)该函数即可。
语法:
def functionname( *args ):
"函数_文档字符串"
function_suite
return [expression]
定义 函数使用关键字 def,后跟函数名与括号内的形参列表。函数语句从下一行开始并且必须缩进。
函数内的第一条语句是字符串时,该字符串就是文档字符串,也称为 docstring,详见文档字符串。利用文档字符串可以自动生成在线文档或打印版文档,还可以让开发者在浏览代码时直接查阅文档;Python 开发者最好养成在代码中加入文档字符串的好习惯。
也就是注释或注解。函数注解 是可选的用户自定义函数类型的元数据完整信息。
详见4.8.7.文档字符串:
https://docs.python.org/zh-cn/3/tutorial/controlflow.html#documentation-strings
函数在 执行 时使用函数局部变量符号表,所有函数变量赋值都存在局部符号表中;引用变量时,首先,在局部符号表里查找变量,然后,是外层函数局部符号表,再是全局符号表,最后是内置名称符号表。因此,尽管可以引用全局变量和外层函数的变量,但最好不要在函数内直接赋值(除非是 global 语句定义的全局变量,或 nonlocal 语句定义的外层函数变量)。
在调用函数时会将实际参数(实参)引入到被调用函数的局部符号表中;因此,实参是使用 按值调用 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)。 1 当一个函数调用另外一个函数时,会为该调用创建一个新的局部符号表。
函数定义在当前符号表中把函数名与函数对象关联在一起。解释器把函数名指向的对象作为用户自定义函数。还可以使用其他名称指向同一个函数对象,并访问访该函数。
一般来说,解释器不会输出单独的返回值 None ,如需查看该值,可以使用 print()
return [表达式] 语句返回函数的值。return 语句不带表达式参数时,返回 None。函数执行完毕退出也返回 None。
接下来我们分析演示:
-
首先我们告诉 Python 创建一个函数,我们使用到的命令是 def ,也就是“定义(define)”的意思。
-
紧接着 def 的是函数的名称。名字可以随便取也没关系。但最好函数的名称能够体现出函数的功能来。
-
然后我们告诉函数我们需要 *args (asterisk args),参数必须放 在圆括号 () 中才能正常工作。
-
接着我们用冒号 : 结束本行,然后开始下一行缩进。
-
冒号以下,使用 4 个空格缩进的行都是属于functionname的内容
“函数_文档字符串”
function_suite
return [expression] -
为了演示它的工作原理,我们把解包后的每个参数都打印出来,这和我们在之前脚本练习中所作的类似。
如下:test.py
#this one is like your scripts with argv
def print_two(*args):
arg1, arg2 = args
print(f"arg1: {
arg1}, arg2: {
arg2}")
#空行
#ok, that *args is actually pointless, we can just do this
def print_two_again(arg1, arg2):
print(f"arg1: {
arg1}, arg2: {
arg2}")
#空行
#this just takes one argument
def print_one(arg1):
print(f"arg1: {
arg1}")
#空行
#this one takes no arguments
def print_none():
print("I got nothin'.")
#空行
print_two("Zed","Shaw")
print_two_again("Zed","Shaw")
print_one("First!")
print_none()
1、参数、解包、变量
用例:test2.py
from sys import argv
script, first, second, third = argv
print("The script is called:", script)
print("Your first variable is:", first)
print("Your second variable is:", second)
print("Your third variable is:", third)
参数(argv)可以是接收的数据,数字,字符串,表达式,变量,也可以是组合,比如:数学表达式和变量的组合。
函数的方法名也可以作为另一个函数的参数。也可以叫 parameters都是参数( argument)的意思,argv是所谓的“参数变量(argument variable)”,是一个非常标准的编程术语。在其他的编程语言里你也可以看到它。这个变量包含了你传递给 Python 的参数。
调用函数时可使用的正式参数类型:
- 必备参数:以正确的顺序传入函数。调用时的数量必须和声明时的一样。例如:test2.py
- 关键字参数:函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。 - 默认参数:调用函数时,默认参数的值如果没有传入,则被认为是默认值。
- 不定长参数:函数能处理比当初声明时更多的参数。声明时不会命名。例如:test.py
argv “解包(unpack)”,在执行时与其将所有参数放到同一个变量下面,我们将每个参数赋予
一个变量名: script, first, second, 以及 third。
那么执行:
python test2.py 1st 2nd 3rd
它的含义很简单:“把 argv 中的东西解包,将所有的参数依次赋予(=)左边的变量名”。
python命令后跟的都是参数。4个。
*args是将参数解包,这和脚本参数解包的原理差不多。
前面我们使用 import 让你的程序实现更多的功能,但实际上没人吧 import 称为“功能”。我希望你可以在没接触到正式术语的时候就弄懂它的功能。在继续下去之前, 你需要知道它们的真正名称:模组(modules)。
从现在开始我们将把这些我们导入(import)进来的功能称作模组。你将看到类似这样的说法:“你需 要把 sys 模组 import 进来。”也有人将它们称作“库(libraries)”,
不过我们还是叫 它们模组吧。
记住“模组(modules)”为你提供额外功能。多读几遍把这个词记住,因为我们后面还会用到它。
叫模块也可以,后面是这么叫的。
2、提示和传递
参数接收区别:
- argv是在执行命令时输入参数,也就是在键入命令时,脚本还没有开始运行。
- python2.0,使用raw_input是在脚本运行的过程中需要输入。
python3.0,使用input是在脚本运行的过程中需要输入。
我们可以使用:
prompt = '>'
作为提示符提示,可以改成不同的值也是可以的。我们将用户提示符设置为变量 prompt,这样我们就不需要在每次用到 raw_input 时重复输入提示用户的字符了。而且如果你要将提示符修改成别的字串,你只要改一个位置就可以了。非常顺手吧。
函数()里面的参数会依次传递给{}里的变量或者对应位置的变量并替换{}。
3、函数调用
函数的本质就是一段有特定功能、可以重复使用的代码,如果需要同样的功能,直接通过起好的名字就可以调用这段代码。
运行上面的脚本test.py会看到如下结果:
执行:> python text.py
arg1: 'Zed', arg2: 'Shaw'
arg1: 'Zed', arg2: 'Shaw'
arg1: 'First!'
I got nothin'.
可以看到:
print_two("Zed","Shaw")
print_two_again("Zed","Shaw")
print_one("First!")
print_none()
这几个函数functionname部已被调用。*args部参数被解包依次被传递。
为自己写一个函数注意事项以供后续参考。你可以写在一个索引卡片上随时阅读,直到你记住所有的要点为止。注意事项如下:
1. 函数定义是以 def 开始的吗?
2. 函数名称是以字符和下划线 _ 组成的吗?
3. 函数名称是不是紧跟着括号 ( ?
4. 括号里是否包含参数?多个参数是否以逗号隔开?
5. 参数名称是否有重复?(不能使用重复的参数名)
6. 紧跟着参数的是不是括号和冒号 ): ?
7. 紧跟着函数定义的代码是否使用了 4 个空格的缩进 (indent)?
8. 函数结束的位置是否取消了缩进 (“dedent”)?
当你运行(或者说“使用 use”或者“调用
call”)一个函数时,记得检查下面的要点:
1. 调运函数时是否使用了函数的名称?
2. 函数名称是否紧跟着 ( ?
3. 括号后有无参数?多个参数是否以逗号隔开?
4. 函数是否以 ) 结尾?
按照这两份检查表里的内容检查你的练习,直到你不需要检查表为止。
最后,将下面这句话阅读几遍:
“‘运行函数(run)’、‘调用函数(call)’、和 ‘使用函数(use)’是同一个意思”
“‘运行函数(run)’、‘调用函数(call)’、和 ‘使用函数(use)’是同一个意思”
“‘运行函数(run)’、‘调用函数(call)’、和 ‘使用函数(use)’是同一个意思”
4. lambda匿名函数
在python中用【def + 函数名+参数】的方式定义函数,即:
>>> def function_name(parameters): ...
这样的函数拥有函数名,调用函数只需要
>>> function_name(input_parameter)
暂且把def定义的函数叫作“有名函数”,
那什么是匿名函数呢?顾名思义,这类函数没有显示地定义函数名。
认识匿名函数
匿名函数不需要显示地定义函数名,使用【lambda + 参数 +表达式】的方式,
匿名函数语法:
lambda [arg1 [,arg2,.....argn]]:expression
lambda只是一个表达式,函数体比def简单很多。
lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
也就是说,lambda用来表示匿名函数,可以传入多个参数,但只能有一个表达式。
下图可以看出匿名函数的独特之处
比方说,我要写一个函数用于两个数相乘
如果用def方式来写:
>>> def f(x,y):
... return x*y
>>> f(2,3)
6
用匿名函数来写:
>>> func = lambda x,y:x*y
可以看到,上面我们把匿名函数对象赋给一个变量,只要直接调用该对象就可以使用匿名函数:
>>> func(2,3)
6
你也可以给匿名函数传入一个参数:
>>> func_2 = lambda x:x^2
>>> func_2(3)
9
以上对匿名函数作了解释,也举了一些例子用以说明。那么,匿名函数的优点是什么呢?
匿名函数优点:
1. 使用Python写一些脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。
2.对于一些抽象的,不会被别的地方再重复使用的函数,有时候函数起个名字也是个难题,使用lambda不需要考虑命名的问题
3.使用lambda在某些时候然后代码更容易理解
不用取名称,因为给函数取名是比较头疼的一件事,特别是函数比较多的时候
可以直接在使用的地方定义,如果需要修改,直接找到修改即可,方便以后代码的维护工作。
语法结构简单,不用使用def 函数名(参数名):这种方式定义,直接使用lambda 参数:返回值 定义即可。
实例:
# 可写函数说明
sum = lambda arg1, arg2: arg1 + arg2;
# 调用sum函数
print ("相加后的值为 : ", sum( 10, 20 )) # 相加后的值为 : 30
print ("相加后的值为 : ", sum( 20, 20 )) # 相加后的值为 : 40
# 对字典排序
infors = [{
"name":"wang","age":10},{
"name":"xiaoming","age":20},{
"name":"banzhang","age":10}]
infors.sort(key=lambda x:x['age']) #根据age对字典排序
print(infors)
# 排序结果 [{
'name': 'wang', 'age': 10}, {
'name': 'banzhang', 'age': 10}, {
'name': 'xiaoming', 'age': 20}]
# 把lambda当一个变量def test(a,b,func):
result = func(a,b)
return result
num = test(11,22,lambda x,y:x+y)
print(num)
4、总结
- Python 内置函数
abs() file() map() staticmethod()
all() filter() max() str()
any() float() memoryview() sum()
basestring() format() min() super()
bin() frozenset() next() tuple()
bool() getattr() object() type()
breakpoint() globals() oct() vars()
bytearray() hasattr() open() zip()
bytes() hash() ord() __import__()
callable() help() pow()
chr() hex() print()
classmethod() id() property()
compile() input() range()
complex() int() repr()
delattr() isinstance() reversed()
dict() issubclass() round()
dir() iter() set()
divmod() len() setattr()
enumerate() list() slice()
eval() locals() sorted()
内置函数 ,可以python help(),也可以上网查,了解它们的意思与用处。
- 定义函数格式:
(1)无参数、无返回值
def 函数名():
代码
(2)无参数、有返回值
def 函数名():
语句
return 需要返回的数值
(3)有参数、无返回值
def 函数名(形参列表):
语句
(4)有参数、有返回值
def 函数名(形参列表):
语句
return 需要返回的数值
- 1.全局变量和局部变量使用
def test1():
a = 300 #局部变量
print('test1-----------修改前:a = %d'%a)
a = 100
print('test1-----------修改后:a = %d'%a)
def test2():
a = 500 #不同的函数可以定义相同的名字,彼此无关
print('test2-----------a = %d'%a)
test1()
test2()
- 2.全局变量和局部变量相同名字
a = 100 #全局变量
def test1():
a = 300 #局部变量优先使用
print('test1-----------修改前:a = %d'%a)
a = 200
print('test1-----------修改后:a = %d'%a)
def test2():
#a = 500 #不同的函数可以定义相同的名字,彼此无关
print('test2-----------a = %d'%a)
test1()
test2()
- 3.全局变量和局部变量相同名字
局部变量使用全局变量就要使用关键字global
a = 100 #全局变量
def test1():
global a
#声明全局变量在函数中的标识符,声明之后所有函数访问全局变量的值a
print(f'test1 修改前:a = {
a}')
a = 200
print(f'test1 修改后:a = {
a}')
def test2():
print(f'test2 : a = {
a}')#没有局部变量,默认使用全局变量
#输出test2 : a = 200
test1()
test2()
- 函数使用
#函数的定义
def printinfo():
print('--'*30)
print(' 人生苦短,我用python ')
print('--'*30)
#函数的调用
printinfo()
printinfo()
#带参数的函数
def add2Num(a,b):
c = a + b
print(c)
add2Num(11,22)
#带返回值的参数
def add2Num(a,b):
return a + b
result = add2Num(11,22)
print(result) #33
print(add2Num(11,22)) #33
# 返回多个值的函数
def divid(a,b):
shang = a//b
yushu = a%b
return shang,yushu #多个返回值用逗号分隔
sh,yu = divid(5,2) #需要使用多个值来保存返回内容
print(f'商:{
sh},余数:{
yu}')
八、模块
1. 模块的定义
模块包含可执行语句及函数定义。这些语句用于初始化模块,且仅在 import 语句第一次 遇到模块名时执行。(文件作为脚本运行时,也会执行这些语句。
)可以理解为是对代码更高级的封装,即把能够实现某一特定功能的代码编写在同一个 .py文件中,并将其作为一个独立的模块,这样既可以方便其它程序或脚本导入并使用,同时还能有效避免函数名和变量名发生冲突。
模块分为内置模块和自定义模块。
自定义模块:创建模块,只需将所需代码保存在文件扩展名为 .py 的文件中。
我们知道,在定义函数可以为其添加说明文档,以方便用户清楚的知道该函数或者类的功能。
自定义模块也不例外。
为自定义模块添加说明文档,和函数或类的添加方法相同,即只需在模块开头的位置定义一个字符串即可。可以通过模板的__doc__
属性,来访问模板的说明文档。
事实上,函数定义也是“执行”的“语句”;模块级函数定义的执行会将函数名称添加到模块的全局命名空间中。
Each module has its own private namespace, which is used as the global namespace by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables. On the other hand, if you know what you are doing you can touch a module’s global variables with the same notation used to refer to its functions, modname.itemname.
译:[每个模块都有自己的私有命名空间,模块中定义的所有函数都将其用作全局命名空间。因此,模块的作者可以在模块中使用全局变量,而不必担心与用户的全局变量发生意外冲突。另一方面,如果您知道自己在做什么,则可以使用用于引用其函数的相同表示法(modname.itemname)来触摸模块的全局变量。]
Modules can import other modules. It is customary but not required to place all import statements at the beginning of a module (or script, for that matter). The imported module names, if placed atthe top level of a module (outside any functions or classes), are added to the module’s global namespace.
译:[模块可以导入其他模块。习惯上,但不是必须将所有 import 语句放在模块(或脚本,就此而言)的开头。导入的模块名称(如果放置在模块的顶层在任何函数或类外部)将添加到模块的全局命名空间中。]
模块到底指的是什么呢?模块,英文为 Modules,至于模块到底是什么,可以用一句话总结:模块就是 Python 程序。换句话说,任何 Python程序都可以作为模块,包括在前面章节中写的所有 Python 程序,都可以作为模块。
代码的可重用性体现在,当编写好一个模块后,只要编程过程中需要用到该模块中的某个功能(由变量、函数、类实现),无需做重复性的编写工作,直接在程序中导入该模块即可使用该功能。
模块(module)的一些属性:
- 模组是包含函数和变量的 Python 文件。(模块可以包含已经描述的函数,但也可以包含各种类型的变量(数组、字典、对象等))
- 你可以 import (导入)这个文件。
- 然后你可以使用 ‘.’ 操作符访问到模组中的函数和变量。
Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。(这就创建了模块!!!)
模块让你能够有逻辑地组织你的 Python 代码段。
把相关的代码分配到一个模块里能让你的代码更好用,更易懂。
模块能定义函数,类和变量,模块里也能包含可执行的代码。
2. 模块的导入
- import 语句
模块定义好后,我们可以使用 import 语句来引入模块。
语法:
import module1[, module2[,... moduleN]]
一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行。
注:相当于导入的是一个文件夹,是个相对路径。
- from…import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中。
语法:
from modname import name1[, name2[, ... nameN]]
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
注:相当于导入的是一个文件夹中的文件,是个绝对路径。
例如我们想一次性引入 math 模块中所有的东西,语句如下:
from math import *
- from…import…as… 语句
导入模块成员时,也可以用 as 为成员指定别名(alias)。
语法:
from modname import name1[, as alias1[, name2[, as alias2]] ...
- 区别
import 与 from…import 的区别是当引用文件时是:
import //模块.函数
from…import // 直接使用函数名使用就可以了
from…import *:是把一个模块中所有函数都导入进来; 注:相当于:相当于导入的是一个文件夹中所有文件,所有函数都是绝对路径。
结论:
from…import *语句与import区别在于:
import 导入模块,每次使用模块中的函数都要指定是哪个模块。
from…import * 导入模块,每次使用模块中的函数,直接使用函数就可以了;注因为已经知道该函数是那个模块中的了。
- 调用模块属性的区别
import 模块名
模块名.xxx = 引用
from 模块名 import *
xxx = 拷贝 # 能修改属性值
函数,类… : “import 模块名” 和 “from 模块名 import *” 都是引用。
- 私有属性两种导入的区别
# . 类中的私有属性
# 本质做了一个名字重整
class test()
self.__name
__name 名字重整成 _test__name。
_littlethree : 模块的私有属性(数据)。
from 模块 import * : 导入模块时,会跳过私有属性;
import 模块 : 通过引用可以访问私有属性
通俗的理解 __name__
== ‘__main__
’:
假如你叫小明.py,在朋友眼中,你是小明(__name__
== ‘小明’);在你自己眼中,你是你自己
(__name__
== ‘__main__
’)。
if __name__
== '__main__
‘的意思是:当 .py 文件被直接运行时,if __name__
== '__main__
’
之下的代码块将被运行; 当 .py 文件以模块形式被导入时,if __name__
== '__main__
'之下的
代码块不被运行
3. 模块的执行(调用)
可以用以下方式运行 Python 模块:
python fibo.py <arguments>
这项操作将执行模块里的代码,和导入模块一样,但会把 __name__
赋值为 “__main__
”。 也就是
把下列代码添加到模块末尾:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
既可以把这个文件当脚本使用,也可以用作导入的模块, 因为,解析命令行的代码只有在模块以
“main” 文件执行时才会运行:
> python fibo.py 50
输出:
0 1 1 2 3 5 8 13 21 34
导入模块时,不运行这些代码:
>>> import fibo
这种操作常用于为模块提供便捷用户接口,或用于测试(把模块当作执行测试套件的脚本运行)。
调用模块时的区别:
对 module.xxx 的修改在重新 import 后仍然有效:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
print __name__
import math
print math.__name__
math.__name__ = "hello"
print math.__name__
import math
print math.__name__
输出:
__main__
math
hello
hello
from module import xxx
对 module.xxx 的修改在重新 import 后不会起效:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
print __name__
from math import __name__
print __name__
__name__ = "hello"
print __name__
from math import __name__
print __name__
输出:
__main__
math
hello
math
4. 模块搜索路径
当一个名为 spam 的模块被导入时,解释器首先搜索具有该名称的内置模块。这些模块的名字被列在 sys.builtin_module_names中。如果没有找到,它就在变量 sys.path 给出的目录列表中搜索一个名为 spam.py 的文件, sys.path 从这些位置初始化:
输入脚本的目录(或未指定文件时的当前目录)。
PYTHONPATH (目录列表,与 shell 变量 PATH 的语法一样)。
依赖于安装的默认值(按照惯例包括一个 site-packages 目录,由 site 模块处理)。
注解:在支持 symlink 的文件系统中,输入脚本目录是在追加 symlink 后计算出来的。
换句话说,包含 symlink 的目录并 没有 添加至模块搜索路径。
初始化后,Python 程序可以更改sys.path。运行脚本的目录在标准库路径之前,置于搜索路径的开头。即,加载的是该目录里的脚本,而不是标准库的同名模块。除非刻意替换,否则会报错。详见 标准模块。
1. PYTHONPATH 变量
作为环境变量,PYTHONPATH 由装在一个列表里的许多目录组成。PYTHONPATH 的语法和
shell 变量 PATH 的一样。
在 Windows 系统,典型的 PYTHONPATH 如下:
set PYTHONPATH=c:\python27\lib;
在 UNIX 系统,典型的 PYTHONPATH 如下:
set PYTHONPATH=/usr/local/lib/python
5. “已编译的” Python 文件
为了快速加载模块,Python 把模块的编译版缓存在 __pycache__
目录中,文件名为 module.version.pyc,version对编译文件格式进行编码,
一般是 Python 的版本号。例如,CPython 的 3.3 发行版中,spam.py 的编译版本缓存为
__pycache__/spam.cpython-33.pyc
使用这种命名惯例,可以让不同 Python 发行版及不同版本的已编译模块共存。
Python 对比编译版本与源码的修改日期,查看它是否已过期,是否要重新编译,此过程完全自动化。
此外,编译模块与平台无关,因此,可在不同架构系统
之间共享相同的支持库。
Python 在两种情况下不检查缓存。
其一,从命令行直接载入模块,只重新编译,不存储编译结果;
其二,没有源模块,就不会检查缓存。为了支持无源文件(仅编译)发行版本, 编译模块必须在源目录下,并且绝不能有源模块。
给专业人士的一些小建议:
在 Python 命令中使用 -O 或 -OO 开关,可以减小编译模块的大小。-O 去除断言语句,
-OO 去除断言语句和 __doc__
字符串。有些程序可能依赖于这些内容,因此,没有十足的把握,不要使用这两个选项。
“优化过的”模块带有 opt- 标签,并且文件通常会一小些。将来的发行版或许会改进优化的效果。
从 .pyc 文件读取的程序不比从 .py 读取的执行速度快,.pyc 文件只是加载速度更快。
compileall 模块可以为一个目录下的所有模块创建 .pyc 文件。
6. 标准模块
Python 自带一个标准模块的库,它在 Python 库参考(此处以下称为"库参考" )里另外描述。
一些模块是内嵌到编译器里面的, 它们给一些虽并非语言核心但却内嵌的操作提供接口,要么是为了效率,要么是给操作系统基础操作例如系统调入提供接口。 这些模块集是一个配置选项,
并且还依赖于底层的操作系统。例如,winreg 模块只在 Windows 系统上提供。
一个特别值得注意的模块 sys,它被内嵌到每一个 Python 编译器中。
sys.ps1 和 sys.ps2 变量定义了一些字符,它们可以用作主提示符和辅助提示符:
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>
只有解释器用于交互模式时,才定义这两个变量。
变量 sys.path 是字符串列表,用于确定解释器的模块搜索路径。该变量以环境变量
PYTHONPATH 提取的默认路径进行初始化,如未设置 PYTHONPATH,则使用内置的
默认路径。可以用标准列表操作修改该变量:
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')
7.各类内置模块简介
- dir()函数
内置函数 dir() 用于查找模块定义的名称。返回结果是经过排序的字符串列表。
可以理解为:dir() 函数一个排好序的字符串列表,内容是一个模块里定义过的名字。
返回的列表容纳了在一个模块里定义的所有模块,变量和函数。 - globals() 和 locals() 函数
根据调用地方的不同,globals() 和 locals() 函数可被用来返回全局和局部命名空间里的名字。
如果在函数内部调用 locals(),返回的是所有能在该函数里访问的命名。
如果在函数内部调用 globals(),返回的是所有在该函数里能访问的全局名字。
两个函数的返回类型都是字典。所以名字们能用 keys() 函数摘取。 - reload() 函数
当一个模块被导入到一个脚本,模块顶层部分的代码只会被执行一次。
因此,如果你想重新执行模块里顶层部分的代码,可以用 reload() 函数。该函数会
重新导入之前导入过的模块。
语法:
reload(module_name)
- 系统相关的信息模块: import sys
sys.argv 是一个 list,包含所有的命令行参数.
sys.stdout sys.stdin sys.stderr 分别表示标准输入输出,错误输出的文件对象.
sys.stdin.readline() 从标准输入读一行 sys.stdout.write("a") 屏幕输出a
sys.exit(exit_code) 退出程序
sys.modules 是一个dictionary,表示系统中所有可用的module
sys.platform 得到运行的操作系统环境
sys.path 是一个list,指明所有查找module,package的路径.
- 操作系统相关的调用和操作: import os
os.environ 一个dictionary 包含环境变量的映射关系
os.environ["HOME"] 可以得到环境变量HOME的值
os.chdir(dir) 改变当前目录 os.chdir('d:\\outlook') #注意windows下用到转义
os.getcwd() 得到当前目录
os.getegid() 得到有效组id os.getgid() 得到组id
os.getuid() 得到用户id os.geteuid() 得到有效用户id
os.setegid os.setegid() os.seteuid() os.setuid()
os.getgruops() 得到用户组名称列表
os.getlogin() 得到用户登录名称
os.getenv 得到环境变量
os.putenv 设置环境变量
os.umask 设置umask
os.system(cmd) 利用系统调用,运行cmd命令
- 内置模块(不用import就可以直接使用)常用内置函数:
help(obj) 在线帮助, obj可是任何类型
callable(obj) 查看一个obj是不是可以像函数一样调用
repr(obj) 得到obj的表示字符串,可以利用这个字符串eval重建该对象的一个拷贝
eval_r(str) 表示合法的python表达式,返回这个表达式
dir(obj) 查看obj的name space中可见的name
hasattr(obj,name) 查看一个obj的name space中是否有name
getattr(obj,name) 得到一个obj的name space中的一个name
setattr(obj,name,value) 为一个obj的name
space中的一个name指向vale这个object
delattr(obj,name) 从obj的name space中删除一个name
vars(obj) 返回一个object的name space。用dictionary表示
locals() 返回一个局部name space,用dictionary表示
globals() 返回一个全局name space,用dictionary表示
type(obj) 查看一个obj的类型
isinstance(obj,cls) 查看obj是不是cls的instance
issubclass(subcls,supcls) 查看subcls是不是supcls的子类
- 类型转换
chr(i) 把一个ASCII数值,变成字符
ord(i) 把一个字符或者unicode字符,变成ASCII数值
oct(x) 把整数x变成八进制表示的字符串
hex(x) 把整数x变成十六进制表示的字符串
str(obj) 得到obj的字符串描述
list(seq) 把一个sequence转换成一个list
tuple(seq) 把一个sequence转换成一个tuple
dict(),dict(list) 转换成一个dictionary
int(x) 转换成一个integer
long(x) 转换成一个long interger
float(x) 转换成一个浮点数
complex(x) 转换成复数
max(...) 求最大值
min(...) 求最小值
8. 包
包是一种用“点式模块名”构造 Python 模块命名空间的方法。例如,模块名 A.B 表示包 A 中名为 B的子模块。正如模块可以区分不同模块之间的全局变量名称一样,点式模块名可以区分 NumPy 或 Pillow 等不同多模块包之间的模块名称。
包的本质依然是模块,包可以包含包。Python 库:相比模块和包,库是一个更大的概念,例如在 Python 标准库中的每个库都有好多个包,而每个包中都有若干个模块。
包是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的 Python 的应用环境。
简单来说,包就是文件夹,但该文件夹下必须存在 __init__
.py 文件, 该文件的内容可以为空。__init__
.py 用于标识当前文件夹是一个包。
通常情况下,当使用 import 语句导入模块后,Python 会按照以下顺序查找指定的模块文件:
- 在当前目录,即当前执行的程序文件所在目录下查找;
- 到 PYTHONPATH(环境变量)下的每个目录中查找;
- 到 Python 默认的安装目录下查找。
以上所有涉及到的目录,都保存在标准模块 sys 的 sys.path
变量中,通过此变量我们可以看到指定程序文件支持查找的所有目录。换句话说,如果要导入的模块没有存储在 sys.path显示的目录中,那么导入该模块并运行程序时,Python 解释器就会抛出 ModuleNotFoundError(未找到模块)异常。
解决“Python找不到指定模块”的方法有 3 种,分别是:
- 向 sys.path 中临时添加模块文件存储位置的完整路径;
- 将模块放在 sys.path 变量中已包含的模块加载路径中;
- 设置 path 系统环境变量。
假设要为统一处理声音文件与声音数据设计一个模块集(“包”)。声音文件的格式很多(通常以扩展名来识别,例如:.wav, .aiff, .au),因此,为了不同文件格式之
间的转换,需要创建和维护一个不断增长的模块集合。为了实现对声音数据的不同处理(例如,混声、添加回声、均衡器功能、创造人工立体声效果),还要编写无穷无尽的模块流。下面这个分级文件树展示了这个包的架构:
sound/ Top-level package
__init__.py Initialize the sound package
formats/ Subpackage for file format conversions
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ Subpackage for sound effects
__init__.py
echo.py
surround.py
reverse.py
...
filters/ Subpackage for filters
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
导入包时,Python 搜索 sys.path 里的目录,查找包的子目录。
Python 只把含 __init__
.py 文件的目录当成包。这样可以防止以 string 等通用名称
命名的目录,无意中屏蔽出现在后方模块搜索路径中的有效模块。 最简情况下,
__init__
.py只是一个空文件,但该文件也可以执行包的初始化代码,或设置 __all__
变量,
详见下文。
还可以从包中导入单个模块,例如:
import sound.effects.echo
这段代码加载子模块 sound.effects.echo ,但引用时必须使用子模块的全名:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
另一种导入子模块的方法是 :
from sound.effects import echo
这段代码还可以加载子模块 echo ,不加包前缀也可以使用。因此,可以按如下方式使用:
echo.echofilter(input, output, delay=0.7, atten=4)
Import 语句的另一种变体是直接导入所需的函数或变量:
from sound.effects.echo import echofilter
同样,这样也会加载子模块 echo,但可以直接使用函数 echofilter():
echofilter(input, output, delay=0.7, atten=4)
注意,使用 from package import item 时,item 可以是包的子模块(或子包),也可以是包中定义的函数、类或变量等其他名称。import 语句首先测试包中是否定义了 item;如果未在包中定义,则假定 item 是模块,并尝试加载。如果找不到 item,则触发 ImportError 异常。
相反,使用 import item.subitem.subsubitem 句法时,除最后一项外,每个 item 都必须是包;最后一项可以是模块或包,但不能是上一项中定义的类、函数或变量。
用例:
在 package_runoob 目录下的 runoob1.py、runoob2.py、__init__
.py 文件,test.py
为测试调用包的代码,目录结构如下:
test.py
package_runoob
|-- __init__.py
|-- runoob1.py
|-- runoob2.py
源代码如下:
package_runoob/runoob1.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def runoob1():
print "I'm in runoob1"
package_runoob/runoob2.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
def runoob2():
print "I'm in runoob2"
现在,在 package_runoob 目录下创建 __init__
.py:
package_runoob/__init__
.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
if __name__ == '__main__':
print '作为主程序运行'
else:
print 'package_runoob 初始化'
然后我们在 package_runoob 同级目录下创建 test.py 来调用 package_runoob 包
test.py
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# 导入 Phone 包
from package_runoob.runoob1 import runoob1
from package_runoob.runoob2 import runoob2
runoob1()
runoob2()
以上实例输出结果:
package_runoob 初始化
I'm in runoob1
I'm in runoob2
1. 从包中导入 *
使用 from sound.effects import * 时会发生什么?理想情况下,该语句在文件系统查找
并导入包的所有子模块。这项操作花费的时间较长,并且导入子模块可能会产生不必要的副作用,这种副作用只有在显式导入子模块时才会发生。
唯一的解决方案是提供包的显式索引。import 语句使用如下惯例:如果包的 __init__
.py 代码定义了列表 __all__
,运行 from package import * 时,它就是用于导入的模块名列表。发布包的新版本时,包的作者应更新此列表。如果包的 作者认为没有必要在包中执行导入 * 操作, 也可以不提供此列表。
例如,sound/effects/__init__
.py 文件包含以下代码:
__all__ = ["echo", "surround", "reverse"]
这将意味着将 from sound.effects import * 导入sound.effects 包的三个命名的子模块。
如果没有定义 __all__
,from sound.effects import * 语句 不会 把包 sound.effects 中所有子模块都导入到当前命名空间;该语句只确保导入包 sound.effects (可能还会运行 __init__
.py 中的初始化代码),然后,再导入包中定义的名称。这些名称包括 __init__
.py中定义的任何名称(以及显式加载的子模块),还包括之前 import 语句显式加载的包里的子模块。
请看以下代码:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
本例中,执行 from…import 语句时,将把 echo 和 surround 模块导入至当前命名空间,
因为,它们是在 sound.effects 包里定义的。(该导入操作在定义了__all__
时也有效。)
虽然,可以把模块设计为用 import * 时只导出遵循指定模式的名称,但仍不提倡在生产代码中使用这种做法。
记住,使用 from package import specific_submodule 没有任何问题! 实际上,除了导入模块使用不同包的同名子模块之外,这种方式是推荐用法。
2. 子包参考
包中含有多个子包时(与示例中的 sound 包一样),可以使用绝对导入引用兄弟包中的子模块。
例如,要在模块 sound.filters.vocoder 中使用sound.effects 包的 echo 模块时,可以用from sound.effects import echo 导入。
还可以用 import 语句的 from module import name 形式执行相对导入。这些导入语句使用前导句点表示相对导入中的当前包和父包。例如,相对于surround 模块,可以使用:
from . import echo
from .. import formats
from ..filters import equalizer
注意,相对导入基于当前模块名。因为主模块名是 “__main__
” ,所以 Python 程序的主模块
必须始终使用绝对导入。
3. 多目录中的包
包支持一个更特殊的属性 __path__
。在包的 :file:__init__
.py 文件中的代码被执行前,
该属性被初始化为包含 :file:__init__
.py
文件所在的目录名在内的列表。可以修改此变量;但这样做会影响在此包中搜索子模块和子包。
这个功能虽然不常用,但可用于扩展包中的模块集。
Python 模块索引:https://docs.python.org/zh-cn/3/py-modindex.html 可找到对应各模块的解释与用法。
模块变化可参考:https://docs.python.org/zh-cn/3/contents.html 新增去除对应目录可了解。
九、文件操作
关于文件,它有两个关键属性,分别是“文件名”和“路径”。其中,文件名指的是为每个文件设定的名称,而路径则用来指明文件在计算机上的位置。
文件的操作有很多种,常见的操作包括创建、删除、修改权限、读取、写入等,这