人生苦短,我用python

基础数据集

list,tuple,dictionary

list

list相当于数组

1
2
3
4
5
6
7
8
9
li = [1, 9, 8, 4] #定义
li_reflect = [elem*2 for elem in li] #映射
#方法
#append,count,extend,index,insert,pop,remove,reverse,sort
# 连接list和分割字符串
li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
str1 = ';'.join(li) # 'server=mpilgrim;uid=sa;database=master;pwd=secret'
str2 = str1.split(";") # ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
# join 和 split方法是逆用的过程

tuple

tuple是不可修改的数据类型,一般用于定义常量

dictionary

字典数据类型,存储key-value类型数据

1
2
3
4
5
6
params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"} # 定义
params.values() # ['mpilgrim', 'sa', 'master', 'secret']
params.items() # [('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
["%s=%s" % (k, v) for k, v in params.items()] # ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
# 方法
#clear,copy,fromkeys,get,values,has_key,items,iteritems,iterkeys,itervalues,keys,pop,popitem,setdefault,update,viewitems,viewvalues,viewkeys

自省

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def info(object, spacing=10, collapse=1): (1) (2) (3)
"""Print methods and doc strings.
Takes module, class, list, dictionary, or string."""
methodList = [method for method in dir(object) if callable(getattr(object, method))]
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
print "\n".join(["%s %s" %
(method.ljust(spacing), processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
if __name__ == "__main__":
print info.__doc__
li = []
info(li)
"""append count extend index insert pop remove reverse sort
L.append(object) -- append object to end
L.count(value) -> integer -- return number of occurrences of value
L.extend(list) -- extend list by appending list elements L.index(value) -> integer -- return index of first occurrence of value
L.insert(index, object) -- insert object before index
L.pop([index]) -> item -- remove and return item at index (default last)
L.remove(value) -- remove first occurrence of value L.reverse() -- reverse *IN PLACE*
L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1"""

使用 type、str、dir 和其它内置函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# type 函数返回任意对象的数据类型
type(1) # <type 'int'>
li = []
type(li) # <type 'list'>
# str 将数据强制转换为字符串。每种数据类型都可以强制转换为字符串
str(1) # '1'
horsemen = ['war', 'pestilence', 'famine'] # "['war', 'pestilence', 'famine']"
# dir 函数返回任意对象的属性和方法列表, 包括模块对象、函数对象、字符串对象、列表对象、字典对象 ...相当多的东西
li = []
dir(li) # ['append', 'count', 'extend', 'index', 'insert','pop', 'remove', 'reverse', 'sort']
# callable 函数,它接收任何对象作为参数,如果参数对象是可调用的, 返回 True;否则返回 False。可调用对象包括函数、类方法,甚至类自身
import string
string.punctuation # '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
callable(string.punctuation) #False
callable(string.Template) # True
string.Template.__doc__ # A string class for supporting $-substitutions.

type、str、dir 和其它的 Python 内置函数都归组到了 builtin (前后分别是双下 划线) 这个特殊的模块中。如果有帮助的话,你可以认为 Python 在启动时自 动执行了 from builtin import *,此语句将所有的 “内置” 函数导入该命名空间, 所以在这个命名空间中可以直接使用这些内置函数

通过 getattr 获取对 象引用

使用 getattr 函数,可以得到一个直到运行时才知道名称的函数的引用。

1
2
3
4
5
li = ["Larry", "Curly"]
print (li.pop,getattr(li, "pop")) # <built-in method pop of list object at 0x1098cfac8> <built-in method pop of list object at 0x1098cfac8>
getattr(li, "append")("Moe") # li变成了["Larry", "Curly", "Moe"]
#getattr 的返回值是 方法,然后你 就可以调用它,就像直接使用 li.append("Moe") 一样。但是实际上你没有直 接调用函数;只#是以字符串形式指定了函数名称。
# getattr 不仅仅适用于内置数据类型,也可作用于模块。
getattr 作为一个分发者

getattr 常见的使用模式是作为一个分发者。举个例子,如果你有一个程序可以 以不同的格式输出数据,你可以为每种输出格式定义各自的格式输出函数, 然后使用唯一的分发函数调用所需的格式输出函数。例如,让我们假设有一个以 HTML、XML 和普通文本格式打印站点统计的程序。 输出格式在命令行中指定,或者保存在配置文件中。statsout 模块定义了三个 函数:output_html、output_xml 和 output_text。然后主程序定义了唯一的输出函数, 如下:

1
2
3
4
5
6
7
8
import statsout
def output(data, format="text"):
output_function = getattr(statsout, "output_%s" % format)
return output_function(data)
# getattr 缺省值
def output(data, format="text"):
output_function = getattr(statsout, "output_%s" % format, statsout.output_text)
return output_function(data)

过滤列表

Python 具有通过列表解析 (Section 3.6, “映射 list”) 将列表映射到 其它列表的强大能力。这种能力同过滤机制结合使用,使列表中的有些元素 被映射的同时跳过另外一些元素。
过滤列表语法:[mapping-expression for element in source-list if filter-expression]

1
2
3
4
5
6
7
li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
[elem for elem in li if len(elem) > 1] # ['mpilgrim', 'foo']
[elem for elem in li if elem != "b"] #['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
#count 是一个列表方法,返回某个值在列表中出现的次数。你可以认为这个过滤器将从列表中剔除重复元素
[elem for elem in li if li.count(elem) == 1] # ['a', 'mpilgrim', 'foo', 'c']
# 综合使用,过滤出可以调用的方法
methodList = [method for method in dir(object) if callable(getattr(object, method))]

and or 的用法

  • 使用 and 时,在布尔环境中从左到右演算表达式的值。如果布尔环境中的某个值为假,则 and 返回第一个假值。所有值都为真,所以 and 返回最后一个真值
  • 使用 or 时,在布尔环境中从左到右演算值,如果有一个值 为真,or立刻返回该值.如果所有的值都为假,or返回最后一个假值
    1
    2
    3
    4
    5
    6
    7
    'a' and 'b' # 'b'
    '' and 'b' # ''
    'a' and 'b' and 'c' # 'c'
    'a' or 'b' # 'a'
    '' or 'b' # 'b'
    '' or [] or {} # {}

使用 lambda 函数

Python 支持一种有趣的语法,它允许你快速定义单行的最小函数。这些叫做
lambda 的函数,是从 Lisp 借用来的,可以用在任何需要函数的地方。
总的来说,lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个 表达式的值。lambda 函数不能包含命令,包含的表达式不能超过一个。不要 试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义 一个普通函数,然后想让它多长就多长。

1
2
3
4
5
6
def f(x):
return x*2
f(3) # 6
g = lambda x: x*2
g(3) # 6
(lambda x: x*2)(3) # 6

对象和面向对象

导入模块

  • import module
  • from module import
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# coding:utf-8
import copy
class User:
"""user class,include user info"""
def __init__(self,name=None,age=None,dic=None):
self.name = name
self.age = age
self.dic = {}
#self['sex'] = sex
# 专用方法,定义了专业方法,可以自己显示调用,也可以通过一定的写法,让python自己调用
def __getitem__(self,key):
return self.dic[key]
# 专用方法
def __setitem__(self,key,value):
self.dic[key] = value
user1 = User('chenxushan',24)
user1.__setitem__('address','suzhou')
address = user1.__getitem__('address')# 也可以这样调用,python自动完成。address = user1['address']
user2 = copy.copy(user1)
print(address,user1.__doc__,user1.__class__,user2.__class__)#suzhou user class,include user info <class '__main__.User'> <class '__main__.User'>
## 类属性定义和修改
class Counter:
count = 0 # count 是 counter 类的一个类属性。
def __init__(self):
self.__class__.count += 1 # __class__ 是每个类实例的一个内置属性 (也是每个类的)。它是一个类的引 用,而 self 是一个类 (在本例中,是 counter 类) 的实例。
counter # <class __main__.counter at 010EAECC>
counter.count # 0 # 因为 count 是一个类属性,它可以在我们创建任何类实例之前,通过直接 对类引用而得到。
c = counter()
c.count # 1 创建一个类实例会调用 __init__ 方法,它会给类属性 count 加 1。这样会影 响到类自身,不只是新创建的实例。
counter.count #1
d = counter() # 创建第二个实例将再次增加类属性 count。注意类属性是如何被类和所有 类实例所共享的。
d.count # 2
c.count # 2
counter.count # 2

私有函数

与大多数的语言不同,一个 Python 函数,方法,或属性是私有还是公有,完 全取决于它的名字。举例来说
有两个方法:__parse 和 __setitem。正如我们已经讨论过的, \setitem 是一个专有方法;通常,你不直接调用它,而是通过在一个类上使 用字典语法来调用,但它是公有的,并且如果有一个真正好的理由,你可以 直接调用它 (甚至从 fileinfo 模块的外面)。然而,\parse 是私有的,因为在它的 名字前面有两个下划线。
在 Python 中,所有的专用方法 (像 __setitem) 和内置属性 (像 \doc__) 遵守一 个标准的命名习惯:开始和结束都有两个下划线。不要对你自已的方法和属 性用这种方法命名;

异常和文件处理

异常

Python 使用 try…except 来处理异常,使用 raise 来引发异常。Java 和 C++ 使用 try…catch 来处理异常,使用 throw 来引发异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# coding:utf-8
#
import os
if __name__ == '__main__':
try:
fsock = open('./text','rb')
except IOError:
print ("The file does not exist, exiting gracefully")
else:
print ("This line will always print")
#print (fsock.mode,fsock.name)
fsock.seek(2,0)
fsock.close()
#print (fsock.tell(),fsock.read(12))
# 文件对象的 seek 方法在被打开文件中移动到另一个位置。第二个参数指 出第一个参数是什么意思:0 表示移动到一个绝对位置
# (从文件起始处算 起),1 表示移到一个相对位置 (从当前位置算起),还有 2 表示相对于文件 尾的位置。
# tell 方法确认了当前位置已经移动了。
class ReadFile:
def __init__(self,filename = None):
self.filename = filename
def read_file (self,filename = None, mode = None, postion = 0,counte = 0):
try:
fsock = open(filename,mode)
try:
fsock.seek(postion)
tagdate = fsock.read(counte) ## 读文件
finally:
fsock.close()
except IOError:
pass
return tagdate
def write_file (self,filename = None,mode = None,method = None,content = None):
try:
fsock = open(filename,mode)
try:
write_method = getattr(fsock,"%s" % method)
write_method(content)
finally:
fsock.close()
except IOError:
pass
f = ReadFile('./text')
#out = f.read_file('./text','rb',0,12)
f.write_file('./text','w','write','chenxuhsan') # w模式是覆盖写
f.write_file('./text','a','write',"xuminrui") # a模式是追加写
#print(out)

for 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# coding:utf-8
#
#for 循环不仅仅用于简单计数。它们可以遍历任何类型的东西。下面的例子是 一个用 for 循环遍历 dictionary 的例子。
import os,sys
if __name__ == "__main__":
li = ['a','b','c']
for item in range(len(li)):
print(li[item])
# 遍历字典
for k,v in os.environ.items():
#print("%s=%s"%(k,v))
pass
# 遍历符合数据类型
tagDataMap = {"title":( 3, 33, 'stripnulls'), "artist":( 33, 63, 'stripnulls'),\
"album" :( 63, 93, 'stripnulls'),\
"year":( 93, 97, 'stripnulls'),\
"comment":( 97, 126, 'stripnulls'),\
"genre":(127, 128, 'ord')\
}
for tag, (start, end, parseFunc) in tagDataMap.items():
#print("%s=(%d,%d,%s)" % (tag,start, end, parseFunc))
pass
#print(','.join(sys.modules.keys()))
#sys 模块包含了系统级的信息,像正在运行的 Python 的版本 (sys.version 或 sys.version_info),和系统级选项,
#像最大允许递归的深度 (sys.getrecursionlimit() 和 sys.setrecursionlimit())
for k,v in sys.modules.items():
print("%s=%s"%(k,v))
print(sys.modules['io'])
#<module 'io' from '/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/io.py'>
#每个 Python 类都拥有一个内置的类属性 __module__,它定义了这个类的模 块的名字。
#将它与 sys.modules 字典复合使用,你可以得到定义了某个类的模块的引用。

目录操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# coding:utf-8
#
import os
if __name__ == "__main__":
# 构造路径名
path1 = os.path.join("/Users/chenxushan/Documents/SublimeWorkspace/python/base/", "text.txt")
print(path1,os.path.expanduser("~"),os.path.join(os.path.expanduser("~"), "Python"))
# expanduser 将对使用 ~ 来表示当前用户根目录的路径名进行扩展。在任何 平台上,只要用户拥有一个根目录,它就会有效
# 分割路径
(filepath, filename) = os.path.split('/Users/chenxushan/Documents/SublimeWorkspace/python/base/text.txt')
(shortname, extension) = os.path.splitext(filename)
print(filepath,filename,shortname,extension)
# 列出目录
dirname = './'
listdir = os.listdir(dirname)
# 过滤出是否是文件
isFile = [f for f in os.listdir(dirname) if os.path.isfile(os.path.join(dirname, f))]
# 过滤出是否是文件夹
isDir = [f for f in os.listdir(dirname) if os.path.isdir(os.path.join(dirname, f))]
print(listdir,isFile,isDir)

python类支持继承,也支持多继承

迭代器

for element in [1, 2, 3]:
print(element)
这种形式的访问清晰、简洁、方便。迭代器的用法在 Python 中普遍而且统一。 在后台,for 语句在容器对象中调用 iter() 。该函数返回一个定义了 next() 方法的迭代器对象,它在容器中逐一访问元素。没有后续的元素时, next() 抛 出一个 StopIteration 异常通知 for 语句循环结束。以下是其工作原理的示 例:

1
2
3
s = 'abc'
it = iter(s)
next(it) # 'a'

了解了迭代器协议的后台机制,就可以很容易的给自己的类添加迭代器行为。定 义一个 iter() 方法,使其返回一个带有 next() 方法的对象。如果这个类 已经定义了 next() ,那么 iter() 只需要返回 self:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
self.data = data
self.index = len(data)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
rev = Reverse('spam')
iter(rev) # <__main__.Reverse object at 0x00A1DB50>
for char in rev:
print(char) # 输出 m a p s

我们已经知道,可以直接作用于for循环的数据类型有以下几种:
一类是集合数据类型,如list、tuple、dict、set、str等;
一类是generator,包括生成器和带yield的generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象:

1
2
from collections import Iterable
isinstance([], Iterable) # ture

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。可以使用isinstance()判断一个对象是否是Iterator对象:

1
2
from collections import Iterator
isinstance((x for x in range(10)), Iterator) # true

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。把list、dict、str等Iterable变成Iterator可以使用iter()函数:

1
2
isinstance(iter([]), Iterator) # true
isinstance(iter('abc'), Iterator) # true

为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
g = (x * x for x in range(10)) #<generator object <genexpr> at 0x1022ef630>
next(g) # 0
next(g) # 1
# 面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
for n in g:
print(n)
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b # 把print 换成 yield就变成了一个 generator
a, b = b, a + b
n = n + 1
return 'done'
f = fib(6) # <generator object fib at 0x104feaaa0>
# 这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变##成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
def odd():
print('step 1')
yield 1
print('step 2')
yield(3)
print('step 3')
yield(5)
o = odd()
next(o) # step 1 1
# 但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
g = fib(6)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
#g: 1
# g: 1
# g: 2
# g: 3
# g: 5
# g: 8
# Generator return value: done

小结

凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Python的for循环本质上就是通过不断调用next()函数实现的,例如:

综合例子

遍历字典

1
2
3
4
5
6
7
8
9
10
11
12
def buildConnectionString(params):
"""Build a connection string from a dictionary of parameters.
Returns string."""
return ";".join(["%s=%s" % (k, v) for k, v in params.items()])
if __name__ == "__main__": # 这里的写法目的是:允许这个程序在自己独立运行时做些有用的事情,同时又
#不妨碍作为其它程序的模块使用
myParams = {"server":"mpilgrim", \
"database":"master", \
"uid":"sa", \
"pwd":"secret" \
}
print buildConnectionString(myParams)