Python: First Glimpse
时间:2010-08-16 来源:贺韬
Python: First Glimpse
初学Python,做了写笔记,于是分享之。对C++程序员来说,第一个新颖有趣的地方是什么?
for循环
for有什么不一样?
for…in遍历sequence中的元素
sequence是什么呢?
1. tuple: 圆括号()
2. list: 方括号[]
3. generator:相对于没有中括号的list,每次产生一个iterator
generator是什么?
使用yield抛出iterator的function返回值类型为generator
1. 在函数中使用yield 用来抛出iterator
2. 从底层来看,相当于自动化生成了next()函数,并保存对象状态
举例:
l sum(i*i for i in range(10))
l set(word for line in page for word in line.split())
l list(data[i] for i in range(len (data)-1,-1,-1))
l (i *i for i in a if i >3)
l 可以理解成:没有中括号的列表
通常yield和外部的for搭配着使用
举例:
¡ def reverse(data):
¡ for index in range(len(data)-1,-1,-1):
¡ yield data[index]
¡ for char in reverse("golf"): print char,
列表推导式是什么?
即利用for + sequence来产生列表的一种方法。
例如:
[3*x for x in vec if x>3]
其余的部分呢?
请查看python绝对简明教程
http://wiki.woodpecker.org.cn/moin/PyAbsolutelyZipManual
函数式编程与数据为中心
函数式编程的最重要的概念是什么呢?
1. sequence:体现着数据为中心
2. 函数
a) 匿名函数,lambda函数
b) 函数对象,闭包
为什么说sequence是重要的概念?
1. 且看map函数:map(function,sequence,[sequence...])
2. 再看reduce函数:reduce:reduce(function,sequence,[init])
3. 最后看filter函数:filter(function,sequence)
这里所有的数据都是放在sequence中的,sequence相当于所有数据的通用容器。这也是数据为中心的体现。
而函数就直接通过map,reduce,filter作用在数据上,而弱化具体的控制流。
与数据为中心相对应的概念是什么?
以数据为中心,关注点在数据(sequence)以及操作(函数对象)
与之对应:
面向过程的程序设计,关注点在控制流。
面向对象的程序设计,关注点在微系统实体的建模。
以数据为中心,我们就要弱化对控制流的关注。
把控制流以及算法封装在函数对象内部。
这里也插一个题外话,GNU linux的设计思想,在shell层面,也是以数据为中心。
GNU小工具 ——》 函数对象
pipe,字符流,文件流 ——》 sequence
这样具体的算法和控制流,就被封装在GNU似的小工具中。
数据通过pipe,字符流,文件流,被GNU小工具转换着。
类型与对象
万物皆对象 这不是扯么?
这里的对象其实没有几个,请看下图
(出处:http://wiki.woodpecker.org.cn/moin/PyTypesAndObjects)
对象也就两种:(说万物皆对象,是聪明人在忽悠人,逃避问题。)
1. type对象(经type()函数返回<type 'type'>的对象)
a) 图中第一,二列
2. non-type对象(经type()函数返回types对象(例如list)的对象)
a) 图中第三列
图中两种线:
1. “是——的类” (图中实线)
a) 由继承关系括号指定
b) 由__bases__查看
c) 只有类对象才有__bases__属性
2. “是——的实例”(图中虚线)
a) 由__metaclass__指定
b) 由__class__查看
如果让我来定义一个新的type对象:
class mylist(object):
__metaclass__ = type
题外话
function对象(经type()函数返回<type ‘function'>的对象)
实际上是一种
1. 定义了__call__()函数
2. 通过def简化了“修改__clas__()函数”的过程,直接产生对象一枚
class myfunction(object):
def __init__(self, n):
self.n = n
def __call__(self, x):
self.n += x
return self.n
例子:
>>> def foo():
a=[0]
a[0]=datetime.datetime.now()
def inner():
print a[0]
return inner
>>> a=foo()
>>> b=foo()
>>> a()
2010-08-16 00:07:05.033000
>>> b()
2010-08-16 00:07:12.983000
#可见a,b是两个不同对象
>>> type(a)
<type 'function'>
>>> type(b)
<type 'function'>
#可见a,b都是function类的实例
Mutable vs Imutable
数字、字符串、tuple类型是不可变类型
字典与列表是可变类型(Mutable)
装饰器decorator
http://www.ibm.com/developerworks/cn/linux/l-cpdecor.html
概要
以函数作为输入,返回另外一个函数
@A
def B:pass
等价于
def B:pass
B=A(B)
例子1
from time import time
#测试运行时间
def cost_time(func):
def result(*args,**dic):
beign=time()
func(*args,**dic)
print "cost time : ",time()-beign
return result
@cost_time
def show(n):
for x in range(n):print x
例子2
def arg_sayer(what):
def what_sayer(meth):
def new(self, *args, **kws):
print what
return meth(self, *args, **kws)
return new
return what_sayer
def FooMaker(word):
class Foo(object):
@arg_sayer(word)
def say(self): pass
return Foo()
foo1 = FooMaker('this')
foo2 = FooMaker('that')
print type(foo1),; foo1.say()
# prints: <class '__main__.Foo'> this
print type(foo2),; foo2.say()
# prints: <class '__main__.Foo'> that
惯用法
¡ 通常使用三层的函数来作为decorator
¡ 这样就可以通过参数来配置装饰器了
def arg_sayer(what):#返回用what配置的装饰器函数
def what_sayer(meth):#meth通常是被装饰的函数
def new(self, *args, **kws):#具体如何装饰meth
print what
return meth(self, *args, **kws)
return new
return what_sayer
@arg_sayer(word)
def say(self):pass
decorator最典型的应用是什么呢?
AOP
l 函数参数类型多态
l 跟踪
l 日志
l 存储、缓存
l 线程锁定
l 输入输出重定向
l 认证
l 权限检查
l 检查参数
l 加锁
python不支持函数的重载,那有什么解决方案呢?
1. 默认参数
2. 指定参数
3. 自省判断参数类型分别处理
a) C++重载其实也是对参数类型显式coding
b) C++重载把同一个函数写成不同的函数体,有不便理解之处
c) C++重载语义暗含在语言中,可读性低,不够pythonic。
重载例子:优雅
注意:这里分离了数据处理的代码与重载处理的代码
def elementwise(fn):#让fn可以处理sequence与element两种类型
def newfn(arg):
if hasattr(arg,'__getitem__'): # is a Sequence
return type(arg)(map(fn, arg))
else:
return fn(arg)
return newfn
@elementwise
def compute(x):
return x**3 - 1
print compute(5) # prints: 124
print compute([1,2,3]) # prints: [0, 7, 26]
print compute((1,2,3)) # prints: (0, 7, 26)
闭包
secrets_of_javascript_closures.pdf
http://en.wikipedia.org/wiki/Closure_(computer_science)
闭包最核心的概念是什么呢?
函数对象(除此之外,再无它)
函数对象带来了什么?
函数的状态!
Python的函数与C++的函数有什么区别?
C++中的函数
1. 永远不变的,唯一实例的(像我们的上帝一样)。
2. 调用函数就相当于跳转到唯一函数体中。
Python中的函数,每申明一次函数,就会
1. 产生一个函数对象
2. 维系这个函数对象的变量环境
函数对象的变量环境有什么用呢?
这个闭包的精华之处:
1. 对于同一段函数定义代码,我们产生多个不同的函数对象
2. 存储、改变函数不同对象的变量
3. 从而让同一个函数的不同对象表现出不同的行为
这么抽象,举个例子可以么?
def addgen():
y=[0] #2.7版本中,只支持list类型的函数状态
def sety0(yy):
y[0]=yy
def addy (x):
return x+y[0]
return sety0,addy
通常用在什么场合呢?
1. 回调函数
a) 每次回调,改变其状态。
b) 调用不同的次数,传入不同的参数,函数表现不同。
c) 多个回调函数对象,状态互不干涉
2. 事件响应函数
a) 每次响应,改变其状态。
b) 响应不同的次数,传入不同的参数,函数表现不同。
c) 多个事件响应函数对象,状态互不干涉
与数据为中心的编程的关系呢?
此时,函数已经具有了对象的两个特征:
1. 多实例
2. 有状态
不过函数依然是函数,依然可以作为map,reduce,filter的输入,
依然可以用作数据为中心的编程。
总结
以上,是我初学Python遇到的一些难点,分享之,希望各位鸟都来拍砖斧正。