注:本笔记基于python2.6而编辑,尽量的偏向3.x的语法
Python的特色
1.简单
2.易学
3.免费、开源
4.高层语言: 封装内存管理等
5.可移植性: 程序如果避免使用依赖于系统的特性,那么无需修改就可以在任何平台上运行
6.解释性: 直接从源代码运行程序,不再需要担心如何编译程序,使得程序更加易于移植。
7.面向对象: 支持面向过程的编程也支持面向对象的编程。
8.可扩展性: 需要保密或者高效的代码,可以用C或C++编写,然后在Python程序中使用它们。
9.可嵌入性: 可以把Python嵌入C/C++程序,从而向你的程序用户提供脚本功能。
10.丰富的库: 包括正则表达式、文档生成、单元测试、线程、数据库、网页浏览器、CGI、FTP、
电子邮件、XML、XML-RPC、HTML、WAV文件、密码系统、GUI(图形用户界面)、Tk和其他与系统有关的操作。
除了标准库以外,还有许多其他高质量的库,如wxPython、Twisted和Python图像库等等。
11.概括: Python确实是一种十分精彩又强大的语言。它合理地结合了高性能与使得编写程序简单有趣的特色。
12.规范的代码: Python采用强制缩进的方式使得代码具有极佳的可读性。
Python 下载地址
http://www.python.org/download/
Python 安装:
windows时,运行安装文件之后,还需要配置环境变量,在环境变量的“Path”后面加上英文的分号及python安装目录
如:“;C:\promg\python2.6”
不配置环境变量的话,没法在命令行直接使用python
有两种使用Python运行你的程序的方式
1.使用交互式的带提示符的解释器
直接双击运行“python.exe”,在里面输入内容,如: print ‘haha…’
2.使用源文件
在Python的安装目录下,建一个批处理(test.bat),写入:
@echo off
python.exe test.py
pause
而“test.py”里面的内容是需要执行的程序
Python命令行选项
选项 作用
-c cmd 在命令行直接执行python代码。如python -c ‘print “hello world”’。
-d 脚本编译后从解释器产生调试信息。同PYTHONDEBUG=1。
-E 忽略环境变量。
-h 显示python命令行选项帮助信息。
-i 脚本执行后马上进入交互命令行模式。同PYTHONINSPECT=1。
-O 在执行前对解释器产生的字节码进行优化。同 PYTHONOPTIMIZE=1。
-OO 在执行前对解释器产生的字节码进行优化,并删除优化代码中的嵌入式文档字符串。
-Q arg 除法规则选项,-Qold(default),-Qwarn,-Qwarnall,-Qnew。
-S 解释器不自动导入site.py模块。
-t 当脚本的tab缩排格式不一致时产生警告。
-u 不缓冲stdin、stdout和stderr,默认是缓冲的。同PYTHONUNBUFFERED=1。
-v 产生每个模块的信息。如果两个-v选项,则产生更详细的信息。同PYTHONVERBOSE=x。
-V 显示Python的版本信息。
-W arg 出错信息控制。(arg is action:message:category:module:lineno)
-x 忽略源文件的首行。要在多平台上执行脚本时有用。
file 执行file里的代码。
- 从stdin里读取执行代码。
easy_install
这是个很常用的python安装工具
可以直接安装ez_setup.py脚本(下载网址: http://peak.telecommunity.com/dist/ez_setup.py):
python ez_setup.py
windows 下的使用:
安装:
下载: http://peak.telecommunity.com/dist/ez_setup.py
执行: python ez_setup.py
使用:
easy_install.exe -U %modal% # %modal% 是模块名
linux 下:
安装:
sudo apt-get install python-setuptools
或者:
wget -q http://peak.telecommunity.com/dist/ez_setup.py
sudo python ez_setup.py
使用:
sudo easy_install 模块名
安装完后,最好确保easy_install所在目录已经被加到PATH环境变量里:
Windows: C:\Python25\Scripts
Linux: /usr/local/bin
不能使用easy_install的特殊情况:
a、安装默认版本的MySQL-python会报错,需要指定版本如下:easy_install "MySQL-python==1.2.2"
b、有些包直接easy_install会失败,需要自行下载安装:
wxpython,pil要下载exe安装程序
robotide因为在pypi上找不到,要下载后再easy_install
通过easy_install安装软件,相关安装信息会保存到easy-install.pth文件里,路径类似如下形式:
Windows:C:\Python25\Lib\site-packages\easy-install.pth
Linux:/usr/local/lib/python25/site-packages/easy-install.pth
如果想删除通过easy_install安装的软件包,比如说:MySQL-python,可以执行命令:
easy_install -m MySQL-python
此操作会从easy-install.pth文件里把MySQL-python的相关信息抹去,剩下的egg文件,你可以手动删除。
版本问题
python3.0版本较之前的有很大变动,而且不向下兼容。
Python 2.6作为一个过渡版本,基本使用了Python 2.x的语法和库,同时考虑了向Python 3.0的迁移。即2.6版本兼容2.x和3.0的语法
Python 2.6保持了对之前版本的全兼容,而且还包含了Python 3.0的新玩意(一些新特性需要通过“from future import”来启用)。
如,在Python2.6要使用3.0的打印,得写上“ from future import print_function”
基于早期Python版本而能正常运行于Python 2.6并无警告的程序可以通过一个2 to 3的转换工具无缝迁移到Python 3.0。
部分函数和语句的改变
最引人注意的改变是print语句没有了,取而代之的是print函数
同样的还有exec语句,已经改为exec()函数。去除了<>,全部改用!=。
在python2.x版本中
#!/usr/bin/env python
# 或者上句写: #!/usr/bin/python
print “Hello, world!”
或者:
import sys
sys.stdout.write(“Hello, world\n”)
在python3.x中
print('Hello world!')
用迭代器来替代列表
一些知名的API将不再返回列表。
而字典的dict.iterkeys()、dict.itervalues()和dict.iteritems()方法将会移除,而你可以使用.keys()、.values()和.items(),它们会返回更轻量级的、类似于集合的容器对象,而不是返回一个列表来复制键值。
这样做的优点是,可以直接在键和条目上进行集合操作,而不需要再复制一次。
整型数
移除了含糊的除法符号(‘/’),而只返回浮点数。
在以前的版本中,如果参数是int或者是long的话,就会返回相除后结果的向下取整(floor),而如果参数是float或者是complex的话,那么就会返回相除后结果的一个恰当的近似。
在2.6版本中可以通过from future import division来启用这项特性。
python2 to python3 问题
1.print 语句
2.x 3.x 说明
① print print() # 输出一个空白行
② print 1 print(1) # 输出一个单独的值
③ print 1, 2 print(1, 2) # 输出多个值,以空格分割
④ print 1, 2, print(1, 2, end=’ ‘) # 输出时取消在末尾输出回车符。
⑤ print >>sys.stderr, 1, 2 print(1, 2, file=sys.stderr) # 把输出重定向到一个管道
2.被重命名或者重新组织的模块
1)http
在Python 3里,几个相关的HTTP模块被组合成一个单独的包,即http。
2.x 3.x
① import httplib import http.client # http.client 模块实现了一个底层的库,可以用来请求HTTP资源,解析HTTP响应。
② import Cookie import http.cookies # http.cookies 模块提供一个蟒样的(Pythonic)接口来获取通过HTTP头部(HTTP header)Set-Cookie发送的cookies
③ import cookielib import http.cookiejar # 常用的流行的浏览器会把cookies以文件形式存放在磁盘上,http.cookiejar 模块可以操作这些文件。
④ import BaseHTTPServer import http.server # http.server 模块实现了一个基本的HTTP服务器
import SimpleHTTPServer
import CGIHttpServer
2)urllib
Python 2有一些用来分析,编码和获取URL的模块,但是这些模块就像老鼠窝一样相互重叠。在Python 3里,这些模块被重构、组合成了一个单独的包,即urllib。
2.x 3.x
① import urllib import urllib.request, urllib.parse, urllib.error
② import urllib2 import urllib.request, urllib.error
③ import urlparse import urllib.parse
④ import robotparser import urllib.robotparser
⑤ from urllib import FancyURLopener from urllib.request import FancyURLopener
from urllib import urlencode from urllib.parse import urlencode
⑥ from urllib2 import Request from urllib.request import Request
from urllib2 import HTTPError from urllib.error import HTTPError
以前,Python 2里的 urllib 模块有各种各样的函数,包括用来获取数据的 urlopen(),还有用来将URL分割成其组成部分的 splittype(), splithost()和 splituser()函数。
在python3的 urllib 包里,这些函数被组织得更有逻辑性。2to3将会修改这些函数的调用以适应新的命名方案。
在Python 3里,以前的 urllib2 模块被并入了 urllib 包。同时,以 urllib2 里各种你最喜爱的东西将会一个不缺地出现在Python 3的 urllib 模块里,比如 build_opener()方法, Request 对象, HTTPBasicAuthHandler 和 friends 。
Python 3里的 urllib.parse 模块包含了原来Python 2里 urlparse 模块所有的解析函数。
urllib.robotparse 模块解析 robots.txt 文件。
处理HTTP重定向和其他状态码的 FancyURLopener 类在Python 3里的 urllib.request 模块里依然有效。 urlencode()函数已经被转移到了 urllib.parse 里。
Request 对象在 urllib.request 里依然有效,但是像HTTPError这样的常量已经被转移到了 urllib.error 里。
3)dbm
所有的DBM克隆(DBM clone)现在在单独的一个包里,即dbm。如果你需要其中某个特定的变体,比如GNU DBM,你可以导入dbm包中合适的模块。
2.x 3.x
① import dbm import dbm.ndbm
② import gdbm import dbm.gnu
③ import dbhash import dbm.bsd
④ import dumbdbm import dbm.dumb
⑤ import anydbm import dbm
import whichdb
4)xmlrpc
XML-RPC是一个通过HTTP协议执行远程RPC调用的轻重级方法。一些XML-RPC客户端和XML-RPC服务端的实现库现在被组合到了独立的包,即xmlrpc。
2.x 3.x
① import xmlrpclib import xmlrpc.client
② import DocXMLRPCServer import xmlrpc.server
import SimpleXMLRPCServer
5)其他模块
2.x 3.x
① try: import io
import cStringIO as StringIO # 在Python 2里,你通常会这样做,首先尝试把cStringIO导入作为StringIO的替代,如果失败了,再导入StringIO。
except ImportError: # 不要在Python 3里这样做;io模块会帮你处理好这件事情。它会找出可用的最快实现方法,然后自动使用它。
import StringIO
② try: import pickle
import cPickle as pickle # 在Python 2里,导入最快的pickle实现也与上边 io 相似。在Python 3里,pickle模块会自动为你处理,所以不要再这样做。
except ImportError:
import pickle
③ import __builtin__ import builtins
④ import copy_reg import copyreg # copyreg模块为用C语言定义的用户自定义类型添加了pickle模块的支持。
⑤ import Queue import queue # queue模块实现一个生产者消费者队列(multi-producer, multi-consumer queue)。
⑥ import SocketServer import socketserver # socketserver模块为实现各种socket server提供了通用基础类。
⑦ import ConfigParser import configparser # configparser模块用来解析INI-style配置文件。
⑧ import repr import reprlib # reprlib 模块重新实现了内置函数 repr(),并添加了对字符串表示被截断前长度的控制。
⑨ import commands import subprocess # subprocess 模块允许你创建子进程,连接到他们的管道,然后获取他们的返回值。
builtins模块包含了在整个Python语言里都会使用的全局函数,类和常量。重新定义builtins模块里的某个函数意味着在每处都重定义了这个全局函数。这听起来很强大,但是同时也是很可怕的。
注释
“#”后面的内容
数据类型
共4种: 整数、长整数、浮点数和复数。
1.整数,如:2
2.长整数,如:22L # 长整数不过是大一些的整数。Python 3已经取消这种类型,被int取代了。
3.浮点数,如:3.23 和 52.3E-4 # E标记表示10的幂。在这里,52.3E-4表示52.3 * 10-4。
4.复数,如:(-5+4j) 和 (2.3-4.6j)
在Python 2和Python 3的变化:
1.八进制(octal)数:
Python 2: x = 0755 # 0开头
Python 3: x = 0o755 # 0o开头
2.long 类型
Python 2有为非浮点数准备的 int 和 long 类型。 int 类型的最大值不能超过 sys.maxint,而且这个最大值是平台相关的。
整数可以通过在数字的末尾附上一个L来定义长整型,显然,它比 int 类型表示的数字范围更大。
Python 3里,只有一种整数类型 int,大多数情况下,它很像Python 2里的长整型。
由于已经不存在两种类型的整数,所以就没有必要使用特殊的语法去区别他们。
由于 long 类型在Python 3的取消,引起以下改变
Python 2 Python 3 说明
① x = 1000000000000L x = 1000000000000 # 十进制的普通整数
② x = 0xFFFFFFFFFFFFL x = 0xFFFFFFFFFFFF # 十六进制的普通整数
③ long(x) int(x) # long()函数没有了。可以使用int()函数强制转换一个变量到整型。
④ type(x) is long type(x) is int # 检查一个变量是否是整型
⑤ isinstance(x, long) isinstance(x, int) # 也可以使用 isinstance()函数来检查数据类型
3.sys.maxint(sys.maxsize)
由于长整型和整型被整合在一起了, sys.maxint常量不再精确。
因为这个值对于检测特定平台的能力还是有用处的,所以它被Python 3保留,并且重命名为 sys.maxsize。
Python 2 Python 3
① from sys import maxint from sys import maxsize # maxint变成了maxsize。
② a_function(sys.maxint) a_function(sys.maxsize) # 所有的sys.maxint都变成了sys.maxsize。
int 是 types.IntType 的代名词
print(id(int)) # 打印如:505210872
import types;print(id(types.IntType)) # 打印如:505210872
标识符的命名
变量是标识符的例子。 标识符 是用来标识 某样东西 的名字。在命名标识符的时候,你要遵循这些规则:
1.标识符的第一个字符必须是字母表中的字母(大写或小写)或者一个下划线(‘_’)。
2.标识符名称的其他部分可以由字母(大写或小写)、下划线(‘_’)或数字(0-9)组成。
3.标识符名称是对大小写敏感的。例如,myname和myName不是一个标识符。
有效 标识符名称的例子有i、__my_name、name_23和a1b2_c3。
无效 标识符名称的例子有2things、this is spaced out和my-name。
逻辑行与物理行
物理行是在编写程序时文本的一行。逻辑行是程序的一个语句。
Python假定每个 物理行 对应一个 逻辑行 。 他希望每行都只使用一个语句,这样使得代码更加易读。
1. 如果你想要在一个物理行中使用多于一个逻辑行,那么你需要使用分号(;)来特别地标明这种用法。
分号表示一个逻辑行/语句的结束。
如: i = 5; print i; # 强烈建议你坚持在每个物理行只写一句逻辑行。 让程序见不到分号,而更容易阅读。
2. 明确的行连接
在多个物理行中写一个逻辑行,行结尾用反斜杠标明
如: s = ‘This is a string. \
This continues the string.’
# 上面这两行是一个逻辑行,打印是: This is a string. This continues the string.
print \
i
# 上面这两行也是一个逻辑行, 等同于: print i
3. 暗示的行连接
在多个物理行中写一个逻辑行,行结尾不需要使用反斜杠标明。
这种情况出现在逻辑行中使用了圆括号、方括号或波形括号的时候。
4. 缩进
行首的空白是重要的。在逻辑行首的空白(空格和tab符)用来决定逻辑行的缩进层次,从而用来决定语句的分组。
同一层次的语句必须有相同的缩进。每一组这样的语句称为一个块。
不要混合使用tab符和空格来缩进,因为这在跨越不同的平台的时候,无法正常工作。强烈建议只使用一种风格来缩进。
语法规则
1.缩进规则
一个模块的界限,完全是由每行的首字符在这一行的位置来决定的(而不是花括号{})。这一点曾经引起过争议。
不过不可否认的是,通过强制程序员们缩进,Python确实使得程序更加清晰和美观。
在逻辑行首的空白(空格和tab)用来决定逻辑行的缩进层次,从而用来决定语句的分组。错误的缩进会引发错误。
注意: 强制缩进的问题,最常见的情况是tab符和空格的混用会导致错误,而这是用肉眼无法分别的。
2.变量没有类型
使用变量时只需要给它们赋值。 不需要声明或定义数据类型。
3.单语句块
如果你的语句块只包含一句语句,那么你可以在条件语句或循环语句的同一行指明它。如: if 1!=2: print(‘Yes’)
强烈建议不要使用这种缩略方法。这会破坏Python清晰美观的代码风格,违背设计者的初衷。
如果是在Python解释器输入,它的把提示符会改变为…以表示语句还没有结束。这时按回车键用来确认语句已经完整了。然后,Python完成整个语句的执行,并且返回原来的提示符来等待下一句输入。
运算符与表达式:
运算符
运算符 名称 说明
+ 加 两个对象相加,也可以字符串拼接
- 减 得到负数或是一个数减去另一个数
* 乘 两个数相乘 或是返回一个被重复若干次的字符串
** 幂 返回x的y次幂
/ 除 x除以y
// 取整除 返回商的整数部分
% 取模 返回除法的余数 # 8%3得到2。 -25.5%2.25得到1.5
<< 左移 把一个数的二进制向左移一定数目 # 2 << 2得到8
右移 把一个数的二进制向右移一定数目 # 11 >> 1得到5 & 按位与 数的按位与 # 5 & 3得到1。 | 按位或 数的按位或 # 5 | 3得到7。 ^ 按位异或 数的按位异或 # 5 ^ 3得到6 ~ 按位翻转 x的按位翻转是-(x+1) # ~5得到6。 < 小于 返回x是否小于y 大于 返回x是否大于y <= 小于等于 返回x是否小于等于y
= 大于等于 返回x是否大于等于y
== 等于 比较对象是否相等
!= 不等于 比较两个对象是否不相等(python3删除了“<>”符号)
not 布尔“非” 如果x为True,返回False。如果x为False,它返回True。 # x = True; not x返回False。
and 布尔“与” 如果x为False,x and y返回False,否则它返回y的计算值。 # x=False; y=True; x and y返回False。
or 布尔“或” 如果x是True,它返回True,否则它返回y的计算值。# x = True; y = False; x or y返回True。
in, not in 成员测试 (由类里面的 contains 函数指定返回值)
is, is not 同性测试 (两值的 is 运算是判断引用,与“==”的比较有所不同)
说明:
1.加号“+”:有数学相加,也有字符串拼接作用,注意:不能字符串和数字相加。如: 3 + 5得到8; ‘a’ + ‘b’得到’ab’。
2.乘号“”:两个数相乘,也可以把字符串重复拼接若干次,如: 2 3得到6; ‘la’ * 3得到’lalala’。
3.幂“” :这种写法,其他语言好像没见到过,如: 3 4得到81(即3 * 3 * 3 * 3)
4.除号“/”:整数的除法得到整数结果,浮点数的得到浮点数,如:4/3得到1(返回相除后结果的向下取整(floor)); 4.0/3或4/3.0得到1.333…
注意:Python 3.0开始,移除了含糊的除法符号(‘/’),而只返回浮点数。如:4/3得到1.333…
5.取整除“//”:将两数相除,然后对结果取整,如: 7 // 3得到2; 4 // 3.0得到1.0
6.比较运算符:所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量 True 和 False 等价。注意大小写。
如果两个操作数都是数字,它们首先被转换为一个共同的类型(如double)。否则,它总是返回 False 。
5 < 3返回0(即False); 而3 < 5返回1(即True)。比较可以被任意连接: 3 < 5 < 7返回True。
大于、小于、小于等于、大于等于时:数字跟数字可以比较,字符串跟字符串可以比较,但数字不能跟字符串比较。
等于、不等于时: 数字跟数字可以比较,字符串跟字符串可以比较,数字跟字符串比较返回 False (表示不相等)
等于: Python 使用“==”来做比较,用“=”来赋值。但不允许内嵌的赋值,所以不会出现你本以为在做比较而意外的写成赋值的情况。
7.布尔运算: and 和 or 都是短路运算,没有非短路运算的运算符。
短路运算:当前面一个表达式可以决定结果时,后面的语句不用再判断。非短路运算时,还照样判断后面的。
注意:在 and or 运算中,空字符串”,数字0,空列表[],空字典{},空元组(), None,在逻辑运算中都被当作假来处理。
8.and 和 or 的特殊用法:
由于语言的松散性,用 and 和 or 在赋值语句时有判断作用。
1) or 用在赋值语句里,返回第一个逻辑为真的值, 没有逻辑为真的返回最后一个。(如下这写法比较常用)
如:ss = False or None or 0 or ” or -1 or ‘sss’; print(ss) # 打印:-1 (-1作if判断时返回 True)
设定预设值的写法: edittype = edittype or “text”; # 如果 edittype 之前有值,则取之前的值; 之前为空,则取默认值
2) and 用在赋值语句里,与 or 刚好相反,返回第一个逻辑为假的值, 没有逻辑为假的返回最后一个。
如: a = 0 and 1; print(a) # 打印: 0
a = 2 and 1; print(a) # 打印: 1
应用: valid = True; valid = valid and checkLength(name, 16); valid = valid and checkLength(name, 16); # 如果前面的验证不通过,则后面的不再验证
简便的记忆是: and 偏 False, or 偏 True
要理解 and 和 or 的这种写法,得考虑到它的短路运算特性。它是在做逻辑判断,但返回的是前或后一个的值,而不是返回 True 或 False 。
9.三目运算符:
Python 没有三目运算符“cond ? a : b”,但可以使用 and 和 or 来代替(需理解前面的 and 和 or 的特殊用法),如下:
1) c = cond and a or b # 这多数情况下是正确的,但当 a 是空字符串”、数字0等逻辑运算为假的情况下会出错。
2) c = (cond and [a] or [b])[0] # 即使 a或者b为一个逻辑假的值,将他放入集合中后,就为真了,也就是[False] [None]都不为假。
3) c = (b, a)[cond and 1 or 0] # 注意 a和b的位置是颠倒的,将表达式结果转成1和0来作为元组下标而选择结果。
4) c = a if cond else b # 使用 if else 写条件(python特有的写法,建议使用,前3种写法难理解也容易出错)
10.自增,自减:
Python 没有“++”和“–”两个语法,自增自减时只能写: i = i + 1 或者 i += 1, 不能用 i++
这在一定程度上避免出错,因为新手经常搞错“++”放前面还是放后面; 但这也导致 for 循环的写法与其它语言很不同
11.switch/case 语句
Python现在不支持这语句,但可以用 range(N) 生成一个 列表
12.一次性的多比较
“ if (0 < n < 4000) ”这种写法在python是允许的,它等价于“ if ((0 < n) and (n < 4000)) ”但前者更适合阅读。
运算符优先级
下面这个表给出Python的运算符优先级,从最低的优先级(最松散地结合)到最高的优先级(最紧密地结合)。
在一个表达式中,Python会首先计算下表中较下面的运算符,然后在计算列在下表上部的运算符。
在下表中列在同一行的运算符具有 相同优先级 。例如,+和-有相同的优先级。
建议使用圆括号来分组运算符和操作数,以便能够明确地指出运算的先后顺序,使程序尽可能地易读。例如,2 + (3 * 4)显然比2 + 3 * 4清晰。
运算符 描述
lambda Lambda表达式
or 布尔“或”
and 布尔“与”
not x 布尔“非”
in,not in 成员测试
is,is not 同一性测试
<,<=,>,>=,!=,== 比较
| 按位或
^ 按位异或
& 按位与
<<,>> 移位
+,- 加法与减法
*,/,% 乘法、除法与取余
+x,-x 正负号
~x 按位翻转
** 指数
x.attribute 属性参考
x[index] 下标
x[index:index] 寻址段
f(arguments...) 函数调用
(experession,...) 绑定或元组显示
[expression,...] 列表显示
{key:datum,...} 字典显示
'expression,...' 字符串转换
计算顺序
默认地,运算符优先级表决定了哪个运算符在别的运算符之前计算。然而,如果要改变它们的计算顺序,得使用圆括号。
例如,你想要在一个表达式中让加法在乘法之前计算,那么你就得写成类似(2 + 3) * 4的样子。
结合规律
运算符通常由左向右结合,即具有相同优先级的运算符按照从左向右的顺序计算。例如,2 + 3 + 4被计算成(2 + 3) + 4。
一些如赋值运算符那样的运算符是由右向左结合的,即a = b + c被处理为a = (b + c)。
对象
Python 将 “一切皆对象” 贯彻得非常彻底,不区分什么 “值类型” 和 “引用类型”。所谓变量,实质就是一个通用类型指针 (PyObject*),它仅仅负责指路,至于目标是谁,一概不管。
Python Object 对象的自身结构了。任何对象,就算一个最简单的整数,它的头部都会拥有 2 个特殊的附加信息,分别是:”引用计数” 和 “类型 (type) 指针” 。前者指示 GC 何时回收,而后者标明了对象的身份,如此我们就可以在运行期动态执行对象成员调用。
连同附加头,一个 "普通" 的整数起码得 12 字节:
a = 8; import sys; print(sys.getsizeof(a)) # 打印: 12 (python3.2中,打印的是14)
print(sys.getsizeof(None)) # 打印: 8
字符串
1.使用单引号“’”引起来: ‘Quote me on this’
2.使用双引号“””引起来: “What’s your name?”
3.使用三引号(”’或”“”): 可以指示一个多行的字符串。你可以在三引号中自由的使用单引号和双引号。 /”’
如:
“”“This is a multi-line string. This is the first line.
“What’s your name?,” I asked.
He said “Bond, James Bond.”
“””
4.转义符“\”
\ 指示反斜杠本身
\’ 指示单引号
\” 指示双引号
注意: 行末的单独一个反斜杠表示字符串在下一行继续,而不是开始一个新的行。
5.自然字符串
自然字符串通过给字符串加上前缀r或R来指定,取消转义符的功能。例如: r”Newlines are indicated by \n”。
三引号的字符串也可以同样用法,如:R”’Newlines are indicated by \n”’
6.Unicode字符串
Python允许你处理Unicode文本(超过拉丁文字范围的)——只需要在字符串前加上前缀u或U。
例如,u”This is a Unicode string.哈哈..”。(Python3.x之后不需要这样了,可以直接写中文;而这样写会报错)
Python 3.0开始对unicode全面支持,所有的文本(str)都是Unicode的;并引入了一个叫做bytes的新类型来处理字节序列。而编码过的Unicode会以二进制的数据来表示。
因为在2.x的世界里,大量的bug都是因为已编码的文本和未编码的文本混杂在一起而产生的。
7.按字面意义级连字符串
如果你把两个字符串按字面意义相邻放着,他们会被Python自动级连。
例如,”What’s” ’ your name?’会被自动转为”What’s your name?”。
即是说,两个字符串放在一起,会有字符拼接的效果。加号“+”也有字符拼接的效果。
8.字符串拼接
可以使用“str1.add(str2)”或者“str1 + str2”或者直接两个字符串放一起,来拼接字符串
但字符串与其它类型拼接时,得先把其它类型转成字符串类型,否则会出错。如“str1 + 2”就会出错,需要“str1 + str(2)”
9.格式化
使用“%控制符”可以格式化字符串,非常方便。如: str1 = “Swaroop’s age is %d, weight is %f” % (5, 65.5)
“%(name)控制符”可按名称传参数(不写名称是按位置传参数),如: str = “%(row)d Rows is %(value)s” % { ‘value’: ‘kkkk’, ‘row’: 22 }
格式化的符号用法参考下面的“字符串格式化控制表”
另外,string.format()函数也可以格式化字符串
例如:’subtracting {0}, adding {1}’.format(1, ‘haha’) # 参数讲对应到“{number}”的位置上
10.字符串序列(索引和切片)
字符串可以使用下标来获取字符串中某个项目,以及截取字符串。详情参考“序列”
用法如: name = ‘swaroop’; name[1]; name[1:3]; name[1:-1]
11.str(anything)函数和 unicode(anything)函数
Python 2有两个全局函数可以把对象强制转换成字符串:unicode()把对象转换成Unicode字符串,还有 str()把对象转换为非Unicode字符串。
Python 3只有一种字符串类型,Unicode字符串,所以 str()函数即可完成所有的功能。(unicode()函数在Python 3里不再存在了。)
另外:
没有专门的char数据类型,确实没有需要有这个类型。
单引号和双引号字符串是完全相同的——它们没有在任何方面有不同。
正则表达式: 一定要用自然字符串处理正则表达式。否则会需要使用很多的反斜杠。
使用 help(str) 可查看字符串对象定义的所有方法及属性。
由于百分号有特殊作用,所以字符串里面要用百分号的话需要使用“%%”,如:”select * from my_table where name like ‘%%测试%%’”
字符串格式化控制:(未参考帮助文档,只是个人猜测)
转义符 (Escape Sequence):
\ddd 1到3位8进制数指定Unicode字符输出(如:“\127”显示“W”)
\uxxxx 1到4位16进制数指定Unicode字符输出(Python3.x开始支持此写法,如: \u54C8 显示“哈”字)
\xhh 16进制数指定Unicode字符输出(如:“\xe5\x93\x88”显示“哈”)
\ \
\ \ (单独的一个斜杠也显示斜杠,即不后接有转移作用的字符时,作为斜杠使用)
\’ ’
\” ”
\a 字符:0x07 响铃(ASCII控制字符)
\b 字符:0x08 退格(光标向左走一格)(ASCII控制字符)
\f 字符:0x0c Formfeed(FF)(走纸转页,换页)(ASCII控制字符)
\n 字符:0x0a 换行(ASCII控制字符)
\N{name} Unicode字符 只能针对Unicode
\r 字符:0x0d 回车
\t 字符:0x09 跳格(tab符号),水平制表符
\v 字符:0x0b 垂直制表符
%% %
%d 输出10进制整数,只能是数字类型,输出字符串类型会出错;浮点类型的数字将被取整(直接删除小数部分)。
%f,%F 以10进制输出浮点数,只能是数字类型,输出字符串类型会出错。
%e,%E 以科学计数法输出10进制的浮点数,大小写的“e”反应在显示时科学计数法的“e/E”上,只能是数字类型。
%a Python3.0开始支持此写法,原样输出结果,字符串类型会加上单引号引起来。
%o (字母o)以8进制整数方式输出,只能是数字类型;浮点类型的数字将被取整(直接删除小数部分)。
%x,%X 将数字以16进制方式输出,只能是数字类型;浮点类型的数字将被取整(直接删除小数部分)。
%s 将字符串格式化输出(可输出任何类型)
%c 以字符方式输出,提供的类型必须是 char 或 int 。
注:布尔类型的 True 或 False,用数字类型输出是 1或0,字符串输出是 True 或 False。
字符串转换成数字
float(str) 转换成浮点数,如, float(“1e-1”) 结果:0.1
int(str) 转换成整数,如, int(“12”) 结果:12
int(str,base) 转换成base进制的整数,如, int(“11”,2) 转换成2进制的整数,结果:3
long(str) 转换成长整数,Python3取消此语法,如, long(“12L”) 结果:12L
long(str,base) 转换成base进制的长整数,Python3取消此语法,如, long(“11L”,2) 结果:3L
字符串用例
name = ‘Swaroop’ # This is a string object
# 检查字符串的开头部分
if name.startswith('Swa'): # 类似函数如 endswith()
print('Yes, the string starts with "Swa"')
# 检查是否包含有此内容
if 'a' in name:
print('Yes, it contains the string "a"')
# 找出给定字符串的位置,找不到则返回-1
if name.find('war') != -1:
print('Yes, it contains the string "war"', 's')
# join()函数把列表拼接起来
delimiter = '; '
mylist = ['Brazil', 'Russia', 'India', 'China']
print(delimiter.join(mylist)) # 打印: Brazil; Russia; India; China
# 大小写转换
print("THIS IS TEST".lower()) # 转换成小写,打印:this is test
print("this is test".upper()) # 转换成大写,打印:THIS IS TEST
print("This Is Test".swapcase()) # 大小写互换,打印:tHIS iS tEST
print(" This Is Test ".strip()) # 去掉前后空格,打印:This Is Test
# 常用 string 函数
replace(string,old,new[,maxsplit])
字符串的替换函数,把字符串中的old替换成new。默认是把string中所有的old值替换成new值,如果给出maxsplit值,还可控制替换的个数,如果maxsplit为1,则只替换第一个old值。
如: a="11223344";print(string.replace(a,"1","one")) # 打印: oneone2223344
print(string.replace(a,"1","one",1)) # 打印: one12223344
b = "dfsdf dfsdfsd dfsdf ";print(a.replace(' ', '')) # 打印: dfsdfdfsdfsddfsdf
capitalize(string)
该函数可把字符串的首个字符替换成大字。
如: import string; print(string.capitalize("python")) # 打印: Python
split(string,sep=None,maxsplit=-1)
从string字符串中返回一个列表,以sep的值为分界符。
如: import string; ip="192.168.3.3"; print(string.split(ip,'.')) # 打印: ['192', '168', '3', '3']
控制台输入
使用 raw_input()函数 或者 input()函数 能够很方便的控从制台读入数据,得到的是字符串。
Python2.x时,raw_input()和 input()的区别:
当输入为纯数字时:input()返回的是数值类型,如:int,float; raw_input()返回的是字符串类型
input()会计算在字符串中的数字表达式,而 raw_input()不会。如输入“57+3”: input()得到整数60,raw_input()得到字符串’57+3’
注:Python3.0将 raw_input()函数去除了,而用 input() 取代它的功能。另外,input()获取的字符串会包括结尾的换行符。
例:(此处是Python2.6的写法,3.x时应该把 raw_input() 改成 input())
1.输入字符串
nID = raw_input(“Input your id plz:\n”); print(‘your id is %s’ % (nID))
2.输入整数
nAge = int(raw_input(“input your age plz:\n”)); print(‘your age is %d\n’ % nAge)
3.输入浮点型
fWeight = float(raw_input(“input your weight:\n”)); print(‘your weight is %f’ % fWeight)
4.输入16进制数据
nHex = int(raw_input(‘input hex value(like 0x20):\n’),16); print(‘nHex = %x,nOct = %d\n’ %(nHex,nHex))
5.输入8进制数据
nOct = int(raw_input(‘input oct value(like 020):\n’),8); print(‘nOct = %o,nDec = %d\n’ % (nOct,nOct))
注:打印字符串时,“%”作为特殊符号,两个百分号才能打印出一个百分号
Python 2 与 Python 3 的比较
Python 2 Python 3
① raw_input() input() # 最简单的形式,raw_input()被替换成input()。
② raw_input('prompt') input('prompt') # 可以指定一个提示符作为参数
③ input() eval(input()) # 如果想要请求用户输入一个Python表达式,计算结果
控制流:
if 语句
写法: if … elif … else … # if后面不用圆括号
注:在Python中没有switch语句。你可以使用 if..elif..else 语句来完成同样的工作(在某些场合,使用字典会更加快捷。)
在C/C++里面可以使用 else if ,但这里不行,得写成: else :\n\t if,故此增加关键字 elif
例:
number = 23
# int是一个类,不过这里它只是把一个字符串转换为一个整数(假设这个字符串含有一个有效的整数文本信息)。
guess = int(raw_input('Enter an integer : '))
if guess == number:
print('Congratulations, you guessed it.')
elif guess < number:
print('No, it is a little higher than that') # Another block
else:
print('No, it is a little lower than that')
while 语句
只要条件为真,while语句允许你重复执行一块语句。
注:while语句有一个可选的else从句。else块事实上是多余的,因为可以把其中的语句跟在while语句里面。
例:
number = 23
running = True
while running:
guess = int(raw_input('Enter an integer : '))
if guess == number:
print('Congratulations, you guessed it.')
running = False # this causes the while loop to stop
elif guess < number:
print('No, it is a little higher than that')
else:
print('No, it is a little lower than that')
else:
# Do anything else you want to do here
print('The while loop is over.')
for 循环
for..in 是另外一个循环语句,它在一序列的对象上 递归 即逐一使用队列中的每个项目。
else 部分是可选的。如果包含 else,它总是在 for 循环结束后执行一次,除非遇到 break 语句。
例:
for i in range(1, 5):
print(i)
else:
print('The for loop is over')
# 打印结果: 1 至 4 以及 else 的内容
# range(1,5)给出序列[1, 2, 3, 4]。range默认步长为1,第三个参数是步长。如,range(1,5,2)给出[1,3]。
# 记住,range包含第一个数,但不包含第二个数。
注:
Python的 for 循环从根本上不同于C/C++的 for 循环。类似 foreach 循环。
在C/C++中,如果你想要写 for (int i = 0; i < 5; i++),那么用Python,你写成 for i in range(0,5)。
# 范例:九九乘法表
# 由于Python2 与Python3的 print 语法不相同,改用string来打印,保证两个版本的输出结果相同。
str = ''
for i in range(1,10):
for j in range(1, i+1):
str += ('%d * %d = %d \t' % (j, i, i*j))
str += '\n'
print(str)
break 语句
break 语句是用来 终止 循环语句的,即哪怕循环条件没有称为 False 或序列还没有被完全递归,也停止执行循环语句。
一个重要的注释是,如果你从 for 或 while 循环中 终止 ,任何对应的循环 else 块将不执行。
continue 语句
continue 语句被用来告诉Python跳过当前循环块中的剩余语句,然后 继续 进行下一轮循环。
break 语句 和 continue 语句 对于 while 循环 和 for 循环 都有效。
例(2.x写法):
while True:
s = raw_input('Enter something : ')
if s == 'quit':
break
if len(s) < 3:
print 'Input is not of sufficient length'
continue
# Do other kinds of processing here...
print 'Length of the string is', len(s)
例(3.x写法):
while True:
s = input('Enter something : ') # 3.x用input()代替raw_input(),且会获取结尾输入的换行符
s = s[:-1] # 去掉结尾的换行符
if s == 'quit':
break
if len(s) < 3:
print('Input is not of sufficient length')
continue
# Do other kinds of processing here...
print('Length of the string is', len(s))
函数:
定义函数
函数通过def关键字定义。
def关键字后跟一个函数的 标识符 名称,然后跟一对圆括号。圆括号之中可以包括一些变量名,该行以冒号结尾。
接下来是一块语句,它们是函数体。
例:
def sayHello():
print('Hello World!') # block belonging to the function
sayHello() # call the function
函数形参
函数中的参数名称为 形参 而你提供给函数调用的值称为 实参 。
局部变量
当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的。
这称为变量的 作用域 。所有变量的作用域是它们被定义的块,从它们的名称被定义的那点开始。
例:
x = 50
def func(x):
print('x is', x)
x = 2
print('Changed local x to', x) # 打印: 2
func(x)
print('x is still', x) # 打印: 50, 值没有变
global 语句
如果要为一个定义在函数外的变量赋值,那么你就得告诉Python这个变量名不是局部的,而是 全局 的。使用global语句完成这一功能。
没有global语句,是不可能为定义在函数外的变量赋值的。
你可以使用定义在函数外的变量的值(假设在函数内没有同名的变量)。然而,应避免这样做,因为这降低程序的可读性,不清楚变量在哪里定义的。
使用global语句可以清楚地表明变量是在外面的块定义的。
注:可以使用同一个global语句指定多个全局变量。例如 global x, y, z。
例:
def func():
global x
print('x is', x)
x = 2
print('Changed local x to', x) # 打印: 2
x = 50
func()
print('Value of x is', x) # 打印: 2, 值被改变了
默认参数值
如果希望一些参数是 可选 的,这些参数可使用默认值。
可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。
注意,默认参数值应该是一个参数。
例:
def say(message, times = 2):
print(message * times)
say('Hello ') # 打印:Hello Hello
say('World ', 5) # 打印:World World World World World
重要:
只有在形参表末尾的那些参数可以有默认参数值,即不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。
这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=5)是有效的,但是def func(a=5, b)是 无效 的。
关键参数
如果某个函数有许多参数,而你只想指定其中的一部分,那么可以通过命名来为这些参数赋值
——这被称作 关键参数 ——使用名字(关键字)而不是位置来给函数指定实参。
这样做有两个优势:
一、由于我们不必担心参数的顺序,使用函数变得更加简单了。
二、假设其他参数都有默认值,我们可以只给我们想要的那些参数赋值。
例:
def func(a, b=5, c=10):
print('a is', a, 'and b is', b, 'and c is', c)
func(3, 7) # 参数a得到值3,参数b得到值7,而参数c使用默认值10。
func(25, c=24) # 根据实参的位置,变量a得到值25。根据命名,即关键参数,参数c得到值24。变量b根据默认值,为5。
func(c=50, a=100) # 使用关键参数来完全指定参数值。a得到值100,c得到值50。变量b根据默认值,为5。
return 语句
return语句用来从一个函数 返回 即跳出函数。我们也可选从函数 返回一个值 。
例:
def maximum(x, y):
if x > y:
return x
else:
return y
print(maximum(2, 3)) # 打印 3
None
None 是Python中表示没有任何东西的特殊类型(相当于java的 null)。例如,如果一个变量的值为None,可以表示它没有值。
注意:函数没有返回值的,等价于最后返回return None。通过运行print someFunction(),你可以明白这一点。
例:
def someFunction():
# pass语句在Python中表示一个空的语句块。它后面的代码会照常运行。
pass
print(someFunction())
DocStrings
DocStrings:文档字符串。它是一个重要的工具,帮助你的程序文档更加简单易懂,应该尽量使用它。甚至可以在程序运行的时候,从函数恢复文档字符串!
在函数的第一个逻辑行的字符串是这个函数的 文档字符串 。注意,DocStrings也适用于模块和类。
文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议遵循这个惯例。
例:
def printMax(x, y):
'''Prints the maximum of two numbers.
The two values must be integers.'''
x = int(x) # convert to integers, if possible
y = int(y)
if x > y:
print(x, 'is maximum')
else:
print(y, 'is maximum')
printMax(3, 5) # 打印: 5 is maximum
print(printMax.__doc__) # 打印: Prints the maximum ... must be integers.
注:
使用__doc__(注意是两个下划线)调用printMax函数的文档字符串属性。请记住Python把 每一样东西 都作为对象,包括这个函数。
Python中help()函数即是使用DocStings的了,它只是抓取函数的__doc__属性,然后整洁地展示给你。可以对上面的函数尝试一下: help(printMax)。记住按q退出help。
自动化工具也可以以同样的方式从你的程序中提取文档。因此强烈建议你对你所写的任何正式函数编写文档字符串。
函数属性 func_*
在Python 2里,函数的里的代码可以访问到函数本身的特殊属性。在Python 3里,为了一致性,这些特殊属性被重新命名了。
Python 2 与 Python 3 的比较
Python 2 Python 3 说明
① a_function.func_name a_function.__name__ # 包含了函数的名字。
② a_function.func_doc a_function.__doc__ # 包含了在函数源代码里定义的文档字符串(docstring)。
③ a_function.func_defaults a_function.__defaults__ # 是一个保存参数默认值的元组。
④ a_function.func_dict a_function.__dict__ # 一个支持任意函数属性的名字空间。
⑤ a_function.func_closure a_function.__closure__ # 一个由cell对象组成的元组,包含了函数对自由变量(free variable)的绑定。
⑥ a_function.func_globals a_function.__globals__ # 一个对模块全局名字空间的引用,函数本身在这个名字空间里被定义。
⑦ a_function.func_code a_function.__code__ # 一个代码对象,表示编译后的函数体。
模块:
如果要在其他程序中重用很多函数,那么你该使用模块。
模块基本上就是一个包含了所有你定义的函数和变量的文件。
为了在其他程序中重用模块,模块的文件名必须以.py为扩展名。
sys模块(标准库模块)
sys模块包含了与Python解释器和它的环境有关的函数。
例:
import sys # 输入 sys模块。基本上,这句语句告诉Python,我们想要使用这个模块。
print('The command line arguments are:')
# 打印调用文件的命令行参数
for i in sys.argv:
print(i)
print('\nThe PYTHONPATH is', sys.path)
输出:
$ python using_sys.py we are arguments
The command line arguments are:
using_sys.py
we
are
arguments
The PYTHONPATH is ['/home/swaroop/byte/code', '/usr/lib/python23.zip',
'/usr/lib/python2.3', '/usr/lib/python2.3/plat-linux2',
'/usr/lib/python2.3/lib-tk', '/usr/lib/python2.3/lib-dynload',
'/usr/lib/python2.3/site-packages', '/usr/lib/python2.3/site-packages/gtk-2.0']
注:
执行 import sys 语句的时候,它在 sys.path 变量中所列目录中寻找 sys.py 模块。
如果找到了这个文件,这个模块的主块中的语句将被运行,然后这个模块将能够被你使用。
注意,初始化过程仅在我们 第一次 输入模块的时候进行。另外,“sys”是“system”的缩写。
脚本的名称总是sys.argv列表的第一个参数。所以,在这里,'using_sys.py'是sys.argv[0]、'we'是sys.argv[1]。
sys.path包含输入模块的目录名列表。
可以观察到sys.path的第一个字符串是空的——这个空的字符串表示当前目录也是sys.path的一部分,这与PYTHONPATH环境变量是相同的。
这意味着你可以直接输入位于当前目录的模块。否则,你得把你的模块放在sys.path所列的目录之一。
另外:
sys.exit() # 程序结束
sys.stdin、 sys.stdout 和 sys.stderr 分别对应你的程序的标准输入、标准输出和标准错误流。
字节编译的.pyc文件
输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。
一种方法是创建 字节编译的文件,这些文件以.pyc作为扩展名。另外,这些字节编译的文件也是与平台无关的。
当你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。
from … import 语句
如果你想要直接输入 argv 变量到你的程序中(避免在每次使用它时打sys.),那么你可以使用 from sys import argv 语句。
如果你想要输入所有 sys 模块使用的名字,那么你可以使用 from sys import *语句。
这对于所有模块都适用。
注意:
1.使用 from package import item 方式导入包时,这个子项(item)既可以是包中的一个子模块(或一个子包),也可以是包中定义的其它命名,像函数、类或变量。
import 语句首先核对是否包中有这个子项,如果没有,它假定这是一个模块,并尝试加载它。如果没有找到它,会引发一个 ImportError 异常。
2.使用像 import item.subitem.subsubitem 这样的语句时,这些子项必须是包,最后的子项可以是包或模块,但不能是前面子项中定义的类、函数或变量。
3.应该避免使用 from…import 而使用 import 语句,因为这样可以使你的程序更加易读,也可以避免名称的冲突。
import … as
为 import 的模块起一个简称。如: import cPickle as p
起简称后,下面的语句即可使用简称,如原本的 cPickle.dump() 可写成 p.dump()
模块的 name
每个模块都有一个名称,在模块中可以通过语句来找出模块的名称。
这在一个场合特别有用——就如前面所提到的,当一个模块被第一次输入的时候,这个模块的主块将被运行。
假如我们只想在程序本身被使用的时候运行主块,而在它被别的模块输入的时候不运行主块,我们该怎么做呢?这可以通过模块的name属性完成。
每个Python模块都有它的name,如果它是’main‘,这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。
例:
# Filename: using_name.py
if __name__ == '__main__':
print('This program is being run by itself')
else:
print('I am being imported from another module')
输出:
$ python using_name.py
This program is being run by itself
$ python
>>> import using_name
I am being imported from another module
自定义模块
每个Python程序也是一个模块。
模块,例:
# Filename: mymodule.py
def sayhi():
print('Hi, this is mymodule speaking.')
version = '0.1'
# End of mymodule.py
上面是一个 模块 的例子。你已经看到,它与我们普通的Python程序相比并没有什么特别之处。
记住这个模块应该被放置在我们输入它的程序的同一个目录中,或者在 sys.path 所列目录之一。
用例1:
import mymodule
mymodule.sayhi()
print('Version', mymodule.version)
注:函数和成员都以点号来使用。
用例2: 使用from..import语法的版本。
from mymodule import sayhi, version # 或者写: from mymodule import *
sayhi()
print('Version', version)
包(Packages)
包通常是使用用“圆点模块名”的结构化模块命名空间。例如, A.B 表示名为”A” 的包中含有名为”B”的子模块。
使用圆点模块名保存不同类库的包可以避免模块之间的命名冲突。(如同用模块来保存不同的模块架构可以避免变量之间的命名冲突)
包目录必须要有一个 init.py 文件的存在;这是为了防止命名冲突而无意中在随后的模块搜索路径中覆盖了正确的模块。
最简单的情况下, init.py 可以只是一个空文件,不过它也可能包含了包的初始化代码,或者设置了 all 变量。
dir()函数
使用内建的dir函数来列出模块定义的标识符。标识符有函数、类和变量。
当你为 dir()提供一个模块名的时候,它返回模块定义的名称列表。如果不提供参数,它返回当前模块中定义的名称列表。
$ python
>>> import sys
>>> dir(sys) # get list of attributes for sys module
['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__',
'__stdin__', '__stdout__', '_getframe', 'api_version', 'argv',
'builtin_module_names', 'byteorder', 'call_tracing', 'callstats',
'copyright', 'displayhook', 'exc_clear', 'exc_info', 'exc_type',
'excepthook', 'exec_prefix', 'executable', 'exit', 'getcheckinterval',
'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding',
'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode',
'meta_path','modules', 'path', 'path_hooks', 'path_importer_cache',
'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags',
'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout',
'version', 'version_info', 'warnoptions']
>>> dir() # get list of attributes for current module
['__builtins__', '__doc__', '__name__', 'sys']
>>>
>>> a = 5 # create a new variable 'a'
>>> dir()
['__builtins__', '__doc__', '__name__', 'a', 'sys']
>>>
>>> del a # delete/remove a name; 这个得留意
>>>
>>> dir()
['__builtins__', '__doc__', '__name__', 'sys']
>>>
数据结构
可以处理一些 数据 的 结构 。或者说,它们是用来存储一组相关数据的。
在Python中有三种内建的数据结构——列表、元组和字典。
列表(list, 有的语言称为:数组)
是处理一组有序项目的数据结构,即你可以在一个列表中存储一个 序列 的项目。
列表中的项目应该包括在方括号中,每个项目之间用逗号分割。
可以添加、删除或是搜索列表中的项目。列表是 可变的 数据类型。
列表对象定义的所有方法可以通过 help(list) 获得完整的知识。我比较习惯称它为“数组”。
例:
shoplist = ['apple', 'mango', 'carrot', 'banana']
#查看长度
print('I have', len(shoplist),'items to purchase.')
#遍历
print('These items are:', end=' ') # 注意这行的结尾,打印时可以不换行,python 2.x应该用逗号结尾
for item in shoplist:
print(item, end=' ') # python 2.x 此行应该写:“print item,”
#添加
print('\nI also have to buy rice.')
shoplist.append('rice')
print('My shopping list is now:', shoplist)
#排序
print('I will sort my list now')
shoplist.sort()
print('Sorted shopping list is:', shoplist)
#删除,以及使用下标
print('The first item I will buy is:', shoplist[0])
olditem = shoplist[0]
del shoplist[0]
print('I bought the', olditem)
print('My shopping list is now:', shoplist)
#多维列表时,保存的对象只是引用
newlist = ['waa','dd']
shoplist.append(newlist)
print('My shopping list is now:', shoplist)
del newlist[0]
print('My shopping list is now', shoplist)
# 删除重复, 用 set (对元组也可以这样写)
L = [1,1,1,2,2]
print(list(set(L))) # 打印:[1, 2]
l = [(1, 2), (1, 2), 3, 5, 4, 3, 4, (1, 2), 0, 5]
l = list(set(l))
print(l) # 打印: [(1, 2), 0, 3, 4, 5]
# 复制列表(浅拷贝)
c = shoplist[:]
# 复制(深拷贝)
import copy
c = copy.deepcopy(shoplist)
元组(tuple)
元组和列表十分类似,只不过元组和字符串一样是 不可变的 即你不能修改元组。
元组通过圆括号中用逗号分割的项目定义。
元组通常用在使语句或用户定义的函数能够安全地采用一组值的时候,即被使用的元组的值不会改变。
如果你想要知道元组对象定义的所有方法,可以通过 help(tuple) 获得完整的知识。
例:
#一维元组
zoo = ('wolf', 'elephant', 'penguin')
print('Number of animals in the zoo is %s' % len(zoo)) # 打印: 3
newlist = ['waa','dd']
#多维元组
new_zoo = ('monkey', 'dolphin', zoo, newlist)
print('Number of animals in the new zoo is %s' % len(new_zoo)) # 打印: 3
print('All animals in new zoo are %s' % str(new_zoo)) # 打印: ('monkey','dolphin',('wolf','elephant','penguin'),['waa','dd'])
print('Animals brought from old zoo are %s' % str(new_zoo[2])) # 打印: ('wolf', 'elephant', 'penguin')
print('Last animal brought from old zoo is %s' % new_zoo[2][2]) # 打印: penguin
#多维元组时,保存的对象只是引用
del newlist[0]
print('new_zoo is now:' + str(new_zoo) ) # 打印: ('monkey','dolphin',('wolf','elephant','penguin'),['dd'])
注意:含有0个或1个项目的元组
一个空的元组(含有0个项目)由一对空的圆括号组成,如myempty = ()。
含有单个元素的元组必须在第一个(唯一一个)项目后跟一个逗号。如: singleton = (2 , )。
如果小括号里面只有唯一一个项目,而这个项目后面又没有跟一个逗号的话,Python会认为它是一个表达式。
字典(dict, 有的语言称为:json)
字典把键(名字)和值(详细情况)联系在一起。
注意,键必须是唯一的,且只能使用不可变的对象(比如字符串)来作为字典的键,但字典的值没有此限制。应该说只能使用简单的对象作为键。
键值对在字典中以这样的方式标记:d = {key1 : value1, key2 : value2 }。
键值对用冒号分割,而各个对用逗号分割,所有这些都包括在花括号中。
记住字典中的键/值对是没有顺序的。如果要一个特定的顺序,那么应该在使用前自己对它们排序。
字典是dict类的实例/对象,可以用 help(dict) 来查看其属性和函数。
例:
ab = { 'Swaroop': 'swar',
'Larry' : 'larry',
'Spammer': 'spammer'
}
print(ab) # 打印: {'Swaroop':'swar', 'Larry':'larry', 'Spammer':'spammer'}
print("Swaroop's address is %s" % ab['Swaroop']) # 打印: swar
# 添加值,或者设值
ab['Guido'] = 'guido'
# 删除值
del ab['Spammer']
# ab.pop('Spammer') # 也可以用 pop 来删除,但建议后面的这种写法,避免没有这个键时会报错: ab.pop('Spammer', None)
print('\nThere are %d contacts in the address-book\n' % len(ab)) # 打印: 3
# 遍历(这写法得留意)
for name, address in ab.items():
print('Contact %s at %s' % (name, address))
# 包含key
if 'Guido' in ab: # 或者写: if ab.has_key('Guido'):
print("\nGuido's address is %s" % ab['Guido'])
# 原字典上创建新字典
print(ab) # 打印: {'Swaroop':'swar', 'Larry':'larry', 'Guido':'guido'}
dd = dict(ab, slug_field='slug', test=5) # 创建新字典,字典作为参数的只能放第一个,其余不能再是字典;字典参数可省略
print(dd) # 打印: {'Swaroop':'swar', 'test':5, 'slug_field':'slug', 'Larry':'larry', 'Guido':'guido'}
# 建议的取值方法
print( ab['test'] ) # 这样取值,当字典里面没有对应的key时会报错:“KeyError”
print( ab.get('test', 'default_value') ) # get取值,当字典里面没有对应的key时可取后面的预设值,预设值是可选的(默认是 None)
# 所有的键和值
print(ab.keys()) # 所有的键
print(ab.values()) # 所有的值
# 复制(浅拷贝)
print(ab.copy())
# 复制(深拷贝)
import copy
c = copy.deepcopy(ab)
序列
列表、元组和字符串都是序列,序列的两个主要特点是“索引”操作符和“切片”操作符。
索引操作符让我们可以从序列中抓取一个特定项目。(即使用下标)
切片操作符让我们能够获取序列的一个切片,即一部分序列。(即在下标的中括号里面使用冒号)
例:
shoplist = ['apple', 'mango', 'carrot', 'banana']
# Indexing or 'Subscription' operation
print('Item 0 is %s' % shoplist[0])
print('Item 3 is %s' % shoplist[3])
print('Item -1 is %s' % shoplist[-1]) # 打印:banana 即倒数第一个
print('Item -2 is %s' % shoplist[-2]) # 打印:carrot 即倒数第二个
# Slicing on a list
print('Item 1 to 3 is %s' % shoplist[1:3]) # 打印:['mango', 'carrot'] 即下标[1]到[3],包括开始但不包括结束
print('Item 2 to end is %s' % shoplist[2:]) # 打印:['carrot', 'banana'] 即下标[2]到结束,包括最后一个
print('Item 1 to -1 is %s' % shoplist[1:-1]) # 打印:['mango', 'carrot'] 即下标[1]到[-1],包括开始但不包括结束
print('Item start to end is %s' % shoplist[:]) # 打印整个列表,跟直接写“shoplist”效果一样
# Slicing on a string (string与列表有同样的操作,)
name = 'swaroop'
print('characters 1 to 3 is %s' % name[1:3]) # 打印:wa
print('characters 2 to end is %s' % name[2:]) # 打印:aroop
print('characters 1 to -1 is %s' % name[1:-1]) # 打印:waroo
print('characters start to end is %s' % name[:]) # 打印:swaroop 跟直接写这个字符串一样
参考(引用)
当你创建一个对象并给它赋一个变量的时候,这个变量仅仅 参考 那个对象,而不是表示这个对象本身!
也就是说,变量名指向你计算机中存储那个对象的内存。
这被称作名称到对象的绑定。
例:
shoplist = ['apple', 'mango', 'carrot', 'banana']
mylist = shoplist # mylist 只是对象的另一个名称,他们指向相同的内存空间
del shoplist[0]
# 他们此时打印相同的内容,都少了'apple'
print('shoplist is', shoplist)
print('mylist is', mylist)
# 深拷贝,复制成另一个对象(得记住用切片操作符来取得拷贝)
mylist = shoplist[:] # make a copy by doing a full slice
del mylist[0] # remove first item
# 注意,现在他们打印出不同的内容
print('shoplist is', shoplist)
print('mylist is', mylist)
列表综合
通过列表综合,可以从一个已有的列表导出一个新的列表。
[返回值 for 元素 in 列表 if 条件] 比如 [num for num in xrange(100) if num%2==0] 返回0~99之间的偶数列表
# 例如,你有一个数的列表,而你想要得到一个对应的列表,使其中所有大于2的数都是原来的2倍。对于这种应用,列表综合是最理想的方法。
listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2] # 为满足条件(if i > 2)的数指定了一个操作(2*i),从而导出一个新的列表。
print(listtwo) # 打印: [6, 8]
ls=[1,3,5,7] # reduce 在python3去掉了
print(reduce(lambda x,y:x+y,ls)) # 计算过程就是 1+3=4 然后4+5得到结果9,再加7,以此类推,最后返回最终计算的结果(总和);打印:16
# 将字典的key,value倒过来的写法:
a_dict = {'a': 1, 'b': 2, 'c': 3}
# python3 的写法:
b_dict = {value:key for key, value in a_dict.items()}
# python2 时的写法:
b_dict = {}
for key, value in a_dict.iteritems():
b_dict[value] = key
print(b_dict) # key与value翻转,打印: {1:'a', 2:'b', 3:'c'}
说明:
注意原来的列表并没有发生变化。
在很多时候,我们都是使用循环来处理列表中的每一个元素,而使用列表综合可以用一种更加精确、简洁、清楚的方法完成相同的工作。
小心 list 的 += 操作(python2时可以用,python3不可以再这样用)
集合
Python3 开始有这写法,跟之前的差不多,只是用大括号括起来,如: a = {1, ‘aa’, 3, 5, 6}
集合同样可以使用综合计算,如: a = {x for x in range(10) if x % 2 == 0}
成员测试 in, not in
检查是否包含有此内容,返回 True 或者 False, 例如:
# 1.对字符串
if 'a' in 'Swaroop':
print('Yes, it contains the string "a"')
# 2.对集合(列表、元组和字典)
if 'genre' in ('genre', 'jazz'):
print('Yes, it contains the genre')
print('genre' in ('genre', 'jazz')) # 元组,打印: True
print('genre' in ['genre', 'jazz']) # 列表,打印: True
print('genre' in {'genre':'sss', 'jazz':'dddd'}) # 字典,检查key,打印: True
print('sss' in {'genre':'sss', 'jazz':'dddd'}) # 字典,打印: False
排序
1.sort方法
Python语言内置了sort方法,可以很方便地对某个List进行排序
例如:
L = [6, 5, 1, 3, 4, 2]
L.sort()
print(L) # 打印:[1, 2, 3, 4, 5, 6]
li=[(2,’a’),(4,’b’),(1,’d’)]
li.sort() # 元组列表排序
print(li) # 打印: [(1, ‘d’), (2, ‘a’), (4, ‘b’)]
2.自定义排序(例如,按关键词的权重排序,按人的年龄排序,等等)
若List中每个元素都是2-tuple,tuple中第一个元素为String类型的keyword,第二个元素为该字符串对应的权重(int类型),希望按照权重排序(从高到低),则可以这样:
L = [('b', 1), ('a', 0), ('c', 2), ('d', 3)]
# L.sort(lambda E1, E2: -cmp(E1[1], E2[1])) # cmp函数里面是需比较的两个值,负号表示倒序。(python2 的写法)
L.sort(key=lambda d:-d[1]) # Python3的写法,由于去掉了cmp()函数,得传入key参数; python2也可以这样用;负号表示倒序
print(L) # 打印:[('d', 3), ('c', 2), ('b', 1), ('a', 0)]
3.dict排序
对字典的排序,因为每一个项包括一个键值对,所以要选择可比较的键或值进行排序
sorted(iterable[, cmp[, key[, reverse]]])
# cmp 和 key 一般使用 lambda
如:
d={"ok":1,"no":2}
# 对字典按键排序,用元组列表的形式返回
print(sorted(d.items(), key=lambda a:a[0])) # 打印: [('no', 2), ('ok', 1)]
print(sorted(d)) # 打印:['no', 'ok']
print(d) # 原字典并未改变,打印:{'ok':1, 'no':2}
# 对字典按值排序,用元组列表的形式返回
print(sorted(d.items(), key=lambda d:d[1])) # 打印:[('ok', 1), ('no', 2)]
# 排序后再转成字典,就无法再保证排序了
b = sorted(d.items(), key=lambda v:v[0])
print(b) # 打印: [('no', 2), ('ok', 1)]
print(dict(b)) # (排序又乱了)打印: {'ok': 1, 'no': 2}
4.类的排序
class test:
def __init__(self,a,b):
self.a = a
self.b = b
test1 = test(5,25)
test2 = test(50,35)
test3 = test(10,15)
tests = [test1, test2, test3]
# 以 cmp 来指定排序方式, python3不可以这样写(没有cmp参数及cmp函数)
result = sorted(tests,cmp = lambda x,y: cmp(x.a, y.a))
# 遍历排序结果,结果是已排序的: a:5 a:10 a:50
for item in result:
print("a:%s" % item.a)
# 以 key 来排序,结果也是可以的
result2 = sorted(tests,key = lambda d:d.a)
for item in result2:
print("a:%s" % item.a)
# 遍历原资料,原资料的顺序没有改变
for item in tests:
print("a:%s" % item.a)
5.注意:
python3 由于去掉了 cmp() 函数,可以用“(a > b) - (a < b)”代替“ cmp(a, b) ”
6.冒泡算法,如下:
num = [23,2,3,6,18,9,33,13,24,19]
for i in range(len(num)-1):
for j in range(len(num)-i-1):
if (num[j] > num[j+1]):
num[j], num[j+1] = num[j+1], num[j] # 置换,这样写比较简便,不需再用临时变量
print(num)
综合实例:
在Python中对列表,元组,字典等内置的数据结构的处理是很方便的事情,python借鉴了Lisp中的很多函数式计算的方法来处理列表,可以极大的简化我们的代码。
1. set(): 将元组,列表 转化成没有重复项的集合
2. list(): 将集合,元组转化成列表
3. tuple(): 将集合,列表转化成元组
4. map(func,list):将list的每一个元素传递给func的函数,这个函数有一个参数,且返回一个值,map将每一次调用函数返回的值组成一个新列表返回
5. filter(func,list):将list的每一个元素传递给func的函数,这个函数有一个参数,返回bool类型的值,filter将返回True的元素组成新列表返回
6. reduce(func,list):将list的元素,挨个取出来和下一个元素通过func计算后将结果和再下一个元素继续计算
一、列表去重
ls = [1,3,2,5,2,1,3,4,6]
ls = list(set(ls)) # 最简单的列表去除重复
L = [1, 8, 3, 4, 6, 2, 3, 4, 5]
kk = [x for x in L if x not in locals()['_[1]']] # 保留原顺序的去除重复,只有 2.6 上可以, 2.7 以上版本不能这样写
# '_[1]' 是个内部临时变量,可查看: [x for x, y in locals().items()]
二、假如有列表:
books = [
{"name":"C#从入门到精通", "price":23.7, "store":"卓越"},
{"name":"ASP.NET高级编程", "price":44.5, "store":"卓越"},
{"name":"C#从入门到精通", "price":24.7, "store":"当当"},
{"name":"ASP.NET高级编程", "price":45.7, "store":"当当"},
{"name":"C#从入门到精通", "price":26.7, "store":"新华书店"},
{"name":"ASP.NET高级编程", "price":55.7, "store":"新华书店"},
]
2.1 求《ASP.NET高级编程》价格最便宜的店:
storename=min([b for b in books if b['name']=="ASP.NET高级编程"],key=lambda b:b['price'])["store"]
过程:先用列表解析取出《ASP.NET高级编程》的列表,通过min函数,比较字典的price键获取price最小的项
2.2 求在新华书店购买两本书一样一本要花的钱:
price=sum([b['price'] for b in books if b['store']=="新华书店"])
2.3 求列表中有那几本书:
booknames=list(set([b['name'] for b in books]))
2.4 列表里的书都打5折:
books=map(lambda b:dict(name=b['name'],price=b['price']*0.5,store=b['store']),books)
2.5 《C#从入门到精通》的平均价格:
avg=(lambda ls:sum(ls)/len(ls))([b['price'] for b in books if b['name']=="C#从入门到精通"])
2.6 求每本书的平均价格:
book_avg=map(lambda bookname:dict(name=bookname,avg=(lambda ls:sum(ls)/len(ls))([b['price'] for b in books if b['name']==bookname])),list(set([b['name'] for b in books])))
这段代码放在一行比较难看懂,但是格式化一下就很好懂了,构建的过程如下:
step1: 要求每本书的平均价格,首先要得到共有几本书,方法见2.3,得到去重的书名列表
list(set([b['name'] for b in books])) #去重后的书名列表
step2: 要求每一本书的均价,需要将计算均价的函数映射到每一本书上,于是
map(
#计算均价的函数,
list(set([b['name'] for b in books])) #去重后的书名列表
)
step3: 加入计算单本书均价的函数,参考2.5的方法,由于只用一行,所以用lambda来搞定:
func=lambda bookname:(lambda ls:sum(ls)/len(ls))([b.price for b in books if b['name']==bookname])
step4: 将计算单本均价的lambda函数加入map中,得到最终结果:
经过格式化后的结果,前面的单行代码可以格式化为下面容易阅读的形式
book_avg=map(
lambda bookname:
dict(
name = bookname,
# 计算单本书均价的函数
avg = (lambda ls:sum(ls)/len(ls)) ([b['price'] for b in books if b['name']==bookname])
),
#去重后的书名列表
list(
set(
[b['name'] for b in books]
)
)
)
在函数中接收元组和列表(函数的参数数量可以变动,即可变长参数)
当要使函数接收元组或字典形式的参数的时候,有一种特殊的方法,它分别使用和*前缀。
这种方法在函数需要获取可变数量的参数的时候特别有用。
而且,使用和*前缀的参数还可以传递给其它函数。
例:
# 由于在args变量前有*前缀,所有多余的函数参数都会作为一个元组存储在args中
def sum(message, *args):
'''Return the sum of each argument.'''
total = 0
# 除了用循环,也可以用下标来读取参数,如: args[0]
for i in args:
total += i
print (str(type(args)) + ' ' + message + ":" + str(total))
sum2(args) # 这样传过去的 args 是一个元组;打印如: ((3, 5.5),)
sum2(*args) # 这样传过去的 *args 表示多个参数;打印如:(3, 5.5)
def sum2(*args):
print(args)
sum('hight', 3, 5.5) # 打印: hight:8.5
sum('weight', 10) # 打印: weight:10
# 函数参数接收字典用法。使用的是**前缀,多余的参数则会被认为是一个字典的键/值对。
def printDict(message, **args):
print(str(type(args)) + ' ' + message + ':' + str(args))
printDict2(args = args) # 可这样,把 args 当做一个值(里面是字典),传过去;打印如: {'args': {'a': 3, 'b': 'dd'}}
printDict2(**args) # 也可这样,把 **args 看做传过来的多个键/值对,传过去;打印如:{'a': 3, 'b': 'dd'}
def printDict2(**args):
print(args)
# 注意:参数为字典时,参数里面必须使用等号,否则运行出错
printDict('hight', a=3, b='dd') # 打印: hight:{'a': 3, 'b': 'dd'}
# 可以混合使用*和**前缀的参数, 但是必须 *args 在前, **args 在后,否则编译不通过
def printMul(message, *args1, **args2):
print(message + ' args1:' + str(args1) + ' args2:' + str(args2))
printMul('hello', 5, 4, a=2, b=3) # 打印: hello args1:(5, 4) args2:{'a': 2, 'b': 3}
面向对象的编程
面向过程的编程:根据操作数据的函数或语句块来设计程序的。
面向对象的编程:把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。
类和对象是面向对象编程的两个主要方面。“类”创建一个新类型,而“对象”是这个类的实例。
域:属于一个对象或类的变量。
方法:属于类的函数,被称为类的方法。
域和方法可以合称为类的属性。
域有两种类型——属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。
类使用class关键字创建。类的域和方法被列在一个缩进块中。
self 参数
类的方法与普通的函数只有一个特别的区别——它们“必须”有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。
虽然你可以给这个参数任何名称,但是“强烈建议”使用self这个名称——其他名称都是不赞成使用的。
使用一个标准的名称有很多优点——1.方便别人阅读;2.有些IDE(集成开发环境)也可以帮助你。
Python中的self等价于C++中的self指针和Java、C#中的this参考。
例:
class Person:
def sayHi(self): # self参数必须写
print('Hello, how are you?')
p = Person()
p.sayHi() # self参数不需赋值
print(p) # 打印: <__main__.Person instance at 0xf6fcb18c> (已经在__main__模块中有了一个Person类的实例)
类的变量和对象的变量
类的变量: 由一个类的所有对象(实例)共享使用。当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。
对象的变量: 由类的每个对象/实例拥有。它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。
使用的数据成员名称以“双下划线前缀”且不是双下划线后缀,比如__privatevar,Python的名称管理体系会有效地把它作为私有变量。
惯例: 如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。
例:
class Person:
'''Represents a person.'''
population = 0 # 类的变量
def __init__(self, name):
'''Initializes the person's data.'''
# 每创建一个对象都增加1
Person.population += 1 # 调用类的变量,必须用 类名.变量名,如果写 self.变量名 则是对象的变量了
self.name = name # 对象的变量,每个对象独立的
print('(Initializing %s) We have %d persons here.' % (self.name, Person.population))
def __del__(self):
'''I am dying.'''
print('%s says bye.' % self.name)
Person.population -= 1
def sayHi(self):
self.__sayHi2() # 调用私有方法,外部不能调用的
# 以双下划线开头(但没有双下划线结尾),则变成私有,仅供内部调用
def __sayHi2(self): # 使用 self.population 也可以读取类的变量,只是改变的时候却只改变对象的变量
print('Hi, my name is %s. We have %d persons here.' % (self.name, self.population))
swaroop = Person('Swaroop')
swaroop.sayHi() # 打印: Swaroop, 1
kalam = Person('Abdul Kalam')
kalam.sayHi() # 打印: Abdul Kalam, 2
swaroop.sayHi() # 打印: Swaroop, 2
print(Person.population) # 打印: 2
del swaroop # 调用对象的 __del__ 方法
print(Person.population) # 打印: 1
print(Person.__doc__) # 打印类的docstring
print(Person.__init__.__doc__) # 打印类的方法的docstring
继承
多态现象:一个子类型在任何需要父类型的场合可以被替换成父类型,即对象可以被视作是父类的实例。
被继承的类被称为“基本类”或“超类”、“父类”。继承的类被称为“导出类”或“子类”。
例:
# 父类
class Member:
def __init__(self, name, age):
self.name = name
self.age = age
print('(Initialized Member: %s)' % self.name)
def tell(self):
print('Member Name:"%s" Age:"%s"' % (self.name, self.age))
def tell2(self):
print('Member haha...')
# 子类
class Student(Member): # 继承的父类写括号里面;多继承则写多个,这括号的称为继承元组
def __init__(self, name, age, marks):
Member.__init__(self, name, age) # 父类的初始化,需手动写;Python不会自动调用父类的constructor
self.marks = marks
print('(Initialized Student: %s)' % self.name)
def tell(self):
Member.tell(self) # 调用父类的方法,注意:方法调用之前要加上父类名称前缀,然后把self变量及其他参数传递给它。
print('Marks: "%d"' % self.marks)
s = Student('Swaroop', 22, 75)
s.tell() # 会调用子类的方法
s.tell2() # 子类没有的,则使用父类的;如果多继承,且父类都有这个方法,则使用继承元组中排前面的
特殊的方法
init 方法
init 方法在类的一个对象被建立时,马上运行。用来对你的对象做初始化。
注意,这个名称的开始和结尾都是双下划线。( init 方法类似于C++、C#和Java中的 constructor )
例:
class Person:
def __init__(self, name):
self.test_name = name
def sayHi(self):
print('Hello, my name is ' + self.test_name)
self.test = 'sss' # 属性可以随处定义,不需事先定义
print('the test is ' + self.test)
p = Person('Swaroop')
p.sayHi() # 打印: Swaroop , sss
print('the Person test is ' + p.test) # 打印: sss
p.test2 = 'haha...'
print('the Person test2 is ' + p.test2) # 打印: haha...
名称 说明
__init__(self,...) 这个方法在新建对象恰好要被返回使用之前被调用。
__del__(self) 在对象要被删除之前调用。如使用 del 删除时。
__str__(self) 在我们对对象使用 print 语句或是使用 str() 的时候调用。
__lt__(self,other) 当使用 小于 运算符 (<) 的时候调用。
__gt__(self,other) 当使用 大于 运算符 (>) 的时候调用。
__eq__(self,other) 当使用 等于 运算符 (==) 的时候调用。
__ne__(self,other) 当使用 不等于 运算符 (!=) 的时候调用。
__le__(self,other) 当使用 小于等于 运算符 (<=) 的时候调用。
__ge__(self,other) 当使用 大于等于 运算符 (>=) 的时候调用。
__add__(self,other)当使用 加 运算符 (+) 的时候调用。
__getitem__(self,key) 使用x[key]索引操作符的时候调用。
__len__(self) 对序列对象使用内建的 len() 函数的时候调用。
try … except (处理异常)
使用 try … except 语句来处理异常。
except 从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。没有给出错误或异常的名称,则处理所有的错误和异常。
如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并且打印一个消息。
还可以关联上一个 else 从句,当没有异常发生的时候执行。
常见异常(可避免的):
使用不存在的字典关键字 将引发 KeyError 异常。
搜索列表中不存在的值 将引发 ValueError 异常。
调用不存在的方法 将引发 AttributeError 异常。
引用不存在的变量 将引发 NameError 异常。
未强制转换就混用数据类型 将引发 TypeError 异常。
导入一个并不存在的模块将引发一个 ImportError 异常。
try … finally
假如希望在无论异常发生与否的情况下都执行一段代码,可以使用 finally 块来完成。
注意,在一个 try 块下,你可以同时使用 except 从句和 finally 块。
如果在 finally 前面的 try 或者 except, else 等里面有 return 语句,会先跳去执行 finally 再执行 return
raise 语句
可以使用 raise 语句引发异常(抛出异常)。你还得指明错误/异常的名称和伴随异常触发的异常对象。
可以引发 Error 或 Exception 类的直接或间接导出类。
在Python 3里,抛出自定义异常的语法有细微的变化。
Python 2 Python 3
① raise MyException MyException
② raise MyException, 'error message' raise MyException('error message')
③ raise MyException, 'error message', a_traceback raise MyException('error message').with_traceback(a_traceback)
④ raise 'error message' unsupported(不支持)
说明:
① 抛出不带自定义错误信息的异常,这种最简单的形式下,语法没有改变。
② 抛出带自定义错误信息的异常时:Python 2用一个逗号来分隔异常类和错误信息;Python 3把错误信息作为参数传递给异常类。
③ 抛出一个带用户自定义回溯(stack trace,堆栈追踪)的异常。在Python 2和3里这语法完全不同。
④ 在Python 2里,可以仅仅抛出一个异常信息。在Python 3里,这种形式不再被支持。2to3将会警告你它不能自动修复这种语法。
例:
raise RuntimeError("有异常发生")
生成器的 throw 方法
在Python 2里,生成器有一个 throw()方法。
调用 a_generator.throw()会在生成器被暂停的时候抛出一个异常,然后返回由生成器函数获取的下一个值。
Python 2 Python 3
① a_generator.throw(MyException) a_generator.throw(MyException) # 没有变化
② a_generator.throw(MyException, 'error message') a_generator.throw(MyException('error message'))
③ a_generator.throw('error message') unsupported(不支持)
说明:
① 最简单的形式下,生成器抛出不带用户自定义错误信息的异常。这种情况下,从Python 2到Python 3语法上没有变化 。
② 如果生成器抛出一个带用户自定义错误信息的异常,你需要将这个错误信息字符串(error string)传递给异常类来以实例化它。
③ Python 2还支持抛出只有异常信息的异常。Python 3不支持这种语法,并且2to3会显示一个警告信息,告诉你需要手动地来修复这处代码。
例(3.x)语法:
# 定义一个异常类,继承 Exception
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s = input('Enter something --> ') # Python 2 的输入是 raw_input()
if len(s) < 3:
raise ShortInputException(len(s), 3) # 引发异常;Python 2可以写:raise ShortInputException,(len(s), 3)
# 捕获 EOFError 异常
except EOFError:
print('\nWhy did you do an EOF on me?')
# 捕获一组错误/异常,Python 2 时应该写: “except (RuntimeError, ImportError), e:”
except (RuntimeError, ImportError) as e:
pass
# Python 2 时应该写: “except ShortInputException, x:”
except ShortInputException as x:
print('ShortInputException: The input was of length %d,\
was expecting at least %d' % (x.length, x.atleast))
# 捕获所有异常
except:
print('\nWhy did you do an Exception on me?')
# 没有任何异常时执行
else:
print('No exception was raised.')
# 不管是否有异常,都会执行
finally:
print('finally .....')
lambda 形式
lambda 语句被用来创建新的函数对象,并且在运行时返回它们。
注意, lambda 形式中,只能使用表达式。
例:
def make_repeater(n):
return lambda s: s*n # 注意: lambda 返回的是函数,而不是表达式的值
# 注意, twice 接收的是函数, 而不是表达式的值, 所以 twice 是一个函数,而不是值
twice = make_repeater(2)
print(twice('word ')) # 因为 twice 是一个函数,这里是调用这个函数,打印结果: word word
print(make_repeater(3)(5)) # 这里的“make_repeater(3)”可以认为是匿名函数,打印结果: 15
# 上面例子貌似太过复杂,下面是简单点的写法
# 记住, twice2 是一个函数
twice2 = lambda s: s*2
print(twice2('word ')) # 打印: word word
print(twice2(5)) # 打印: 10
# 上面的 twice2 相当于正常的函数这样写(lambda 后面的是参数,而结果是返回冒号后面的表达式):
def twice3(s):
return s*2
print(twice3('word ')) # 打印: word word
print(twice3(5)) # 打印: 10
# 可认为 lambda 是一个匿名函数
print((lambda s: s*2)('word ')) # 打印: word word
# 而 def 是不能申明匿名函数的
print((def (s): return s*2)(10)) # 这写法将会报错
print((def twice3(s): return s*2)(10)) # 这写法也同样会报错
# lambda 可以有多个参数
twice4 = lambda x,y: x*y
print(twice4('word ', 3)) # 打印: word word word
print(twice4(5, 3)) # 打印: 15
exec 和 eval
exec 用来执行储存在字符串或文件中的Python语句。
eval 用来计算存储在字符串中的有效Python表达式。
exec 跟 eval 是相似的,但是 exec 更加强大并更具有技巧性。
eval 只能执行单独一条表达式;但是 exec 能够执行多条语句,导入(import),函数声明
实际上 exec 能执行整个Python程序的字符串。
Python 2 与 Python 3 的比较
Python 2 Python 3
① exec codeString exec(codeString)
② exec codeString in global_namespace exec(codeString, global_namespace)
③ exec codeString in global_namespace, local_namespace exec(codeString, global_namespace, local_namespace)
说明:
① 就像 print 语句在Python 3里变成了一个函数一样, exec 语句在Python 3里也变成一个函数。
② exec 可以指定名字空间,代码将在这个由全局对象组成的私有空间里执行。
③ exec 还可以指定一个本地名字空间(比如一个函数里声明的变量)。
例:
exec('print("Hello World")') # 执行打印语句
print(eval('2*3')) # 打印:6
execfile 语句
Python 2里的 execfile 语句也可以像执行Python代码那样使用字符串。不同的是 exec 使用字符串,而 execfile 则使用文件。
在Python 3里,execfile 语句已经被去掉了。如果你真的想要执行一个文件里的Python代码(但是你不想导入它),你可以通过打开这个文件,读取它的内容,然后调用 compile()全局函数强制Python解释器编译代码,然后调用 exec() 函数。
Python 2 写的: execfile('a_filename')
Python 3 写的: exec(compile(open('a_filename', 'rb').read(), 'a_filename', 'exec'))
assert 语句
assert 语句用来声明某个条件是真的。
当 assert 语句失败的时候,会引发一个 AssertionError 错误。
比较常用于检验错误。
例:
assert 2 >= 1 # 正常运行
assert 0 >= 1 # 出现错误
repr 函数
repr 函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。
注意,在大多数时候有 eval(repr(object)) == object。
基本上, repr 函数和反引号用来获取对象的可打印的表示形式。
你可以通过定义类的 repr 方法来控制你的对象在被repr函数调用的时候返回的内容。
例:
i = ["item"]
print(repr(i)) # 打印:['item']
yield 用法
1) 包含 yield 的函数是一个 Generator, 与平常的函数不同
例:
def gen():
print 'enter'
yield 1
print 'next'
yield 2
print 'next end'
print('begin...')
gen() # 直接调用,发现打印没有执行(与平常的函数不同)
# 从容器里拿到 iterator 的时候它还什么也不是,处在容器入口处,对于数组来说就是下标为-1的地方,对于函数来说就是函数入口嘛事没干,但是万事俱备就欠 next 。
print('end...')
print
for i in gen():
print('...%d...' % i)
# 开始 for in , next 让 itreator 爬行到 yield 语句存在的地方并返回值,
# 再次 next 就再爬到下一个 yield 语句存在的地方并返回值,依次这样直到函数返回(容器尽头)。
上面代码的输出是:
begin...
end...
enter
...1...
next
...2...
next end
2) Generator 里面的 send(msg) 与 next()
调用 for in 时,相当于是使用 next() 语句或是 send(None)
如果没有接收值则使用 send 发送的值必须是 None ,否则会出错的,因为 yield 语句没有接收这个值,但 send 又必须传参数的。
例,用上例的 gen() 函数
c = gen()
print(c.next()) # 调用第一个 yield
print(c.send(None)) # 调用第二个 yield, 这里 next() 与 send(None) 是同样效果的
print(c.next()) # 第三次调用则出错了,因为数组下标越界, 抛出 StopIteration 的异常; 但会把最后的“next end”打印出来,前两个是没法把它打印出来的
# send(msg) 貌似没法把 msg 传到参数中
def gen2(m):
for i in range(10):
print(m)
yield i + 101
d = gen2('***')
print(c.next())
print(c.send(5555)) # 打印的依然是 ***, 而不是 5555
3) throw() 与 close() 中断 Generator
中断 Generator 是一个非常灵活的技巧,可以通过 throw 抛出一个 GeneratorExit 异常来终止 Generator 。 Close() 方法作用是一样的,其实内部它是调用了 throw(GeneratorExit) 的。我们看:
def close(self):
try:
self.throw(GeneratorExit)
except (GeneratorExit, StopIteration):
pass
else:
raise RuntimeError("generator ignored GeneratorExit") # Other exceptions are not caught
因此,当我们调用了 close() 方法后,再调用 next() 或是 send(msg) 的话会抛出一个异常
例,继续用前面例的 gen() 函数
c = gen()
print(c.next()) # 调用第一个 yield
c.close()
print(c.next()) # 调用第二个 yield 出错了,抛出 StopIteration 的异常, 因为前面的 close 已经关闭它了
正则表达式
正则表达式有强大并且标准化的方法来处理字符串查找、替换以及用复杂模式来解析文本。
正则表达式的语法比程序代码更紧凑,格式更严格,比用组合调用字符串处理函数的方法更具有可读性。
还可以在正则表达式中嵌入注释信息,这样就可以使它有自文档化的功能。
匹配符:
^ 匹配字符串开始位置。在多行字符串模式匹配每一行的开头。
$ 匹配字符串结束位置。在多行字符串模式匹配每一行的结尾。
. 匹配除了换行符外的任何字符,在 alternate 模式(re.DOTALL)下它甚至可以匹配换行。
\A 匹配字符串开头
\Z 匹配字符串结尾
\b 匹配一个单词边界。即 \w 与 \W 之间。
\B 匹配一个非单词边界;相当于类 [^\b]。
\d 匹配一个数字。
\D 匹配一个任意的非数字字符。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]。
x? 匹配可选的x字符。即是0个或者1个x字符。
x* 匹配0个或更多的x。
x+ 匹配1个或者更多x。
x{n,m} 匹配n到m个x,至少n个,不能超过m个。
(a|b|c) 匹配单独的任意一个a或者b或者c。
(x) 捕获组,小括号括起来即可,它会记忆它匹配到的字符串。
可以用 re.search() 返回的匹配对象的 groups()函数来获取到匹配的值。
\1 记忆组,它表示记住的第一个分组;如果有超过一个的记忆分组,可以使用 \2 和 \3 等等。
记忆组的内容也要小括号括起来。
(?iLmsux) iLmsux的每个字符代表一种匹配模式
re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
re.M(re.MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
re.S(re.DOTALL): 点任意匹配模式,改变'.'的行为
re.L(re.LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
re.U(re.UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
re.X(re.VERBOSE): 松散正则表达式模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。
(?:表达式) 无捕获组。与捕获组表现一样,只是没有内容。
(?P表达式) 命名组。与记忆组一样,只是多了个名称。
(?P=name) 命名组的逆向引用。
(?#...) “#”后面的将会作为注释而忽略掉。例如:“ab(?#comment)cd”匹配“abcd”
(?=...) 之后的字符串需要匹配表达式才能成功匹配。不消耗字符串内容。 例:“a(?=\d)”匹配“a12”中的“a”
(?!...) 之后的字符串需要不匹配表达式才能成功匹配。不消耗字符串内容。 例:“a(?!\d)”匹配“abc”中的“a”
(?<=...) 之前的字符串需要匹配表达式才能成功匹配。不消耗字符串内容。 例:“(?<=\d)a”匹配“2a”中的“a”
(?...) 定义一个命名组,(?P=name) 则是对命名组的逆向引用。
MatchObject 的方法处理捕获组时接受的要么是表示组号的整数,要么是包含组名的字符串。所以命名组可以通过数字或者名称两种方式来得到一个组的信息。
松散正则表达式:
为了方便阅读和维护,可以使用松散正则表达式,它与普通紧凑的正则表达式有两点不同:
1, 空白符被忽略。空格、制表符(tab)和回车会被忽略。如果需要匹配他们,可以在前面加一个“\”来转义。
2, 注释被忽略。注释以“#”开头直到行尾,与python代码中的一样。
使用松散正则表达式,需要传递一个叫 re.VERBOSE的 参数。详细见下面例子。
例如:
# 必须引入 re 标准库
import re
# 字符串替换: sub() 与 subn()
s = '100 NORTH MAIN ROAD'
# 将字符串结尾的单词“ROAD”替换成“RD.”;该 re.sub() 函数执行基于正则表达式的字符串替换。
print(re.sub(r'\bROAD$', 'RD.', s)) # 打印: 100 NORTH MAIN RD.
## subn() 与 sub() 作用一样,但返回的是包含新字符串和替换执行次数的两元组。
print(re.subn(r'\bROAD$', 'RD.', s)) # 打印: ('100 NORTH MAIN RD.', 1)
# 字符串分割, split()
# 在正则表达式匹配的地方将字符串分片,将返回列表。只支持空白符和固定字符串。可指定最大分割次数,不指定将全部分割。
print(re.split(r'\s+', 'this is a test')) # 打印: ['this', 'is', 'a', 'test']
print(re.split(r'\W+', 'This is a test.', 2)) # 指定分割次数,打印:['this', 'is', 'a test']
# 如果你不仅对定界符之间的文本感兴趣,也需要知道定界符是什么。在 RE 中使用捕获括号,就会同时传回他们的值。
print(re.split(r'(\W+)', 'This is a test.', 2)) # 捕获定界符,打印:['this', ' ', 'is', ' ', 'a test']
## `MatchObject` 实例的几个方法
r = re.search(r'\bR(OA)(D)\b', s)
print(r.groups()) # 返回一个包含字符串的元组,可用下标取元组的内容,打印: ('OA', 'D')
print(r.group()) # 返回正则表达式匹配的字符串,打印: ROAD
print(r.group(2)) # 返回捕获组对应的内容(用数字指明第几个捕获组),打印: D
print(r.start()) # 返回匹配字符串开始的索引, 打印: 15
print(r.end()) # 返回匹配字符串结束的索引,打印: 19
print(r.span()) # 返回一个元组包含匹配字符串 (开始,结束) 的索引,打印: (15, 19)
# 匹配多个内容, findall() 返回一个匹配字符串行表
p = re.compile('\d+')
s0 = '12 drummers drumming, 11 pipers piping, 10 lords a-leaping'
print(p.findall(s0)) # 打印: [12, 11, 10]
print(re.findall(r'\d+', s0)) # 也可这样写,打印: [12, 11, 10]
# 匹配多个内容, finditer() 以迭代器返回
iterator = p.finditer(s0)
# iterator = re.finditer(r'\d+', s0) # 上句也可以这样写
for match in iterator:
print(match.group()) # 三次分别打印:12、 11、 10
# 记忆组
print(re.sub('([^aeiou])y$', 'ies', 'vacancy')) # 将匹配的最后两个字母替换掉,打印: vacanies
print(re.sub('([^aeiou])y$', r'\1ies', 'vacancy')) # 将匹配的最后一个字母替换掉,记忆住前一个(小括号那部分),打印: vacancies
print(re.search('([^aeiou])y$', 'vacancy').group(1)) # 使用 group() 函数获取对应的记忆组内容,打印: c
# 记忆组(匹配重复字符串)
p = re.compile(r'(?P\b\w+)\s+\1') # 注意, re.match() 函数不能这样用,会返回 None
p = p.search('Paris in the the spring')
# p = re.search(r'(?P\b\w+)\s+\1', 'Paris in the the spring') # 这一句可以替换上面两句
print(p.group()) # 返回正则表达式匹配的所有内容,打印: the the
print(p.groups()) # 返回一个包含字符串的元组,打印: ('the',)
# 捕获组
r = re.search(r'\bR(OA)(D)\b', s) # 如过能匹配到,返回一个 SRE_Match 类(正则表达式匹配对象);匹配不到则返回“None”
# `MatchObject` 实例的几个方法
if r: # 如果匹配不到,则 r 为 None,直接执行下面语句则会报错;这里先判断一下,避免这错误
print(r.groups()) # 返回一个包含字符串的元组,可用下标取元组的内容,打印: ('OA', 'D')
print(r.group()) # 返回正则表达式匹配的字符串,打印: ROAD
print(r.group(2)) # 返回捕获组对应的内容(用数字指明第几个捕获组),打印: D
# 无捕获组
print(re.match("([abc])+", "abcdefab").groups()) # 正常捕获的结果: ('c',)
print(re.match("(?:[abc])+", "abcdefab").groups()) # 无捕获组的结果: ()
# 命名组
m = re.match(r'(?P\b\w+\b) *(?P\b\w+\b)', 'Lots of punctuation')
print(m.groups()) # 返回正则表达式匹配的所有内容,打印:('Lots', 'of')
print(m.group(1)) # 通过数字得到对应组的信息,打印: Lots
print(m.group('word2')) # 通过名称得到对应组的信息,打印: of
# 命名组 逆向引用
p = re.compile(r'(?P\b\w+)\s+(?P=word)') # 与记忆组一样用法, re.match() 函数同样不能这样用,会返回 None
p = p.search('Paris in the the spring') # r'(?P\b\w+)\s+(?P=word)' 与 r'(?P\b\w+)\s+\1' 效果一样
print(p.group()) # 返回正则表达式匹配的所有内容,打印: the the
print(p.groups()) # 返回一个包含字符串的元组,打印: ('the',)
# 使用松散正则表达式,以判断罗马数字为例
pattern = '''
^ # beginning of string
(M{0,3}) # thousands - 0 to 3 Ms
(CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
# or 500-800 (D, followed by 0 to 3 Cs)
(XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
# or 50-80 (L, followed by 0 to 3 Xs)
(IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
# or 5-8 (V, followed by 0 to 3 Is)
$ # end of string
'''
print(re.search(pattern, 'M')) # 这个没有申明为松散正则表达式,按普通的来处理了,打印: None
print(re.search(pattern, 'M', re.VERBOSE).groups()) # 打印: ('M', '', '', '')
# (?iLmsux) 用法
# 以下这三句的写法都是一样的效果,表示忽略大小写,打印: ['aa', 'AA']
print(re.findall(r'(?i)(aa)', 'aa kkAAK s'))
print(re.findall(r'(aa)', 'aa kkAAK s', re.I))
print(re.findall(r'(aa)', 'aa kkAAK s', re.IGNORECASE))
# 可以多种模式同时生效
print(re.findall(r'(?im)(aa)', 'aa kkAAK s')) # 直接在正则表达式里面写
print(re.findall(r'(aa)', 'aa kkAAK s', re.I | re.M)) # 在参数里面写
print(re.findall(r'(aa)', 'aa kkAAK s', re.I or re.M))
# 预编译正则表达式解析的写法
# romPattern = re.compile(pattern) # 如果不是松散正则表达式,则这样写,即少写 re.VERBOSE 参数
romPattern = re.compile(pattern, re.VERBOSE)
print(romPattern.search('MCMLXXXIX').groups()) # 打印: ('M', 'CM', 'LXXX', 'IX')
print(romPattern.search('MMMDCCCLXXXVIII').groups()) # 打印: ('MMM', 'DCCC', 'LXXX', 'VIII')
# match()、search()、sub()、findall() 等等都可以这样用
match() vs search()
match() 函数只检查 RE 是否在字符串开始处匹配,而 search() 则是扫描整个字符串。记住这一区别是重要的。
match() 只报告一次成功的匹配,它将从 0 处开始;如果匹配不是从 0 开始的, match() 将不会报告它。
search() 将扫描整个字符串,并报告它找到的第一个匹配。
例:
print(re.match('super', 'superstition').span()) # 打印: (0, 5)
print(re.match('super', 'insuperable')) # 打印: None
print(re.search('super', 'superstition').span()) # 打印: (0, 5)
print(re.search('super', 'insuperable').span()) # 打印: (2, 7)
Python标准库:
os 模块
这个模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。
os.sep 获取操作系统特定的路径分割符。比如在Linux、Unix下它是’/’,在Windows下它是’\’,而在Mac OS下它是’:’。
os.name 字符串指示你正在使用的平台。比如对于Windows,它是’nt’,而对于Linux/Unix用户,它是’posix’。
os.getcwd() 函数得到当前工作目录,即当前Python脚本工作的目录路径。
os.getenv(key) 函数用来读取环境变量。
os.putenv(key, value) 函数用来设置环境变量。
os.listdir(path) 返回指定目录下的所有文件和目录名。
os.remove(filePath) 函数用来删除一个文件。
os.system(shellStr) 函数用来运行shell命令,windows平台则是运行批处理命令。
os.linesep 字符串给出当前平台使用的行终止符。例如,Windows使用’\r\n’,Linux使用’\n’而Mac使用’\r’。
os.path.split(pathname) 函数返回一个路径的目录名和文件名。
os.path.isfile(path) 函数检验给出的路径是否一个文件。
os.path.isdir(path) 函数分别检验给出的路径是否目录。
os.path.existe(path) 函数用来检验给出的路径是否真地存在。
unittest 模块(单元测试)
单元测试的好处:
在编写代码之前,通过编写单元测试来强迫你使用有用的方式细化你的需求。
在编写代码时,单元测试可以使你避免过度编码。当所有测试用例通过时,实现的方法就完成了。
重构代码时,单元测试用例有助于证明新版本的代码跟老版本功能是一致的。
在维护代码期间,可验证代码是否破坏原有代码的状态。
在团队编码中,缜密的测试套件可以降低你的代码影响别人代码的机率,提前发现代码与其他人的不可以良好工作。
单元测试的原则:
完全自动运行,而不需要人工干预。单元测试几乎是全自动的。
自主判断被测试的方法是通过还是失败,而不需要人工解释结果。
独立运行,而不依赖其它测试用例(即使测试的是同样的方法)。即,每一个测试用例都是一个孤岛。
例:
#### roman1.py 文件的内容 ####
# 定义异常类型(这里仅做范例,不执行什么)
class OutOfRangeError(ValueError): pass
class NotIntegerError(ValueError): pass
roman_numeral_map = (('M', 1000),
('CM', 900), ('D', 500), ('CD', 400), ('C', 100),
('XC', 90), ('L', 50), ('XL', 40), ('X', 10),
('IX', 9), ('V', 5), ('IV', 4), ('I', 1))
# 被测试函数
def to_roman(n):
'''convert integer to Roman numeral'''
# 数值范围判断
if not ( 0 < n < 4000 ):
raise OutOfRangeError('number out of range (must be less than 4000)')
# 类型判断, 内建的 isinstance() 方法可以检查变量的类型
# isinstance(n, int) 与 type(n) is int 等效
if not isinstance(n, int):
raise NotIntegerError('non-integers can not be converted')
result = ''
for numeral, integer in roman_numeral_map:
while n >= integer:
result += numeral
n -= integer
return result
#### 测试文件的内容 ####
import roman1 # 导入被测试的类
import unittest
# 需继承 unittest 模块的TestCase 类。TestCase 提供了很多可以用于测试特定条件的有用的方法。
class KnownValues(unittest.TestCase):
def setUp(self):
"""初始化"""
#执行数据库连接,数据初始化等,此函数可不写
pass
# setUp 和 tearDown 在执行每个测试函数的前后都会执行
def tearDown(self):
"""销毁"""
pass
# 每一个独立的测试都有它自己的不含参数及没有返回值的方法。如果方法不抛出异常而正常退出则认为测试通过;否则,测试失败。
# 测试本身是类一个方法,并且该方法以 test 开头命名。如果不是 test 开头,则不会执行。
def test_to_roman_known_values(self):
# 对于每一个测试用例, unittest 模块会打印出测试方法的 docstring ,并且说明该测试失败还是成功。
# 失败时必然打印docstring, 成功时需使用“-v”命令行参数来查看。
'''to_roman 方法传回的值与用例的数据不相等时,则测试不通过'''
# 测试的用例,一般是所有明显的边界用例。
known_values = ( (1, 'I'), (2, 'II'), (3, 'III'), (4, 'IV'),
(5, 'V'), (6, 'VI'), (7, 'VII'), (8, 'VIII'),
(9, 'IX'), (10, 'X'), (50, 'L'), (100, 'C'),
(500, 'D'), (1000, 'M'), (31, 'XXXI'), (148, 'CXLVIII'),
(3888, 'MMMDCCCLXXXVIII'), (3940, 'MMMCMXL'), (3999, 'MMMCMXCIX') )
for integer, numeral in known_values:
result = roman1.to_roman(integer) # 这里调用真实的方法。如果该方法抛出了异常,则测试被视为失败。
self.assertEqual(numeral, result) # 检查两个值是否相等。如果两个值不一致,则抛出异常,并且测试失败。
self.assertNotEqual(0, result, '这两个值不应该相等') # 检查两个值是否不相等。
self.assertTrue(5 > 0, '5 > 0 都出错,不是吧')
self.assertFalse(5 < 0)
# 对于每一个失败的测试用例, unittest 模块会打印出详细的跟踪信息。
# 如果所有返回值均与已知的期望值一致,则 self.assertEqual 不会抛出任何异常,于是此次测试最终会正常退出,这就意味着 to_roman() 通过此次测试。
assert 5 > 0 # 为了更灵活的判断,可使用 assert
# 测试异常,让被测试的方法抛出异常,这里来验证异常类型。如果预期的异常没有抛出,则测试失败。
def test_over_value(self):
'''参数过大或者过小时, to_roman 方法应该抛出异常信息'''
# assertRaises 方法需要以下参数:你期望的异常、你要测试的方法及传入给方法的参数。
#(如果被测试的方法需要多个参数的话,则把所有参数依次传入 assertRaises, 它会正确地把参数传递给被测方法的。)
self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, 4000)
# 注意是把 to_roman() 方法作为参数传递;没有调用被测方法,也不是把被测方法作为一个字符串名字传递进去
self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, 0)
self.assertRaises(roman1.OutOfRangeError, roman1.to_roman, -1)
# 验证参数类型
def test_non_integer(self):
'''如果参数不是 int 类型时, to_roman 方法应该抛出异常'''
self.assertRaises(roman1.NotIntegerError, roman1.to_roman, 0.5)
self.assertRaises(roman1.NotIntegerError, roman1.to_roman, 6.0)
# 在说明每个用例的详细执行结果之后, unittest 打印出一个简述来说明“多少用例被执行了”和“测试执行了多长时间”。
if __name__ == '__main__':
# main 方法会执行每个测试用例
unittest.main()
with 关键字
从Python 2.5开始有,需要 from future import with_statement。自python 2.6开始,成为默认关键字。
with 是一个控制流语句, 跟 if/for/while/try 之类的是一类的,with 可以用来简化 try finally 代码,看起来可以比 try finally 更清晰。
with obj 语句在控制流程进入和离开其后的相关代码中,允许对象obj管理所发生的事情。
执行 with obj 语句时,它执行 obj.enter() 方法来指示正在进入一个新的上下文。当控制流离开该上下文的时候,它就会执行 obj.exit(type, value, traceback)。
"上下文管理协议"context management protocol: 实现方法是为一个类定义 __enter__ 和 __exit__ 两个函数。
with expresion as variable的执行过程是,首先执行 __enter__ 函数,它的返回值会赋给 as 后面的 variable, 想让它返回什么就返回什么,如果不写 as variable,返回值会被忽略。
然后,开始执行 with-block 中的语句,不论成功失败(比如发生异常、错误,设置sys.exit()),在with-block执行完成后,会执行__exit__函数。
这样的过程其实等价于:
try:
执行 __enter__()
执行 with_block.
finally:
执行 __exit__()
只不过,现在把一部分代码封装成了__enter__函数,清理代码封装成__exit__函数。
例:
import sys
class test:
def __enter__(self):
print("enter...")
return 1
def __exit__(self,*args):
print("exit...")
return True
with test() as t:
print("t is not the result of test(), it is __enter__ returned")
print("t is 1, yes, it is {0}".format(t))
raise NameError("Hi there")
sys.exit()
print("Never here")
注意:
1) t不是test()的值,test()返回的是"context manager object",是给with用的。t获得的是__enter__函数的返回值,这是with拿到test()的对象执行之后的结果。t的值是1.
2) __exit__函数的返回值用来指示with-block部分发生的异常是否要 re-raise ,如果返回 False,则会抛出 with-block 的异常,如果返回 True,则就像什么都没发生。
在Python2.5中, file objec t拥有 __enter__ 和 __exit__ 方法,__enter__ 返回 object 自己,而 __exit__ 则关闭这个文件:
要打开一个文件,处理它的内容,并且保证关闭它,你就可以简简单单地这样做:
with open("x.txt") as f:
data = f.read()
do something with data
补充:
数据库的连接好像也可以和with一起使用,我在一本书上看到以下内容:
conn = sqlite.connect("somedb")
with conn:
conn.execute("insert into sometable values (?,?)",("foo","bar"))
在这个例子中,commit()是在所有with数据块中的语句执行完毕并且没有错误之后自动执行的,如果出现任何的异常,将执行rollback()
操作,再次提示异常
范例:
1.运行系统命令行
import os
os_command = ‘echo haha…’
# 运行命令行,返回运行结果(成功时返回0,失败返回1或以上的出错数字)
result = os.system(os_command)
if result == 0:
print(‘run Successful’)
else:
print(‘run FAILED’)
# 注:os.system()函数不推荐使用,它容易引发严重的错误。(可能是因为不具备可移植性)
#os.system(os_command) # 这命令会弹出一个黑乎乎的cmd运行窗口,而且无法获得输出
p = os.popen(os_command) # 捕获运行的屏幕输出,以文件类型接收,不再另外弹出窗口
print(p.read()) # p 是个文件类型,可按文件的操作
2.获取系统时间
import time,datetime
time.sleep(2) # 时间暂停两秒
print(time.strftime(‘%Y-%m-%d %H:%M:%S’)) # 打印如: 2011-04-13 18:30:10
print(time.strftime(‘%Y-%m-%d %A %X’, time.localtime(time.time()))) # 显示当前日期; 打印如: 2011-04-13 Wednesday 18:30:10
print(time.strftime(“%Y-%m-%d %A %X”, time.localtime())) # 显示当前日期; 打印如: 2011-04-13 Wednesday 18:30:10
print(time.time()) # 以浮点数形式返回自Linux新世纪以来经过的秒数; 打印如: 1302687844.7
print(time.ctime(1150269086.6630149)) #time.ctime([sec]) 把秒数转换成日期格式,如果不带参数,则显示当前的时间。打印如: Wed Apr 13 21:13:11 2011
# 得到今天的日期
print(datetime.date.today()) # 打印如: 2011-04-13
# 得到前一天的日期
print(datetime.date.today() + datetime.timedelta(days=-1)) # 打印如: 2011-04-12
print(datetime.date.today() - datetime.timedelta(days=1)) # 打印如: 2011-04-14
# 得到10天后的时间
print(datetime.date.today() + datetime.timedelta(days=10)) # 打印如: 2011-04-23
# 得到10小时后的时间,上面的 days 换成 hours
print(datetime.datetime.now() + datetime.timedelta(hours=10)) # 打印如: 2011-04-14 04:30:10.189000
#两日期相减(也可以大于、小于来比较):
d1 = datetime.datetime(2005, 2, 16)
d2 = datetime.datetime(2004, 12, 31)
print((d1 - d2).days) # 打印: 47
#运行时间:
starttime = datetime.datetime.now()
time.sleep(1) # 暂停1秒
endtime = datetime.datetime.now()
print((endtime - starttime).seconds) # 秒, 打印: 1
print((endtime - starttime).microseconds) # 微秒; 打印: 14000
日期格式化符号:
%%: %号本身
%A: 本地星期(全称),如:Tuesday %a: 本地星期(简称),如:Tue
%B: 本地月份(全称),如:February %b: 本地月份(简称),如:Feb
%c: 本地相应的日期表示和时间表示,如:02/15/11 16:50:57
%d: 月内中的一天(0-31),如:15
%H: 24进制小时数(0-23)
%I: 12进制小时数(01-12)
%j: 年内的一天(001-366),如:046
%M: 分钟(00-59),如:50 %m: 月份(01-12),如:02
%p: 上下午(本地A.M.或P.M.的等价符),如:PM
%S: 秒钟(00-59),如:57
%X: 本地的时间,如:16:50:57 %x: 本地的日期,如:02/15/11
%Y: 四位的年(000-9999) %y: 两位数的年份表示(00-99)
%U: 年里的星期数(00-53)从星期天开始,如:07
%W: 年里的星期数(00-53)从星期一开始,如:07
%w: 星期(0-6),星期天为星期的开始,如:2 (星期天为0)
%Z: 当前时区的名称,如:中国标准时间
%z: 当前时区的名称,如:中国标准时间
3.创建目录
import os
pathDir = r’D:\Work’ # 不同系统的目录写法有所不同
if not os.path.exists(pathDir):
os.mkdir(pathDir) # 创建目录, os.makedirs(pathDir) 创建多个不存在的目录
target = pathDir + os.sep + ‘test.txt’
print(target)
# 注意os.sep变量的用法, os.sep 是目录分隔符,这样写方便移植。即在Linux、Unix下它是’/’,在Windows下它是’\’,而在Mac OS下它是’:’。
4.文件操作(读写txt文件)
filePath = ‘poem.txt’
f = open(filePath, ‘w’) # 以写的模式打开文件,Python 2.x 需将 open() / io.open() 改成 file()
for a in range( 0, 10 ):
s = “%5d %5d\n” % (a, a*a)
f.write( s ) # 把文本写入文件
f.close() # 关闭io流
f2 = open(filePath) # 没有提供模式,则默认是读取,即 'r'
while True:
line = f2.readline()
if len(line) == 0: # 读取结束
break
print(line, end=' ') # 避免print自动换行, 此行Python2.x应该写:“print line,”
f2.close() # close the file
# 删除文件
import os
os.remove(filePath)
说明:
一、在pythony 3.0 已经废弃了 file 类。
二、pythony 3.0 内置 open() 函数的构造函数是:
open(file, mode="r", buffering=None, encoding=None, errors=None, newline=None, closefd=True)
1.mode(模式):
r: 读,只能读文件,如果文件不存在,会发生异常
w: 写,只能写文件,如果文件不存在,创建该文件;如果文件已存在,先清空,再打开文件
a: 打开供追加
b: 二进制模式;一般是组合写法,如: rb 以二进制读方式打开;wb 以二进制写方式打开
t: 文本模式
+: 打开一个磁盘文件供更新,一般是组合使用,如:
rb+: 以二进制读方式打开,可以读、写文件,如果文件不存在,会发生异常
wb+: 以二进制写方式打开,可以读、写文件,如果文件不存在,创建该文件;如果文件已存在,先清空,再打开文件
u: 通用换行模式
默认的模式是 rt,即打开供读取的文本模式。
2.buffering 关键字参数的期望值是以下三个整数中的一个以决定缓冲策略:
0: 关闭缓冲
1: 行缓冲
> 1: 所填的 int 数=缓冲区大小
默认: 完全缓冲
3.encoding 默认的编码方式独立于平台。
4.关闭文件描述符 closefd 可以是 True 或 False 。
如果是 False,此文件描述符会在文件关闭后保留。若文件名无法奏效的话,那么必须设为 True 。
三、清空文件内容
f.truncate()
注意:当以 "r+","rb+","w","wb","wb+"等模式时可以执行该功能,即具有可写模式时才可以。
四、文件的指针定位与查询
(1)文件指针:
文件被打开后,其对象保存在 f 中, 它会记住文件的当前位置,以便于执行读、写操作,
这个位置称为文件的指针( 一个从文件头部开始计算的字节数 long 类型 )。
(2)文件打开时的位置:
以"r","r+","rb+" 读方式, "w","w+","wb+"写方式 打开的文件,
一开始,文件指针均指向文件的头部。
(3)获取文件指针的值:
L = f.tell()
(4)移动文件的指针
f.seek(偏移量, 选项) # 偏移量 是 long 或者 int 类型,计算偏移量时注意换行符是2,汉字可能是2或3
选项 =0 时, 表示将文件指针指向从文件头部到 "偏移量"字节处。
选项 =1 时, 表示将文件指针指向从文件的当前位置,向后移动 "偏移量"字节。
选项 =2 时, 表示将文件指针指向从文件的尾部,,向前移动 "偏移量"字节。
五、从文件读取指内容
1.文本文件(以"rt"方式打开的文件)的读取
s = f.readline()
返回值: s 是字符串,从文件中读取的一行,含行结束符。
说明: (1)如果 len(s) = 0 表示已到文件尾(换行符也是有长度的,长度为2)
(2)如果是文件的最后一行,有可能没有行结束符
2.二进制文件(以"rb"、"rb+"、"wb+" 方式打开的文件)的读取
s = f.read(n)
说明: (1)如果 len( s ) =0 表示已到文件尾
(2)文件读取后,文件的指针向后移动 len(s) 字节。
(3)如果磁道已坏,会发生异常。
六、向文件写入一个字符串
f.write( s )
参数: s 要写入的字符串
说明: (1)文件写入后,文件的指针向后移动 len(s) 字节。
(2)如果磁道已坏,或磁盘已满会发生异常。
七、常用文件操作参考
[1.os]
1.重命名:os.rename(old, new)
2.删除:os.remove(file)
3.列出目录下的文件:os.listdir(path)
4.获取当前工作目录:os.getcwd()
5.改变工作目录:os.chdir(newdir)
6.创建多级目录:os.makedirs(r"c:\python\test")
7.创建单个目录:os.mkdir("test")
8.删除多个目录:os.removedirs(r"c:\python") #删除所给路径最后一个目录下所有空目录。
9.删除单个目录:os.rmdir("test")
10.获取文件属性:os.stat(file)
11.修改文件权限与时间戳:os.chmod(file)
12.执行操作系统命令:os.system("dir")
13.启动新进程:os.exec(), os.execvp()
14.在后台执行程序:osspawnv()
15.终止当前进程:os.exit(), os._exit()
16.分离文件名:os.path.split(r"c:\python\hello.py") --> ("c:\\python", "hello.py")
17.分离扩展名:os.path.splitext(r"c:\python\hello.py") --> ("c:\\python\\hello", ".py")
18.获取路径名:os.path.dirname(r"c:\python\hello.py") --> "c:\\python"
19.获取文件名:os.path.basename(r"r:\python\hello.py") --> "hello.py"
20.判断文件是否存在:os.path.exists(r"c:\python\hello.py") --> True
21.判断是否是绝对路径:os.path.isabs(r".\python\") --> False
22.判断是否是目录:os.path.isdir(r"c:\python") --> True
23.判断是否是文件:os.path.isfile(r"c:\python\hello.py") --> True
24.判断是否是链接文件:os.path.islink(r"c:\python\hello.py") --> False
25.获取文件大小:os.path.getsize(filename)
26.*******:os.ismount("c:\\") --> True
27.搜索目录下的所有文件:os.path.walk()
28.文件的访问时间 : os.path.getatime(myfile) # 这里的时间以秒为单位,并且从1970年1月1日开始算起
29.文件的修改时间: os.path.getmtime(myfile)
[2.shutil]
1.复制单个文件:shultil.copy(oldfile, newfle)
2.复制整个目录树:shultil.copytree(r".\setup", r".\backup")
3.删除整个目录树:shultil.rmtree(r".\backup")
[3.tempfile]
1.创建一个唯一的临时文件:tempfile.mktemp() --> filename
2.打开临时文件:tempfile.TemporaryFile()
[4.StringIO] #cStringIO是StringIO模块的快速实现模块
1.创建内存文件并写入初始数据:f = StringIO.StringIO("Hello world!")
2.读入内存文件数据: print f.read() #或print f.getvalue() --> Hello world!
3.想内存文件写入数据:f.write("Good day!")
4.关闭内存文件:f.close()
[5.glob]
1.匹配文件:glob.glob(r"c:\python\*.py")
5.文件操作(遍历目录和文件名)
import os
import os.path
rootdir = r”D:\Holemar\1.notes\28.Python\test”
# os.walk 返回一个三元组,其中parent表示所在目录, dirnames是所有目录名字的列表, filenames是所有文件名字的列表
for parent,dirnames,filenames in os.walk(rootdir):
# 所在目录
print(“parent is:” + parent)
# 遍历此目录下的所有目录(不包含子目录)
for dirname in dirnames:
print(” dirname is:” + dirname)
# 遍历此目录下的所有文件
for filename in filenames:
print(” filename with full path:” + os.path.join(parent, filename))
# 列表显示出某目录下的所有文件及目录(不包括子目录的内容)
ls = os.listdir(rootdir)
6.文件操作(分割路径和文件名)
import os.path
#常用函数有三种:分隔路径,找出文件名,找出盘符(window系统),找出文件的扩展名。
spath = “d:/test/test.7z”
# 下面三个分割都返回二元组
# 分隔目录和文件名
p,f = os.path.split(spath) # 注意二元组的接收
print("dir is:" + p) # 打印: d:/test
print(" file is:" + f) # 打印: test.7z
# 分隔盘符和文件名
drv,left = os.path.splitdrive(spath)
print(" driver is:" + drv) # 打印: d:
print(" left is:" + left) # 打印: /test/test.7z
# 分隔文件和扩展名
f,ext = os.path.splitext(spath)
print(" f is: " + f) # 打印: d:/test/test
print(" ext is:" + ext) # 打印: 7z
7.储存器
pickle标准模块。它可以在一个文件中储存任何Python对象,之后又可以把它完整无缺地取出来。这被称为 持久地 储存对象。
在pythony 3.0 已经移除了 cPickle 模块,可以使用 pickle 模块代替。
import pickle as p # 这里使用 as 简称,方便更改模块时只需改一行代码
# import cPickle as p # Python 2.x 有这个模块(比pickle快1000倍)
# 将会把资料保存在这个文件里面
shoplistfile = 'shoplist.data'
# 需要保存的资料
shoplist = ['apple', 'mango', 'carrot', 2, 5]
# 写入文件
f = open(shoplistfile, "wb") # 以二进制写入,Python2.x时可不用二进制,但3.x必须
p.dump(shoplist, f) # dump the object to a file
f.close()
# 取出资料
f = open(shoplistfile, "rb") # 以二进制读取
storedlist2 = p.load(f)
print(storedlist2)
f.close()
# 删除文件
import os
os.remove(shoplistfile)
8.url编码操作
import urllib,sys
s = '杭州'
print(urllib.quote(s)) # url 转码,打印如: %E6%9D%AD%E5%B7%9E
print(urllib.unquote('%E6%9D%AD%E5%B7%9E')) # url 解码,打印如: 杭州
# 按所用的编码来转码
print(urllib.quote(s.decode(sys.stdin.encoding).encode('utf8'))) # 打印如: %E6%9D%AD%E5%B7%9E
print(urllib.quote(s.decode(sys.stdin.encoding).encode('gbk'))) # 打印如: %BA%BC%D6%DD
print(urllib.quote(s.decode('gbk').encode('utf8'))) # 指定编码来转码
print(urllib.quote(u'中国'.encode('utf8'))) # unicode编码的,需encode一下;否则中文会出错
# decode就是把其他编码转换为unicode,等同于unicode函数;encode就是把unicode编码的字符串转换为特定编码。
# 一些不希望被编码的url
print urllib.quote("http://localhost/index.html?id=1") # 打印: http%3A//localhost/index.html%3Fid%3D1
print urllib.quote("http://localhost/index.html?id=1",":?=/") # 打印: http://localhost/index.html?id=1
# 查看
print(u'中国'.__class__) # 打印:
print('中国'.__class__) # 打印:
9.数据库连接
cx_Oracle : 是一个用来连接并操作 Oracle 数据库的 Python 扩展模块, 支持包括 Oracle 9.2 10.2 以及 11.1 等版本。
安装:
需先oracle安装客户端,并配置环境变量:
ORACLE_HOME=D:\Oracle\Ora81
PATH=D:\Oracle\Ora81\bin;(其他path的地址)
下载 cx_Oracle 安装包: http://www.python.net/crew/atuining/cx_Oracle/
Oracle 示例:
import cx_Oracle
print(cx_Oracle.version) # 打印出版本信息
# 建立连接, 3种不同写法
conn = cx_Oracle.connect('username/pwssword@localhost:1521/db_name') # 参数连写
conn = cx_Oracle.connect('username', 'pwssword', 'ip_address:1521/db_name') # 分开3个参数写
dsn_tns = cx_Oracle.makedsn('localhost', 1521, 'db_name')
conn = cx_Oracle.connect('username', 'pwssword', dsn_tns) # 分开5个参数写
MySQLdb : MySQL 数据库的 Python 扩展模块
import MySQLdb
下载地址(tar安装包): http://sourceforge.net/projects/mysql-python
(exe安装文件) http://www.lfd.uci.edu/~gohlke/pythonlibs/
mongodb:
下载数据库安装文件: http://www.mongodb.org/downloads
import pymongo
其他数据库:
postgresql PostgreSQL psycopg version 1.x, http://initd.org/projects/psycopg1
postgresql_psycopg2 PostgreSQL psycopg version 2.x, http://initd.org/projects/psycopg2
sqlite3 SQLite No adapter needed if using Python 2.5+ Otherwise, pysqlite, http://initd.org/tracker/pysqlite
ado_mssql Microsoft SQL Server adodbapi version 2.0.1+, http://adodbapi.sourceforge.net/
MySQL 示例:
# 0. 导入模块(如果导入出错,说明安装驱动不成功)
import MySQLdb
# 1. 数据库联结,默认host为本机, port为3306(各数据库的连接写法有所不同)
conn = MySQLdb.connect(host="localhost", port=3306, user="root", passwd="root", db="testdb")
# conn = MySQLdb.Connection(host="localhost", port=3306, user="root", passwd="root", db="testdb") # 与上句一样
# 2. 选择数据库(如果前面还没有选择数据库的话)
conn.select_db('database name')
# 3. 获得cursor
cursor = conn.cursor()
# 4.1 执行SQL,查询和增删改都这样写; 查询返回查询结果的行数,增删改返回影响的行数
cursor.execute("SELECT * FROM tb_member")
# 4.1.1. cursor位置设定及读取结果(仅查询时可这样用)
# cursor.scroll(int, mode) # mode可为相对位置或者绝对位置,分别为relative和absolute。
cursor.scroll(0)
# 4.1.2. Fetch 及 获取结果(每次Fetch,结果集都会下移,下次获取的是剩下的结果集,除非再 cursor.scroll() 移动结果集)
print(cursor.fetchone()) # 获取对应位置的资料,返回一个一维元组,打印如:(1L, 'stu1', 'm')
print(cursor.fetchall()) # 返回结果是个二维元组(所有结果) 打印如:((1L, 'stu1', 'm'), (2L, 'stu2', 'f'))
# 4.2 execute SQL, 返回影响的行数
rows = cursor.execute("delete from tb_member where memid=2")
print(rows) # 返回影响的行数(整数类型), 打印如:1
# 5. 关闭连接
cursor.close()
conn.close()
10.需注意的默认参数
# 默认参数: 如果调用的时候没指定,那它会是函数定义时的引用;
# 因此,默认参数建议使用基本类型;如果不是基本类型,建议写 None,然后在函数里面设默认值
##### 范例1,默认参数如果是 []、{} ,将会影响全局 ########
def t1(a, b = []):
b.append(a)
print('%s %s' % (id(b), b))
t1(1) # 打印: 12523400 [1]
t1(2) # 打印: 12523400 [1, 2]
t1(3, b=[]) # 打印: 12545000 [3]
def t2(a, b = {}):
b[len(b)] = a
print('%s %s' % (id(b), b))
t2(1) # 打印: 12540928 {0: 1}
t2(2) # 打印: 12540928 {0: 1, 1: 2}
t2(3, b={}) # 打印: 11547392 {0: 3}
##### 范例2,如果默认的是其它的函数调用,同样原理,默认值只是函数定义时的引用,后面不再改变 ########
import time
def cc(a,b = time.time()):print('%s %s' % (a,b))
cc(1) # 打印: 1 1306501851.48
cc(1,b=2) # 打印: 1 2
cc(2) # 打印: 2 1306501851.48
##### 范例3,只是为了更好的理解上述所讲 ########
def aa():
print('aa...')
return []
# 只在函数定义时,执行被调用的 aa(), 后面不再执行
def bb(a,b = aa()):
b.append(1)
print('%s %s' % (id(b), b))
bb(1) # 打印: 12542840 [1]
bb(2) # 打印: 12542840 [1, 1]
################################################
# 范例4, 为避免上面的出错,正确的写法是这样的:
def t1(a, b = None):
b = b or []
b.append(a)
print('%s %s' % (id(b), b))
def t2(a, b = None):
b = b or {}
b[len(b)] = a
print('%s %s' % (id(b), b))
import time
def cc(a, b = None):
b = b or time.time()
print('%s %s' % (a,b))
随机数
from random import randint # 产生随机整数
for i in xrange(100):
print( randint(10, 90) ) # 产生 10~90 的随机整数
条件参数列表
在实际开发中,我们会遇到如下一种需求:
def test(**on):
# 全部条件列表
accept_args = (“a”, “b”, “c”, “d”, “e”)
# 默认条件
default = on.pop("all", None)
# 如果没有显式指明默认条件,则检查参数列:
# 1. 如果有任何一个 True 条件则默认值为 False。
# 2. 如果全部为 False,则默认值为 True。
if default is None: default = not(True in on.values())
# 使用 setdefault 补全参数字典
for k in accept_args: on.setdefault(k, default)
return on
print test(b = False, e = False) # 显示:{‘a’: True, ‘c’: True, ‘b’: False, ‘e’: False, ‘d’: True}
print test(c = True) # 显示:{‘a’: False, ‘c’: True, ‘b’: False, ‘e’: False, ‘d’: False}
print test(a = True, e = False) # 显示:{‘a’: True, ‘c’: False, ‘b’: False, ‘e’: False, ‘d’: False}
print test(all = True, c = False, e = True) # 显示:{‘a’: True, ‘c’: False, ‘b’: True, ‘e’: True, ‘d’: True}
print test(all = True, c = False, e = False) # 显示:{‘a’: True, ‘c’: False, ‘b’: True, ‘e’: False, ‘d’: True}
print test(all = False, c = True, e = True) # 显示:{‘a’: False, ‘c’: True, ‘b’: False, ‘e’: True, ‘d’: False}
断点调试
import pdb; pdb.set_trace() # 运行到这语句,会出现断点
输入命令:
命令的详细帮助: h
查看代码上下文, l(小写L)
监视变量: p 变量名
单步执行: n
加入断点: b 行号
跳出断点: c
执行到函数返回前: r
修改注册表(使用 _winreg, python3.x是 winreg 模块, 内置模块)
官方的参考文档:
http://docs.python.org/library/_winreg.html
http://www.python.org/doc/2.6.2/library/_winreg.html
读取
读取用的方法是OpenKey方法:打开特定的key
hkey = _winreg.OpenKey(key,sub_key,res=0,sam=KEY_READ)
_winreg.CloseKey(hkey) # 关闭之前打开的,如果不关闭则在对象被销毁时关闭
例子:
import _winreg
key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r”SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces{0E184877-D910-4877-B 4C2-04F487B6DBB7}”)
try:
i=0
while 1:
# EnumValue方法用来枚举键值,EnumKey用来枚举子键
print _winreg.EnumValue(key,i) # 打印: (name,value,type)
i+=1
except WindowsError:
print
print _winreg.QueryValueEx(key,”ExplorerStartupTraceRecorded”) # 打印: (value,type)
创建 修改注册表
创建key:_winreg.CreateKey(key,sub_key)
创建key:_winreg.CreateKeyEx(key, sub_key[, res[, sam]])
删除key: _winreg.DeleteKey(key,sub_key)
删除键值: _winreg.DeleteValue(key,value)
给新建的key赋值: _winreg.SetValue(key,sub_key,type,value)
例子:
import _winreg
key=_winreg.OpenKey(_winreg.HKEY_CURRENT_USER,r”Software\Microsoft\Windows\CurrentVersion\Explorer”)
_winreg.DeleteKey(key, “Advanced”)
_winreg.DeleteValue(key, “IconUnderline”)
newKey = _winreg.CreateKey(key,”MyNewkey”)
_winreg.SetValue(newKey,”ValueName”, _winreg.REG_SZ, “ValueContent”)
访问远程注册表
key = _winreg.ConnectRegisty(“IP地址或者机器名”, _winreg.HKEY_CURRENT_USER)
实例: 修改IE代理服务器
import _winreg # python3 则写 winreg
import ctypes
#proxy = "127.0.0.1:8000"
proxy = "http=127.0.0.1:8580;https=127.0.0.1:8580;ftp=127.0.0.1:8580" # 代理服务器地址
ProxyOverride = ';192.168.*;127.*' # 不使用代理服务器的IP段,或者域名段,可以用*代表任意长字符串,如: 192.168.*
root = _winreg.HKEY_CURRENT_USER
proxy_path = r"Software\Microsoft\Windows\CurrentVersion\Internet Settings"
hKey = _winreg.OpenKey(root, proxy_path)
# value 是代理是否开启的标志,0表示不使用代理,1表示使用
value, type = _winreg.QueryValueEx(hKey, "ProxyEnable")
if value: # value 为 0 时
print("原本已使用代理")
else:
print("原本还没使用代理")
# 修改代理设置
hKey = _winreg.CreateKey(root, proxy_path)
_winreg.SetValueEx(hKey, "ProxyEnable", 0, _winreg.REG_DWORD, 0) # 最后的参数是代理的开关,0为关闭代理,1为开启
_winreg.SetValueEx(hKey, "ProxyServer", 0, _winreg.REG_SZ, proxy)
# 不使用代理服务器的IP段,或者域名段,可以用*代表任意长字符串
_winreg.SetValueEx(hKey, "ProxyOverride", 0, _winreg.REG_SZ, ProxyOverride)
_winreg.SetValueEx(hKey, "MigrateProxy", 0, _winreg.REG_DWORD, 1) # 是否所有协议使用相同代理服务器: 0为否,1为是
# 最后,关闭注册表连接
_winreg.CloseKey(hKey)
# IE Reload注册表的信息, 因为修改注册表之后, ie不会马上生效, 需要这一段; 但在win7系统似乎有点问题
INTERNET_OPTION_REFRESH = 37
INTERNET_OPTION_SETTINGS_CHANGED = 39
internet_set_option = ctypes.windll.Wininet.InternetSetOptionW
internet_set_option(0, INTERNET_OPTION_REFRESH, 0, 0)
internet_set_option(0, INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)
修改注册表(使用 win32api, win32con 模块,需安装)
下载和安装模块: http://starship.python.net/crew/mhammond/downloads/
下载像“pywin32-212.6.win32-py2.6.exe”来安装
注册表基本项
项名 描述
HKEY_CLASSES_ROOT 是HKEY_LOCAL_MACHINE\Software 的子项,保存打开文件所对应的应用程序信息
HKEY_CURRENT_USER 是HKEY_USERS的子项,保存当前用户的配置信息
HKEY_LOCAL_MACHINE 保存计算机的配置信息,针对所有用户
HKEY_USERS 保存计算机上的所有以活动方式加载的用户配置文件
HKEY_CURRENT_CONFIG 保存计算机的硬件配置文件信息
打开注册表
win32api.RegOpenKey(key, subkey, reserved, sam)
win32api.RegOpenKeyEx(key, subkey, reserved, sam)
两个函数的参数用法一样。参数含义如下:
Key:必须为表1中列出的项。
SubKey:要打开的子项。
Reserved:必须为0。
Sam:对打开的子项进行的操作,包括 win32con.KEY_ALL_ACCESS、 win32con.KEY_READ、 win32con.KEY_WRITE 等
关闭注册表
win32api.RegCloseKey(key)
其参数只有一个,其含义如下:
Key:已经打开的注册表项的句柄。
如:
key = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, ‘Software’, 0, win32con.KEY_READ)
print key # 显示:
all
这是一个字符串列表,定义在一个模块出口时使用 from import * 将可以引用到什么变量,但对 import 没有影响。
没有定义此语句,则 import * 默认的行为是导入所有的符号不以下划线开始的对象。
例如:
a1.py 的内容如下:
__all__=['b','c']
a='aaa'
b='bbb'
c='ccc'
b1.py 的内容如下:
import a1
from a1 import *
print a1.a # 正常打印
print b # 正常打印
print a # 报错了,变量未定义
call
类的调用
只要定义类的时候,实现 call 函数,这个类型就成为可调用的。
换句话说,我们可以把这个类型的对象当作函数来使用,相当于 重载了括号运算符。
del
del 类名 # 调用对象的 del 方法
doc
docstring
例:
print(Person.__doc__) # 打印类的docstring
print(Person.func_name.__doc__) # 打印类的方法的docstring
file
当前代码所在的Python模块的文件名。
例:
import os, sys
print( os.path.dirname(os.path.realpath(__file__)) ) # 获取当前目录
print( os.path.dirname(os.path.dirname(os.path.realpath(__file__))) ) # 获取上一层目录
print( os.path.dirname(os.path.abspath(sys.argv[0])) ) # 获取当前目录, sys.argv[0] 与 __file__ 一样显示当前文件名
print( os.getcwd() ) # 获取当前目录
print( os.path.abspath(os.curdir) ) # 获取当前目录
print( os.path.abspath( '. ') ) # 获取当前目录, 打印会加上点号,如: /home/holemar/project/ppf_web/.
init
类的构造方法
例:
class Human(object):
def __init__(self, name):
print(name)
class Person(Human): # Person 类继承 Human 类
def __init__(self, name):
self.name = name # 对象的变量,每个对象独立的
super(Person, self).__init__(name) # 调用父类的 __init__ 方法,但这样的调用要求父类必须继承 object 类,或者继承其它的类
Human.__init__(self, "province") # 这样调用父类的 __init__ 方法也可以
name
每个Python模块都有它的name,如果它是’main‘,这说明这个模块被用户单独运行,我们可以进行相应的恰当操作。
例:
if __name__ == '__main__':
print('This program is being run by itself')
else:
print('I am being imported from another module')
version
版本信息
例如:
__version__ = '2.6.26'
print( tuple(int(i) for i in __version__.split('.')) ) # 打印: (2, 6, 26)
print( float(__version__) ) # 报错
运算符,如大于、小于、等于、加减乘除, 等等
class Field(object):
def init(self, value):
self.value = value
# 小于: x < y, y > x
def __lt__(self, value):
print('__lt__ 被调用啦...')
return self.value < value
# 小于等于: x <= y, y >= x
def __le__(self, value):
return self.value <= value
# x > y, y < x
def __gt__(self, value):
return self.value > value
# x >= y, y <= x
def __ge__(self, value):
return self.value >= value
# 等于: x == y
def __eq__(self, value):
return self.value == value
# 不等于: x != y, x <> y
def __ne__(self, value):
return self.value != value
# 加: x + y
def __add__(self, value):
return str(self.value) + ' + ' + str(value)
# y + x
def __radd__(self, value):
return str(value) + ' + ' + str(self.value)
# 减: x - y
def __sub__(self, value):
return str(self.value) + ' - ' + str(value)
# y - x
def __rsub__(self, value):
return str(value) + ' - ' + str(self.value)
# 乘: x * y
def __mul__(self, value):
return str(self.value) + ' × ' + str(value)
# y * x
def __rmul__(self, value):
return str(value) + ' × ' + str(self.value)
# 除: x / y
def __div__(self, value):
return str(self.value) + ' ÷ ' + str(value)
# y / x
def __rdiv__(self, value):
return str(value) + ' ÷ ' + str(self.value)
# 整除: x // y
def __floordiv__(self, value):
return str(self.value) + ' // ' + str(value)
# y // x
def __rfloordiv__(self, value):
return str(value) + ' // ' + str(self.value)
# python2里面不知道怎么调用这个函数,但python3没有了 __div__,除的时候直接调用此函数
def __truediv__(self, value):
return str(self.value) + ' / ' + str(value)
def __rtruediv__(self, value):
return str(value) + ' / ' + str(self.value)
# 单元运算符
# ~x
def __invert__(self):
return '~' + str(self.value)
# -x
def __neg__(self):
return '-' + str(self.value)
# +x
def __pos__(self):
return '+' + str(self.value)
# x[y]
def __getitem__(self, value):
return 'this[' + str(value) + ']'
# x[y] = z
def __setitem__(self, key, value)
self[key] = value
# del x[y]
def __delitem__(self, value):
del self[value]
# x[y:z]
def __index__(self, y, z):
return self[y:z]
# 遍历
def __iter__(self):
pass
# y in x
def __contains__(self, value): # in 判断,只能返回 True / False
return False
# x.name
#def __getattribute__(self, value): # 覆盖此方法后,调用 self.value 会引起死循环
# return 'this.' + str(value)
# 被特定函数调用时
# len(x) ,返回值必须大于或等于0
def __len__(self):
return 1
# str(x) ,返回值必须是字符串
def __str__(self):
return str(self.value)
# unicode(x)
def __unicode__(self):
return unicode(self.value)
# abs(x)
def __abs__(self):
return abs(self.value)
# hash(x)
def __hash__(self):
return hash(self.value)
# hex(x)
def __hex__(self):
return hex(self.value)
# int(x)
def __int__(self):
return int(self.value)
# long(x)
def __long__(self):
return long(self.value)
# float(x)
def __float__(self):
return float(self.value)
# oct(x)
def __oct__(self):
return oct(self.value)
# cmp(x, y)
def __cmp__(self, value):
return cmp(self.value, value)
# coerce(x, y)
def __coerce__(self, value):
return coerce(self.value, value)
# divmod(x, y)
def __divmod__(self, value):
return divmod(self.value, value)
# divmod(y, x)
def __rdivmod__(self, value):
return divmod(self.value, value)
# pow(x, y[, z])
def __pow__(self, value):
return pow(self.value, value[, z])
# pow(y, x[, z])
def __rpow__(self, value):
return pow(self.value, value[, z])
# repr(x])
def __repr__(self, value):
return repr(self.value)
# size of S in memory, in bytes
def __sizeof__(self, value):
return 1
a = Field(32)
print(a < 12) # 调用 a 的 __lt__
print(12 > a) # 调用 a 的 __lt__
print(a >= 17)
print(a != 15)
print(a == 32)
print(a + 8) # 调用 a 的 __add__
print(8 + a) # 调用 a 的 __radd__
print(a * 8) # 调用 a 的 __mul__
print(8 * a) # 调用 a 的 __rmul__
print(a / 8) # python2时, 调用 a 的 __div__; python3时调用 __truediv__
print(~a)
print(-a)
print(+a)
#print(a.name2)
print(a['name3'])
print('name' in a)
print(len(a)) # 调用 a 的 __len__
print(str(a)) # 调用 a 的 __str__
运算符表:
二元运算符 特殊方法
+ __add__,__radd__
- __sub__,__rsub__
* __mul__,__rmul__
/ __div__,__rdiv__,__truediv__,__rtruediv__
// __floordiv__,__rfloordiv__
% __mod__,__rmod__
** __pow__,__rpow__
<< _lshift__,__rlshift__
>> __rshift__,__rrshift__
& __and__,__rand__
^ __xor__,__rxor__
| __or__,__ror__
+= __iaddr__
-= __isub__
*= __imul__
/= __idiv__,__itruediv__
//= __ifloordiv__
%= __imod__
**= __ipow__
<<= __ilshift__
>>= __irshift__
&= __iand__
^= __ixor__
|= __ior__
== __eq__
!=,<> __ne__
> __gt__
< __lt__
>= __ge__
<= __le__
import(name[, globals[, locals[, fromlist[, level]]]])
被 import 语句调用的函数。它的存在主要是为了你可以用另外一个有兼容接口的函数 来改变 import 语句的语义.
abs(x)
返回一个数的绝对值。参数也许是一个普通或长整型,或者一个浮点数。如果参数是一个复数,返回它的模。
all(iterable)
如果迭代的所有元素都是真就返回真。版本2.5中新增.
any(iterable)
如果迭代中有一个元素为真就返回真。版本2.5中新增.
basestring()
这个抽象类型是str和unicode的父类。它不能被调用或初始化,但是它可以使用来测试一个对象是否是str或unicode的实例。 isinstance(obj, basestring)等价于 isinstance(obj, (str, unicode)) 版本2.3中新增.
bool([x])
将一个值转换为 Boolean,使用标准的真测试程序。如果x是假或忽略了,将返回 False;否则将返回 True.bool也是一个 class,它是 int 的一个子类,bool类不能进一步子类化。它仅有 False 和 True 两个实例。
callable(object)
如果 object 参数是可以调用的函数或者类就返回 True,否则返回 False 。返回 True,仍可能调用失败,但返回 False,就不可能调用成功。
可调用对象包括函数、方法、代码对象、类和已经定义了“ call()”方法的类实例。
如: a=”123”; callable(a) 返回0; callable(chr) 返回1
chr(i)
返回一个ascii码是整数i的字符的字符串。例如: chr(97)返回’a’.这和 ord()刚好相反。这参数在[0..255]之间,全部包含。如果超出这个范围,就抛出 ValueError
classmethod(function)
返回函数的一个类方法。一个类方法接收类作为它的第一个潜在参数,就像一个实例方法接收一个实例。
类方法不同于C++或Java的静态方法。如果你想这样做,使用 staticmethod()。
cmp(x, y)
根据比较两介对象x和y的结果,返回一个整数。如果x