注:本笔记基于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里读取执行代码。
版本问题
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.缩进规则
一个模块的界限,完全是由每行的首字符在这一行的位置来决定的(而不是花括号{})。这一点曾经引起过争议。
不过不可否认的是,通过强制程序员们缩进,Python确实使得程序更加清晰和美观。
在逻辑行首的空白(空格和tab)用来决定逻辑行的缩进层次,从而用来决定语句的分组。错误的缩进会引发错误。
注意: 强制缩进的问题,最常见的情况是tab符和空格的混用会导致错误,而这是用肉眼无法分别的。
2.变量没有类型
使用变量时只需要给它们赋值。 不需要声明或定义数据类型。
3.单语句块
如果你的语句块只包含一句语句,那么你可以在条件语句或循环语句的同一行指明它。如: if 1!=2: print(‘Yes’)
强烈建议不要使用这种缩略方法。这会破坏Python清晰美观的代码风格,违背设计者的初衷。
如果是在Python解释器输入,它的把提示符会改变为…以表示语句还没有结束。这时按回车键用来确认语句已经完整了。然后,Python完成整个语句的执行,并且返回原来的提示符来等待下一句输入。
对象
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
控制台输入
使用 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))
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。
自动化工具也可以以同样的方式从你的程序中提取文档。因此强烈建议你对你所写的任何正式函数编写文档字符串。
模块:
如果要在其他程序中重用很多函数,那么你该使用模块。
模块基本上就是一个包含了所有你定义的函数和变量的文件。
为了在其他程序中重用模块,模块的文件名必须以.py为扩展名。
字节编译的.pyc文件
输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。
一种方法是创建 字节编译的文件,这些文件以.pyc作为扩展名。另外,这些字节编译的文件也是与平台无关的。
当你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。
模块的 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 变量。
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']
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()
操作,再次提示异常
运算符与表达式:
运算符
运算符 名称 说明
+ 加 两个对象相加,也可以字符串拼接
- 减 得到负数或是一个数减去另一个数
* 乘 两个数相乘 或是返回一个被重复若干次的字符串
** 幂 返回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)。
字符串
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.字符串序列(索引和切片)
字符串可以使用下标来获取字符串中某个项目,以及截取字符串。
#字符串的序列,即“索引”和“切片”,参考“1.3.列表、元组和字典.py.txt”的“序列”
用法如: 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里不再存在了。)
12.字符串的乘法运算
“*”:可以把字符串重复拼接若干次,如: 2 * 3得到6; ‘la’ * 3得到’lalala’。但乘以0或者负数时,结果将会是空字符串""。
另外:
没有专门的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 函数
下面所有范例,使用 s = ‘python String function’
1.字符串长度获取: len(str)
例: print ‘%s length=%d’ % (s,len(s)) # 打印: python String function length=22
2.字母处理
全部大写: str.upper()
全部小写: str.lower()
大小写互换: str.swapcase()
首字母大写,其余小写: str.capitalize()
首字母大写(每个词都这样): str.title()
print ‘%s lower=%s’ % (s,s.lower()) # 打印: python String function lower=python string function
print ‘%s upper=%s’ % (s,s.upper()) # 打印: python String function upper=PYTHON STRING FUNCTION
print ‘%s swapcase=%s’ % (s,s.swapcase()) # 打印: python String function swapcase=PYTHON sTRING FUNCTION
print ‘%s capitalize=%s’ % (s,s.capitalize()) # 打印: python String function capitalize=Python string function
print ‘%s title=%s’ % (s,s.title()) # 打印: python String function title=Python String Function
import string; print string.capitalize(s) # 打印: Python string function
3.格式化相关
获取固定长度,右对齐,左边不够用空格补齐: str.ljust(width)
获取固定长度,左对齐,右边不够用空格补齐: str.ljust(width)
获取固定长度,中间对齐,两边不够用空格补齐: str.ljust(width)
获取固定长度,右对齐,左边不足用0补齐
print ‘%s ljust=%s’ % (s,s.ljust(40)) # 打印: "python String function ljust=python String function "
print ‘%s rjust=%s’ % (s,s.rjust(40)) # 打印: “python String function rjust= python String function”
print ‘%s center=%s’ % (s,s.center(40)) # 打印: "python String function center= python String function "
print ‘%s zfill=%s’ % (s,s.zfill(40)) # 打印: “python String function zfill=000000000000000000python String function”
import string; print string.zfill(s, 40) # 打印: 000000000000000000python String function
4.字符串搜索相关
搜索指定字符串,没有返回-1: str.find(‘t’)
指定起始位置搜索: str.find(‘t’,start)
指定起始及结束位置搜索: str.find(‘t’,start,end)
从右边开始查找: str.rfind(‘t’)
搜索到多少个指定字符串: str.count(‘t’)
上面所有方法都可用index代替,不同的是使用index查找不到会抛异常,而find返回-1
print ‘%s find nono=%d’ % (s,s.find(‘nono’)) # 打印: python String function find nono=-1
print ‘%s find t=%d’ % (s,s.find(‘t’)) # 打印: python String function find t=2
print ‘%s find t from %d=%d’ % (s,3,s.find(‘t’,3)) # 打印: python String function find t from 3=8
print ‘%s find t from %d to %d=%d’ % (s,1,2,s.find(‘t’,1,2)) # 打印: python String function find t from 1 to 2=-1
#print '%s index nono ’ % (s,s.index(‘nono’,1,2))
print ‘%s rfind t=%d’ % (s,s.rfind(‘t’)) # 打印: python String function rfind t=18
print ‘%s count t=%d’ % (s,s.count(‘t’)) # 打印: python String function count t=3
import string; print string.find(s, ‘t’) # 打印: 2
5.字符串替换相关
替换old为new: str.replace(‘old’,‘new’)
替换指定次数的old为new: str.replace(‘old’,‘new’,maxReplaceTimes)
另一种写法: import string; string.replace(str,“old”,“new”)
print ‘%s replace t to =%s’ % (s,s.replace(‘t’, '’)) # 打印: python String function replace t to =pyhon Sring funcion
print ‘%s replace t to =%s’ % (s,s.replace(‘t’, '’,1)) # 打印: python String function replace t to * once=pyhon String function
import string; print '%s replace t to =%s’ % (s, string.replace(s,“t”,"")) # 打印: python String function replace t to =pyhon Sring func*ion
6.字符串去空格及去指定字符
去两边空格: str.strip()
去左空格: str.lstrip()
去右空格: str.rstrip()
去两边字符串: str.strip(‘d’),相应的也有lstrip,rstrip
s=’ python String function ’
print ‘%s strip=%s’ % (s,s.strip())
s=‘python String function’
print ‘%s strip=%s’ % (s,s.strip(‘d’))
按指定字符分割字符串为数组: str.split(’ ‘)
split(string,sep=None,maxsplit=-1)
默认按空格分隔
s=‘a b c de’
print ‘%s strip=%s’ % (s,s.split())
s=‘a-b-c-de’
print ‘%s strip=%s’ % (s,s.split(’-’))
import string; ip=“192.168.3.3”; print(string.split(ip,’.’)) # 打印: [‘192’, ‘168’, ‘3’, ‘3’]
字符串判断相关
是否以start开头: str.startswith(‘start’)
是否以end结尾: str.endswith(‘end’)
是否全为字母或数字: str.isalnum()
是否全字母: str.isalpha()
是否全数字: str.isdigit()
是否全小写: str.islower()
是否全大写: str.isupper()
s=‘python String function’
print ‘%s startwith t=%s’ % (s,s.startswith(‘t’))
print ‘%s endwith d=%s’ % (s,s.endswith(‘d’))
print ‘%s isalnum=%s’ % (s,s.isalnum())
s=‘pythonStringfunction’
print ‘%s isalnum=%s’ % (s,s.isalnum())
print ‘%s isalpha=%s’ % (s,s.isalpha())
print ‘%s isupper=%s’ % (s,s.isupper())
print ‘%s islower=%s’ % (s,s.islower())
print ‘%s isdigit=%s’ % (s,s.isdigit())
s=‘3423’
print ‘%s isdigit=%s’ % (s,s.isdigit())
数据结构
可以处理一些 数据 的 结构 。或者说,它们是用来存储一组相关数据的。
在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']
# 序列[index]
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 即倒数第二个
# 序列[start:stop]
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”效果一样,即是复制这个列表
# string[start:stop] (string 与 list, tuple 有同样的操作)
name = 'swaroop'
print('characters 1 to 3 is %s' % name[1:3]) # 打印:wa
print('characters start to 3 is %s' % name[:3]) # 打印:swa 前面空着,表示从下标0开始
print('characters 2 to end is %s' % name[2:]) # 打印:aroop 后面空着,表示直到结束
print('characters 1 to -1 is %s' % name[1:-1]) # 打印:waroo 负数表示倒数第几个
print('characters -2 to end is %s' % name[-2:]) # 打印:op 后面空着,表示直到结束,负数表示倒数第几个
print('characters start to end is %s' % name[:]) # 打印:swaroop 跟直接写这个字符串一样,即是复制这个字符串
# string[start:stop:step] (string 与 list, tuple 有同样的操作)
s = 'ABCDEFG'
print(s[1:7:2]) # 'BDF' step表示隔多少个,默认值是1
print(s[7:1:-1]) # 'GFEDC' 当 step 为负数,表示反序。
print(s[::-1]) # 'GFEDCBA' 反序复制这个字符串
参考(引用)
当你创建一个对象并给它赋一个变量的时候,这个变量仅仅 参考 那个对象,而不是表示这个对象本身!
也就是说,变量名指向你计算机中存储那个对象的内存。
这被称作名称到对象的绑定。
例:
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}
定义函数
函数通过 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, 值被改变了
# 错误示例
# 局部函数里要改变全局变量,将会报错:UnboundLocalError: local variable 'CONSTANT' referenced before assignment
CONSTANT = 0
def modifyConstant():
CONSTANT += 1 # 函数内部可以直接访问全局变量,但直接改变则会报错
print CONSTANT
modifyConstant()
# 上面示例 的正确写法
CONSTANT = 0
def modifyConstant():
global CONSTANT # 使用 global, 则函数内部可以直接改变全局变量了
CONSTANT += 1
print CONSTANT
modifyConstant()
默认参数值
如果希望一些参数是 可选 的,这些参数可使用默认值。
可以在函数定义的形参名后加上赋值运算符(=)和默认值,从而给形参指定默认参数值。
注意,默认参数值应该是一个参数。
例:
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
函数属性 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__ # 一个代码对象,表示编译后的函数体。
需注意的函数默认参数
默认参数: 如果调用的时候没指定,那它会是函数定义时的引用;(只在加载时定义一次,以后都是调用同一个默认参数)
因此,默认参数建议使用基本类型;如果不是基本类型,建议写 None,然后在函数里面设默认值
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}
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
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]
################################################
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))
条件参数列表
在实际开发中,我们会遇到如下一种需求:
1. 默认条件有 (a, b, c, d …),总之很多。
2. 调用者可以传递 (b = False, c = False) 来提供 “非” 条件,其他默认为 True。
3. 或者传递 (b = True, c = True),其他默认为 False。
4. 还可以用 (all = True, …) 来明确指定默认值。
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}
使用 * 和 ** 来传递参数
Python 2.x 提供了另个方法来做相同的事. 你只需要使用一个传统的函数调用 , 使用 * 来标记元组, ** 来标记字典.
下面两个语句是等价的:
result = function(*args, **kwargs)
result = apply(function, args, kwargs)
Decorator(装饰器)
@符号修饰函数(有的语言称为:注释)
python 2.4以后,增加了 @符号修饰函数 对函数进行修饰, python3.0/2.6又增加了对类的修饰。
修饰符必须出现在函数定义前一行,不允许和函数定义在同一行。也就是说 @A def f(): 是非法的。
简单的来说就是用一个新的对象来替换掉原有的对象,新的对象包含原有的对象,并且会处理它的执行结果和输入参数。
python另外一个很有意思的属性:可以在函数中定义函数。
其实总体说起来,装饰器其实也就是一个函数,一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。
官方的说明:
http://www.python.org/dev/peps/pep-0318/
代码上解释 Decorator(装饰器) 就是这样:
@decomaker
def func(arg1, arg2, …):
pass
# 上面相当于这样写:
result = decomaker(func)(arg1, arg2, ...)
范例(普通函数的用法,查看函数运行时间):
import time
def timeit(func):
def wrapper():
start = time.clock()
func()
end =time.clock()
print( ‘used:’ + str(end - start) )
return wrapper
@timeit # 相当于: timeit(foo)()
def foo():
print( 'in foo()' )
# 调用被修饰过的函数,跟普通函数没啥区别
foo() # 打印: in foo()
# 下面用一个不写“@”装饰的函数测试调用方法
def foo2():
print( 'in foo2()' )
# 不被装饰的函数,真实的修饰这样写:
timeit(foo2)() # 打印: in foo2()
范例(多个修饰函数,原函数带参数):
def bold(fn):
def wrapped(arg):
return “” + fn(arg) + “”
return wrapped
def italic(fn):
def wrapped(arg):
return "" + fn(arg) + ""
return wrapped
@bold # 相当于: bold(italic(hello))(arg)
@italic # 相当于: italic(hello)(arg)
def hello(s):
return "hello " + s
# 调用被修饰过的函数,跟普通函数没啥区别
print( hello('holemar') ) # 打印: hello holemar
# 下面用一个不写“@”装饰的函数测试调用方法
def hello2(s):
return "hello " + s
# 不被装饰的函数,真实的修饰这样写:
print( italic(hello2)('world') ) # 打印: hello world
print( bold(hello2)('world') ) # 打印: hello world
print( bold(italic(hello2))('world') ) # 打印: hello world
范例(装饰器带参数的用法,通用的处理输入和输出结果,这写法仅适用于py2.x):
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), “arg %r does not match %s” % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
def returns(rtype):
def check_returns(f):
def new_f(*args, **kwds):
result = f(*args, **kwds)
assert isinstance(result, rtype), "return value %r does not match %s" % (result,rtype)
return result
new_f.func_name = f.func_name
return new_f
return check_returns
# 注意这两个装饰器的顺序,如果倒过来会出错,因为 @accepts 先过滤了 func 函数,而 @returns 又过滤 @accepts 函数的结果
@returns((int,float)) # 相当于: returns((int,float)) (accepts(int, (int,float))(func2)) (arg1, arg2)
@accepts(int, (int,float)) # 相当于: accepts(int, (int,float)) (func2) (arg1, arg2)
def func(arg1, arg2):
return arg1 * arg2
# 测试一下运行结果
print( func(2, 3) )
# 下面用一个不写“@”装饰的函数测试调用方法
def func2(arg1, arg2):
return arg1 * arg2
# 下面的调用,要注意理解各个圆括号, 尤其最后一行嵌套的写法
print( returns((int,float))(func2)(2, 5) )
print( accepts(int, (int,float))(func2)(2, 5) )
print( returns((int,float)) (accepts(int, (int,float))(func2)) (2, 5) )
内置的装饰器
有三个,分别是 staticmethod, classmethod 和 property
作用分别是把类中定义的实例方法变成静态方法、类方法和类属性。
由于模块里可以定义函数,所以静态方法和类方法的用处并不是太多,除非你想要完全的面向对象编程。
而属性也不是不可或缺的,Java没有属性也一样活得很滋润。使用频率较少,了解即可。
staticmethod 和 classmethod 的用法与区别:
对于 classmethod 的参数, 需要隐式地传递类名, 而 staticmethod 参数中则不需要传递类名, 其实这就是二者最大的区别。
对于 staticmethod 就是为了要在类中定义而设置的,一般来说很少这样使用,可以使用模块级(module-level)的函数来替代它。既然要把它定义在类中,想必有作者的考虑。
对于 classmethod, 可以通过子类来进行重定义。
范例(staticmethod 和 classmethod 的用法与区别):
class Person:
def sayHi(self): # self参数必须写,正常函数的写法
print(‘Hello, how are you?’)
@staticmethod # 申明此方法是一个静态方法,外部可以直接调用
def tt(a): # 静态方法,第一个参数不需要用 self
print(a) # 第一个参数就是传过来的参数
def ff(self):
self.sayHi() # 正常方法的调用
self.tt('dd') # 静态方法的调用
@classmethod # 申明此方法是一个类方法
def class_method(class_name, arg1):
c = class_name()
c.sayHi() # 正常类方法的调用,用之前需要new这个类
class_name.tt('cc') # 静态方法的调用
print(arg1) # 第一个参数是类名,第二个参数开始才是传过来的参数
p = Person()
p.ff() # 正常方法的调用: self参数不需赋值, 必须先 new 出一个类才可以用
Person.tt('tt') # 可以直接调用
p.tt('tt') # 使用实例调用也行
Person.class_method('cm') # 也可以直接调用
范例(利用 classmethod 实现单例模式):
class IOLoop(object):
def init(self):
print( ‘IOLoop.init’ )
@classmethod
def instance(cls):
if not hasattr(cls, "_instance"):
cls._instance = cls()
return cls._instance
@classmethod
def initialized(cls):
"""Returns true if the singleton instance has been created."""
return hasattr(cls, "_instance")
def service(self):
print 'Hello,World'
# 下面调用一下,看看效果
print( IOLoop.initialized() ) # 打印: False 表示还没有初始化这个类
ioloop = IOLoop.instance() # 打印: IOLoop.__init__ 表示执行了这个类的 __init__ 构造函数
ioloop.service() # 打印: Hello,World
print( IOLoop.initialized() ) # 打印: True 表示已经初始化这个类了
ioloop = IOLoop.instance() # 没有打印,因为 __init__ 不需要再次执行
ioloop.service() # 打印: Hello,World
Property属性用法
1.现在介绍第一种使用属性的方法(不使用 @property 的写法):
在该类中定义三个函数,分别用作赋值、取值和删除变量(此处表达也许不很清晰,请看示例)
# 假设定义了一个类:C, 该类必须继承自object类, 有一私有变量__x
class C:
def __init__(self):
self.__x=None
# 取值函数
def getx(self):
return self.__x
# 赋值函数
def setx(self,value):
self.__x=value
# 删除函数
def delx(self):
del self.__x
# 定变量名
# property 函数原型为 property(fget=None, fset=None, fdel=None, doc=None), 所以根据自己需要定义相应的函数即可。
x = property(getx, setx, delx, '属性x的doc')
# 现在这个类中的x属性便已经定义好了,我们可以对它进行赋值、取值, 以及删除操作
c=C() # new 一个实例
c.x=100 # 赋值
y=c.x # 取值
print(y) # 打印: 100
print(c.x) # 打印: 100
del c.x # 删除变量