首页 > 代码库 > Python 点滴 II

Python 点滴 II

【__doc__】

>>> str.__doc__         #内置文档字符串; 模块级
"str(object=‘‘) -> string\n\nReturn a nice string representation of the object.\nIf the argument is a string, the return value is the same object."

>>> str.upper.__doc__   #内置文档字符串; 函数级
‘S.upper() -> string\n\nReturn a copy of the string S converted to uppercase.‘


用户自定义文档(假如有这么个文件:docstring.py)

"""
Simple employee class, including sum functions.
Filename: docstrings.py
Author  : Tom Smith
Version : 1.0
"""
spam = 40


def square(x):
    """Calculate square of one number."""
    return x **2


class employee:
    """Employee class document here"""
    pass


print square(4)
print square.__doc__

那么将其模块导入后,要查看其文档

>>> import docstrings                #导入模块
16
Calculate square of one number.
>>> print docstrings.__doc__         #模块文档

Simple employee class, including square functions.
Filename: docstrings.py
Author  : Tom Smith
Version : 1.0

>>> print docstrings.square.__doc__  #函数文档
Calculate square of one number.
>>> docstrings.employee.__doc__      #类文档,在交互模式可不用print
‘Employee class document here‘

【help函数】

取得详细信息

>>> help(int)                        #查看模块级的Pydoc文档
Help on class int in module __builtin__:


class int(object)

...

>>> help(str.title)                  #查看函数级的Pydoc文档
Help on method_descriptor:


title(...)
    S.title() -> string
    
    Return a titlecased version of S, i.e. words start with uppercase
    characters, all remaining cased characters have lowercase.

【PyDoc】

1. Start==>Module Docs==>输入模块名 按Enter键==>Go to selected

2. 或者点击open browser按钮,直接跳转到下面链接: http://localhost:7464/

例如上面写的就可以在下面链接读取到: http://localhost:7464/docstrings.html

3. 或者浏览官方网站: https://www.python.org/doc/

【sort(),sorted()】

>>> D = {‘a‘:1,‘b‘:2,‘c‘:3}
>>> D.keys()
[‘a‘, ‘c‘, ‘b‘]
>>> D.keys().sort()   #无返回值,返回的是None
>>> D.keys()
[‘a‘, ‘c‘, ‘b‘]
>>> sorted(D.keys())  #有返回值,返回的是排序后的列表
[‘a‘, ‘b‘, ‘c‘]
>>> for k in D.keys().sort():  #所以会报NoneType不可迭代的错误
print k,

Traceback (most recent call last):
  File "<pyshell#29>", line 1, in <module>
    for k in D.keys().sort():
TypeError: ‘NoneType‘ object is not iterable
>>> for k in sorted(D.keys()):
print k,

a b c

【函数】

扮演两个主要较色

1. 最大化的代码重用与最小化的代码冗余

2. 流程的分解(大任务分解成无数小任务,实现起来容易)

>>> def calSum(x,y): return x + y
>>> calSum(1,2)
3

函数的基本概念

def是可执行代码                        #函数并不存在,直到Python运行了def后才存在

def创建了一个对象并将其赋值给了变量名  #像上面的calSum

return将一个结果发送给调用者   #当被调用时,调用程序停止直到函数完成任务,函数返回结果并将控制权交给调用程序.

函数是通过赋值(对象引用)传递   #参数通过赋值传递给了函数,就是对象引用

global声明模块级变量并被赋值   #为了分配一个可在整个模块都可以使用的变量名,函数需在global语句中将其列举出来.

参数、返回值及变量不需要声明   #在函数中没有类型约束,可以传递任意类型的参数给函数,函数也可以返回任意类型的对象

函数可以嵌套在if语句中实现不同定义,如:

if test:

  def func(): ...

else:

  def func(): ...

>>> othername = func  #Assign Function Object
>>> othername()       #Call Func again

【变量名解析:LEGB原则】

对于一个def语句:

1. 变量名引用分为三个作用域进行查找:首先是本地,之后是函数内(如果有的话),之后是全局,最后是内置

2. 在默认情况下,变量名赋值会创建或者改变本地变量

3. 全局声明将赋值变量映射到模块文件内部的作用域


【内置作用域】

>>> import __builtin__
>>> dir(__builtin__)
[‘ArithmeticError‘, ‘AssertionError‘, ‘AttributeError‘, ‘BaseException‘, ‘BufferError‘, ‘BytesWarnin
g‘, ‘DeprecationWarning‘, ‘EOFError‘, ‘Ellipsis‘, ‘EnvironmentError‘, ‘Exception‘, ‘False‘, ‘Floatin
gPointError‘, ‘FutureWarning‘, ‘GeneratorExit‘, ‘IOError‘, ‘ImportError‘, ‘ImportWarning‘, ‘Indentat
ionError‘, ‘IndexError‘, ‘KeyError‘, ‘KeyboardInterrupt‘, ‘LookupError‘, ‘MemoryError‘, ‘NameError‘,
 ‘None‘, ‘NotImplemented‘, ‘NotImplementedError‘, ‘OSError‘, ‘OverflowError‘, ‘PendingDeprecationWar
ning‘, ‘ReferenceError‘, ‘RuntimeError‘, ‘RuntimeWarning‘, ‘StandardError‘, ‘StopIteration‘, ‘Syntax
Error‘, ‘SyntaxWarning‘, ‘SystemError‘, ‘SystemExit‘, ‘TabError‘, ‘True‘, ‘TypeError‘, ‘UnboundLocal
Error‘, ‘UnicodeDecodeError‘, ‘UnicodeEncodeError‘, ‘UnicodeError‘, ‘UnicodeTranslateError‘, ‘Unicod
eWarning‘, ‘UserWarning‘, ‘ValueError‘, ‘Warning‘, ‘WindowsError‘, ‘ZeroDivisionError‘, ‘_‘, ‘__debu
g__‘, ‘__doc__‘, ‘__import__‘, ‘__name__‘, ‘__package__‘, ‘abs‘, ‘all‘, ‘any‘, ‘apply‘, ‘basestring‘
, ‘bin‘, ‘bool‘, ‘buffer‘, ‘bytearray‘, ‘bytes‘, ‘callable‘, ‘chr‘, ‘classmethod‘, ‘cmp‘, ‘coerce‘,
‘compile‘, ‘complex‘, ‘copyright‘, ‘credits‘, ‘delattr‘, ‘dict‘, ‘dir‘, ‘divmod‘, ‘enumerate‘, ‘eval
‘, ‘execfile‘, ‘exit‘, ‘file‘, ‘filter‘, ‘float‘, ‘format‘, ‘frozenset‘, ‘getattr‘, ‘globals‘, ‘hasa
ttr‘, ‘hash‘, ‘help‘, ‘hex‘, ‘id‘, ‘input‘, ‘int‘, ‘intern‘, ‘isinstance‘, ‘issubclass‘, ‘iter‘, ‘le
n‘, ‘license‘, ‘list‘, ‘locals‘, ‘long‘, ‘map‘, ‘max‘, ‘memoryview‘, ‘min‘, ‘next‘, ‘object‘, ‘oct‘,
 ‘open‘, ‘ord‘, ‘pow‘, ‘print‘, ‘property‘, ‘quit‘, ‘range‘, ‘raw_input‘, ‘reduce‘, ‘reload‘, ‘repr‘
, ‘reversed‘, ‘round‘, ‘set‘, ‘setattr‘, ‘slice‘, ‘sorted‘, ‘staticmethod‘, ‘str‘, ‘sum‘, ‘super‘, ‘
tuple‘, ‘type‘, ‘unichr‘, ‘unicode‘, ‘vars‘, ‘xrange‘, ‘zip‘]
>>>

#前面是通用Error,后面是内置方法,有两种使用

第一种,直接使用即可              #一般用此种方法

>>> zip
<built-in function zip>

第二种, 通过__builtin__模块调用

>>> import __builtin__
>>> __builtin__.zip
<built-in function zip>

里面要注意def语句里面避免使用内置变量名,如:

>>> def hider():
...   open = ‘spam‘
...   open(‘data.txt‘)

open是PYTHON中内置的方法,但我们又拿其作为了一个变量,所以会报错。

【最小化文件间的修改】

第一个文件

#first.py

X = 99

第二个文件, 给第一个文件中的X赋予了一个新值

#second.py

import first

first.X = 88

这样做的话,有两点不好的地方:

1. 不知道X可以在哪里修改,以后维护起来很难

2. 让两个文件有太强的关联性

修改如下:

#first.py   将其值封装在setX函数里面

X = 99

def setX(new):
    global X
    X = new

#second.py

import first
first.setX(88)
>>> first.X
88

【其他访问全局变量的方法】

#thismod.py

var = 99


def local():
    var = 0                    #改变本地变量var


def global1():
    global var                 #声明全局变量
    var += 1                   #改变全局变量


def global2():
    var = 0                    #改变本地变量var
    import thismod             #导入自身
    thismod.var += 1           #改变全局变量var


def global3():
    var = 0                     #改变本地变量var
    import sys                  #导入系统模块
    glob = sys.module[‘thismod‘]#获得模块对象
    glob.var += 1               #改变全局变量var


def test():

    print var

    local;global1();global2();global3();

    print var

#运行时,将会给全局变量加3,只有第一个函数不会影响全局变量

>>> import thismod

99

102

>>> thismod.var

102

#这表明模块属性和全局变量是等效的.

【嵌套作用域】

简单例子如下: 在一个def函数里面嵌套一个或多个def函数

>>> def f1():
...   x = 88
...   def f2():
...     print x
...   f2()
...
>>> f1()
88

【避免可变参数的修改】

>>> def change(a,b):
...   a = 2
...   b[0] = ‘spam‘
...
>>> X = 1
>>> L = [1,2]
>>> change(X,L)
>>> X;L      #X是不可变数据,没有发生改变;L发生了改变
1
[‘spam‘, 2]

如果想可变数据,比如说列表页不发生改变,只需要

>>> def change(a,b):
...   b = b[:]        #拷贝一份数据
...   a = 2
...   b[0] = ‘spam‘

【工厂函数】

>>> def maker(N):
...   def action(X):
...     return X ** N
...   return action
...
>>> f = maker(2)
>>> f    
<function action at 0x0000000002183908>
>>> f(3)
9
>>> f(4)
16
>>> g = maker(3)
>>> g(3)
27
>>> f(3)          # 3 ** 2 具有记忆的功能
9

【作用域与带循环变量的默认参数比较】

>>> def makeActions():
...   acts = []
...   for i in range(5):
...     acts.append(lambda x: i ** x)
...   return acts
...
>>> acts = makeActions()
>>> acts[0]
<function <lambda> at 0x0000000002183AC8>

#匿名函数里面的i具有记忆功能,i记忆着最后一个值
>>> acts[0](2)   
16
>>> acts[2](2)
16
>>> acts[4](2)
16

#要如何改变呢,只需要在匿名函数里面添加i=i,拿当前的i赋值

>>> def makeActions():
...   acts = []
...   for i in range(5):
...     acts.append(lambda x,i=i:i ** x)
...   return acts
...
>>> m = makeActions()
>>> m[0](2)
0
>>> m[2](2)
4
>>> m[4](2)
16

#这是在匿名函数里面要注意的

【关键字参数实际用途】

用途很多,常见的比如说在Tkinter里面.

>>> from Tkinter import *
>>> widget = Button(text="Press me",command=someFunction)

#创建了一个按钮,创建了文本及回调函数,使用了text及command关键字参数

【更有用的例子:通用的set函数】

#求交集insersect

>>> def intersect(*args):
...   res = []
...   for x in args[0]:
...     for other in args[1:]:
...       if not x in other: break
...       else: res.append(x)
...   return res
...
>>> s1 = ‘spam‘
>>> s2 = ‘scam‘
>>> intersect(s1,s2)
[‘s‘, ‘a‘, ‘m‘]

#求合集union

>>> def union(*args):
...   res = []
...   for seq in args:
...     for x in seq:
...       if not x in res:
...         res.append(x)
...   return res
...
>>> s1 = [1,2,3]
>>> s2 = [3,4,5]
>>> s3 = [5,6,7]
>>> union(s1,s2,s3)
[1, 2, 3, 4, 5, 6, 7]

【lambda函数】

如果是临时性使用,可以考虑使用lambda,而且def给函数的变量名可能会跟其他变量名重复,这个时候就可以考虑用lambda了。如果需要在lambda中执行循环,能够嵌入map调用或列表解析表达式这样的工具来实现.

>>> import sys
>>> showall = lambda x: map(sys.stdout.write,x)
>>> t = [‘spam\n‘,‘toast\n‘,‘eggs\n‘]
>>> showall(t)
spam
toast
eggs

或者用列表表达式来实现

>>> showall = lambda x:[sys.stdout.write(line) for line in x]
>>> t       = [‘spam\n‘,‘toast\n‘,‘eggs\n‘]
>>> showall(t)
spam
toast
eggs

NOTE: 除非不得已,一般不要用这样晦涩的的代码.同时避免使用嵌套的lambda

>>> def action(x):
...   return lambda y: x + y
...
>>> action(99)
<function <lambda> at 0x00000000021B3A58>
>>> action(99)(3)

102

>>> (lambda x: lambda y: x+y)(40)(60) #最好避免lambda代码嵌套
100

【内置函数apply】

一些程序需要以一种更通用的样子来调用任意的函数,而不需要一开始就知道它们的函数名或参数,内置函数apply就可以使用一些特定的调用语法,完成这样的任务.

>>> def func(x,y,z): return x+y+z
...
>>> apply(func,(1,2,3))
6

或者写成匿名函数

>>> f = lambda x,y,z : x + y + z
>>> apply(f,(1,2,3))
6

回调函数的好处是,函数可代码放在一起,清晰易懂.

>>> import sys,Tkinter
>>> x = Button(text=‘Press me‘,command=(lambda:sys.stdout.write(‘Spam\n‘)))

【传入关键字参数】

>>> def echo(*args,**kargs):print args,kargs
...
>>> echo(1,2,a=3,b=4)
(1, 2) {‘a‘: 3, ‘b‘: 4}

用apply来做就是:

>>> args = (1,2)
>>> kargs= {‘a‘:3,‘b‘:4}
>>> apply(echo,args,kargs)
(1, 2) {‘a‘: 3, ‘b‘: 4}

apply与map的区别

apply将后面的实参传递到函数中,只执行一次

map会将序列中的所有元素都调用函数,执行多次。所有的原处处理完为止.

【map函数】

当对列表或其他序列,对每一个元素进行一次操作并把其结果集合起来,这里就要考虑使用map函数.如下面的例子

列表中每个元素加10. 常规做法如下:

>>> L = [1,2,3,4]
>>> res = []
>>> for x in L:
...   res.append(x+10)
...
>>> res
[11, 12, 13, 14]

用map函数来实现就是:

>>> map(lambda x: x + 10,[1,2,3,4])
[11, 12, 13, 14]

>>> pow(3,4)
81
>>> map(pow,[1,2,3],[2,3,4]) #对应 1**2; 2**3; 3**4
[1, 8, 81]


>>> def mymap(func,seq):
...   res = []
...   for x in seq: res.append(func(x))
...   return res
...
>>> def inc(x): return x + 10
...
>>> map(inc,[1,2,3,4])
[11, 12, 13, 14]
>>> mymap(inc,[1,2,3,4])
[11, 12, 13, 14]

map函数的好处: 内置函数,有速度方面的优势

【函数式编程工具:filter和reduce】

filter: 基于某些测试需要过滤一些元素

reduce: 对每个元素都运行函数到最后结果

>>> range(-5,5)
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
>>> filter(lambda x: x>2,range(-5,5))
[3,4]

等效于下面的for循环

>>> res = []
>>> for x in range(-5,5):
...   if x > 2:
...     res.append(x)
...
>>> res
[3, 4]

如果要算一个列表所有值之和

>>> L = [1,2,3,4]
>>> res = L[0]
>>> for x in L[1:]:
...   total += x
...
>>> total
10
>>> reduce(lambda x,y: x+y, L)
10

自己编写个reduce函数

>>> def myreduce(func,seq):
...   res = seq[0]
...   for next in seq[1:]:
...     res = func(res,next)
...   return res
...
>>> myreduce(lambda x,y:x+y,[1,2,3,4])
10
>>> myreduce(lambda x,y:x*y,[1,2,3,4])
24

#接下来可以看看内置的operator模块,看他们结合起来使用

>>> import operator
>>> reduce(operator.add,[1,2,3,4])
10

效果和下面是一样的:
>>> reduce(lambda x,y:x+y,(1,2,3,4))
10

【列表解析】

例1: 如果要解析字符串==>数字.  ord(‘s‘) = 115

方法一: 常规方法

>>> res = []
>>> for x in ‘spam‘:
...   res.append(ord(x))
...
>>> res
[115, 112, 97, 109]

方法二: 内置函数

>>> map(ord,‘spam‘)
[115, 112, 97, 109]

方法三: 列表解析

>>> [ord(x) for x in ‘spam‘]
[115, 112, 97, 109]

例2: 如果要收集range(5)其元素平方

方法一: map函数

>>> map(lambda x:x**2,range(5))
[0, 1, 4, 9, 16]

方法二: 列表解析
>>> [x ** 2 for x in range(5)]
[0, 1, 4, 9, 16]

例3: 过滤出所有偶数

>>> [x for x in range(5) if x%2 == 0]
[0, 2, 4]

>>> filter(lambda x: x%2 == 0, range(5))
[0, 2, 4]

>>> res = []
>>> for x in range(5):
...   if x % 2 == 0:
...     res.append(x)
...
>>> res
[0, 2, 4]

例4: [0-10]之间偶数的平方列表

>>> [x**2 for x in range(10) if x%2 == 0]
[0, 4, 16, 36, 64]

#当然也可以结合map,filter,lambda来实现,但显得复杂

>>> map(lambda x:x**2,filter(lambda x:x%2==0,range(10)))
[0, 4, 16, 36, 64]

相比较普通实现,列表表达式要显得简洁的多,比如:

例5. 求[0,1,2]与[100,200,300]任意两者的和

>>> [x+y for x in [0,1,2] for y in [100,200,300]]
[100, 200, 300, 101, 201, 301, 102, 202, 302]

普通方法实现:(需要四行代码)

>>> res = []
>>> for x in [0,1,2]:
for y in [100,200,300]:
res.append(x+y)

>>> res
[100, 200, 300, 101, 201, 301, 102, 202, 302]

再比如:

>>> [x+y for x in ‘AB‘ for y in ‘CD‘]
[‘AC‘, ‘AD‘, ‘BC‘, ‘BD‘]

最后看一个复杂的多的例子

例6. (0,2,4)与(1,3)组成的所有坐标的集合

#一行代码就搞定了

>>> [(x,y) for x in range(5) if x%2 ==0 for y in range(5) if y%2 == 1]
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

#如果换成普通遍历(至少要6行代码)

>>> res = []
>>> for x in range(5):
        if x%2 == 0:
    for y in range(5):
        if y%2 == 1:
    res.append((x,y))

>>> res
[(0, 1), (0, 3), (2, 1), (2, 3), (4, 1), (4, 3)]

【列表解析和矩阵】

使用Python编写矩阵(多维数组),比如说: 3*3,使用这种结构可以索引行,也可以索引行中的列.

>>> M = [[1,2,3],
         [4,5,6],
         [7,8,9]]
>>> M[1]    
[4, 5, 6]
>>> M[1][1]
5

#列表解析

>>> [M[1][x] for x in [0,1,2]]
[4, 5, 6]
>>> [row[1] for row in M]
[2, 5, 8]
>>> [M[row][1] for row in (0,1,2)]
[2, 5, 8]
>>> [M[i][i] for i in range(len(M))]

[1, 5, 9]

#复杂点列表解析与矩阵

>>> M = [[1,2,3],
         [4,5,6],
         [7,8,9]]

>>> N = [[2,2,2],
         [3,3,3],
         [4,4,4]]
>>> [M[row][col]*N[row][col] for row in range(3) for col in range(3)]
[2, 4, 6, 12, 15, 18, 28, 32, 36]

>>> [[M[row][col] * N[row][col] for col in range(3)] for row in range(3)]
[[2, 4, 6], [12, 15, 18], [28, 32, 36]]

如果是普通实现:

>>> res = []
>>> for row in range(3):
tmp = []
for col in range(3):
tmp.append(M[row][col]*N[row][col])
res.append(tmp)

>>> res
[[2, 4, 6], [12, 15, 18], [28, 32, 36]]

【速度差距】

基于对运行在当前Python下的测试,map调用比等效的for循环要快两倍,而列表解析往往比map调用要稍微快一点。速度的差距是来自底层实现上,map和列表解析式在解析器中以C语言的速度来运行的,比Python的for循环代码在PVM中步进运行要快得多。但是从简单,业务逻辑角度来看,要考虑用for循环.测试模块.time.clock(),time.time()和timeit模块.

【列表解析和map:现实例子】

例1.读取文件的行并去掉换行符

>>> open(‘myfile‘).readlines()
[‘aaa\n‘, ‘bbb\n‘, ‘ccc\n‘]

>>> [line.rstrip() for line in open(‘myfile‘)]
[‘aaa‘, ‘bbb‘, ‘ccc‘]
>>> [line.rstrip() for line in open(‘myfile‘).read()]
[‘a‘, ‘a‘, ‘a‘, ‘‘, ‘b‘, ‘b‘, ‘b‘, ‘‘, ‘c‘, ‘c‘, ‘c‘, ‘‘]
>>> [line.rstrip() for line in open(‘myfile‘).readlines()]
[‘aaa‘, ‘bbb‘, ‘ccc‘]

#用map和lambda联合实现
>>> map(lambda line:line.rstrip(),open(‘myfile‘))
[‘aaa‘, ‘bbb‘, ‘ccc‘]

例2,要取出[(‘Alice‘,30,‘HR‘),(‘Jerry‘,30,‘IT‘)]年龄

#列表解析实现

>>> L = [(‘Alice‘,30,‘HR‘),(‘Jerry‘,40,‘IT‘)]
>>> [age for (name,age,job) in L]
[30, 40]

#map和lambda实现

>>> map(lambda (name,age,job):age,L)
[30, 40]

【生成器】

生成器和一般函数在代码上最大的不同:

一个生成器yield一个值,而不是ruturn一个值.yield语句将函数关起,并向它的调用者返回一个值,但是保存足够的状态信息为了让其能够在函数从它挂起的地方恢复.简而言之,包含了yield语句的函数将会特地编译为生成器。当调用时,它们会返回一个生成器对象,这个生成器对象支持迭代器对象接口。生成器函数也许也有一个return语句,这个语句就是用来终止产生值的。迭代器对象都有下一个方法,并会抛出一个StopIteration来终结这个迭代.

例1: 产生一系列数字的平方

>>> def gensquares(N):
for i in range(N):
yield i ** 2
这个函数在每次循环时都会产生一个值,之后将其返还给它的调用者。当它被暂停后,它的上一个状态被保存下来,并且在yield语句之后控制器马上被回收。例如:当用在一个for循环中时,在循环中每一次完成函数的yield语句后,控制权都会返还给函数.


>>> for i in gensquares(5):
print i,‘:‘,

0 : 1 : 4 : 9 : 16 :

可以看下迭代器做了些什么:

>>> x = gensquares(3)
>>> x
<generator object gensquares at 0x0000000002BE9D38>
>>> x.next()
0
>>> x.next()
1
>>> x.next()
4
>>> x.next()


Traceback (most recent call last):
  File "<pyshell#66>", line 1, in <module>
    x.next()
StopIteration

其他的实现方法

方法一:普通函数

>>> def buildsquares(n):
res = []
for i in range(n):
    res.append(i**2)
return res

>>> for x in buildsquares(5):print x,‘:‘,
0 : 1 : 4 : 9 : 16 :

方法二:列表解析

>>> for x in [n**2 for n in range(5)]:
print x,‘:‘,

0 : 1 : 4 : 9 : 16 :

方法三:map与lambda

>>> for x in map(lambda x:x**2,range(5)):
print x,‘:‘,

0 : 1 : 4 : 9 : 16 :

当结果的列表很大或者在处理每个结果需要很多时间的时候,就要考虑使用生成器.有了生成器,函数变量进行了自动的保存和恢复.

【迭代器和内置类型】

内置的数据类型设计了对应于内置函数iter的迭代器对象。

>>> D = {‘a‘:1,‘b‘:2,‘c‘:3}
>>> x = iter(D)
>>> dir(x)
[‘__class__‘, ‘__delattr__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__iter__‘, ‘__length_hint__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘next‘]
>>> x.next()
‘a‘
>>> x.next()
‘c‘
>>> x.next()
‘b‘
>>> x.next()
Traceback (most recent call last):
  File "<pyshell#25>", line 1, in <module>
    x.next()
StopIteration

此外,所有的迭代内容(包括for循环、map调用、列表解析等)依次设计用来自动调用iter函数,来看看是不是支持迭代协议。这就是为什么我们可以在

字典中进行循环而不用调用它的关键字方法,步进一个文件中的所有行,而不用调用readlines方法的原因.

>>> for k in D:
print k, ‘==>‘,D[k]

a ==> 1
c ==> 3
b ==> 2

>>> for line in open(‘myfile‘):
...   print line,
...
aaa
bbb
ccc

【生成器表达式:迭代器遇到列表解析】

列表解析是用:[]

生成器表达式:()

>>> [x ** 2 for x in range(3)]                   #生成一个列表
[0, 1, 4]
>>> (x**2 for x in range(3))                     #产生一个可迭代对象
<generator object <genexpr> at 0x0000000002B19990>

生成器表达式:不是在内存中构建结果,而是返回一个生成器对象.这个对象支持迭代协议,并获得最终结果列表中的一部分.

>>> G = (x**2 for x in range(3))
>>> G.next()
0
>>> G.next()
1
>>> G.next()
4

NOTE;一般不用next方法操作迭代器,因为for会自动触发

>>> for num in (x**2 for x in range(3)):
print ‘%s %s‘ % (num,num/2.0)


0 0.0
1 0.5
4 2.0

map,sorted,sum等内置函数,还有any,all和list等内置函数都支持迭代.

>>> sum(x**2 for x in range(5))
30
>>> sorted(x**2 for x in range(5))
[0, 1, 4, 9, 16]
>>> sorted((x**2 for x in range(5)),reverse=True)
[16, 9, 4, 1, 0]
>>> import math
>>> map(math.sqrt,(x ** 2 for x in range(4)))
[0.0, 1.0, 2.0, 3.0]

【对迭代的各种方法进行计时】

列表解析要比for循环有速度方面的优势,而且map会依据调用方法的不同变现出更好或更差的性能。生成器表达式看起来比列表解析速度更慢一些,但是它们把内存需求降到了最小.

四个测试:依次创建1000次结果列表,而每个列表中含10万个元素

测试代码

import time,sys
reps = 1000
size = 100000


def tester(func,*args):
    startTime = time.time()
    for i in range(reps):
        func(*args)
    elapsed = time.time() - startTime
    return elapsed


def forStatement():
    res = []
    for x in range(size):
        res.append(abs(x))


def listComprehension():
    res = [abs(x) for x in range(size)]


def mapFunction():
    res = map(abs,range(size))


def generatorExpression():
    res = list(abs(x) for x in range(size))


print sys.version
tests = (forStatement,listComprehension,mapFunction,generatorExpression)
for testfunc in tests:
    print testfunc.__name__.ljust(20),‘=>‘,tester(testfunc)

测试结果

>>> 
2.7.4 (default, Apr  6 2013, 19:55:15) [MSC v.1500 64 bit (AMD64)]
forStatement         => 21.3609998226
listComprehension    => 13.7050001621
mapFunction          => 11.1540000439
generatorExpression  => 16.4489998817

在编写Python代码的时候,性能不应该是最先考虑的。

首先: 考虑代码的简洁,可读性。

其次: 才考虑优化

【函数设计的概念】

如何将任务分解成为更有针对性的函数(导致了聚合性)

函数之间如何通信(耦合性)

下面是一般性的概念:

耦合性: 对于输入使用参数并且对于输出使用return语句

耦合性: 只有在真正必要的情况下才使用全局变量

耦合性: 不可改变可变类型的参数,除非调用者希望这样做.

耦合性: 避免直接改变在另一个模块文件中的变量

聚合性: 每一个函数都应该有一个单一的、统一的目标

大小性: 每一个函数应该相对较小

【函数是对象:简洁调用】

函数对象能够进行赋值、传递给其他的函数以及在数据结构中排序,这和简单的数字和字符串一样。函数对象还支持特殊的操作。

例如: 函数名就是一个简单的对象的引用,而且能够将这个对象重新分配给其他的变量名,以及通过任何引用对她进行调用

#将echo对象赋值给另一个变量x

>>> def echo(messages):
print messages

>>> x = echo
>>> x(‘Hello,World!‘)
Hello,World!

#通过给传入的参数加()后,被调用者就可以调用传入的函数了。 此所谓函数调用函数

>>> def indirect(func,arg):
func(arg)


>>> indirect(echo,‘Hello,World!‘)   #Pass a function to another function.
Hello,World!

#甚至可以将函数对象封装在数据结构中,就像她是整数或字符串一样

>>> schedule = [(echo,‘Jerry!‘),(echo,‘Alice!‘)]
>>> for func,arg in schedule:
func(arg)

Jerry!
Alice!

【函数陷阱】

#本地变量是静态检测的

看下面例子

>>> X = 99
>>> def selector():
...   print X
...
>>> selector()
99

如果改动一下:

>>> X = 99
>>> def selector():
...   print X
...   X = 88
...
>>> selector()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in selector
UnboundLocalError: local variable ‘X‘ referenced before assignment

产生了一个未定义变量名的错误.在编译时,Python看到了对X的赋值语句,并且决定了X将会在函数中的任何一个地方都将是本地变量名。因为print语句在前,先执行,赋值语句还没发生,导致错误发生.

如果希望打印本地变量X,则要这么写

>>> X = 99
>>> def selector():
...   X = 88
...   print X
...
>>> selector()
88

如果希望打印全局变量X,则要这么写

>>> X = 99
>>> def selector():
...   global X
...   print X
...   X = 88
...
>>> selector()
99

NOTE: 这样写的话,只要selector()函数一被调用,全局变量就会发生改变,要想不改变的话,应该这样做:

>>> X = 99
>>> def selector():
...   import __main__   #导入main命名空间
...   print __main__.X  #获取该命名空间中X变量的值 
...   X = 88            #声明并赋值本地变量
...   print X           #打印本地变量
...
>>> selector()
99
88


#默认和可变对象

默认参数是在def语句运行时被评估并保存的,而不是在这个程序调用时。从内部来将,PYTHON会将每一个默认参数保存为一个对象,附加在这个函数本身。因为默认参数在调用时都保存了一个对象,所以必须对修改的可变默认参数十分小心.看下例:

>>> def saver(x=[]):  #总是保存一个列表对象
...   x.append(1)     #每次都改变这个对象
...   print x
...
>>> saver([2])        #未用默认值
[2, 1]
>>> saver()           #使用默认值
[1]
>>> saver()           #每次都增长
[1, 1]

修改如下:
>>> def saver(x=None):
...   if x == None:
...     x = []
...   x.append(1)
...   print x
...
>>> saver([2])
[2, 1]
>>> saver()
[1]
>>> save()
[1]


#没有return语句的函数

在PYTHON函数中,默认都有return或yield语句,如果没有的话,默认会返回None.比如:

>>> def proc(x):
...   print x
...
>>> x = proc(‘TEST‘)
TEST
>>> print x
None

如果想使用一个没有返回值的函数的结果时,PYTHON不会告诉你。比如:对一个列表的append()方法的结果赋值,返回的会是一个None.

>>> L  = [1,2,3]
>>> L1 = L.append(4)
>>> L1
>>> print L1
None


#嵌套作用域的循环变量

在进行嵌套函数作用域查找时,处理嵌套的循环改变了的变量要小心。所有的引用将会使用在最后的循环迭代中对应的值。作为替代,请使用默认参数来保存循环变量的值。

【】

【】

【】

【】

【】

【】

【】

【】

【】


Python 点滴 II