Chinaunix首页 | 论坛 | 博客
  • 博客访问: 12771
  • 博文数量: 5
  • 博客积分: 240
  • 博客等级: 二等列兵
  • 技术积分: 75
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-02 16:45
文章分类

全部博文(5)

文章存档

2012年(5)

我的朋友

分类: Python/Ruby

2012-08-31 10:42:58

6 抽象
6.1 懒惰即美德
eg: fibs=[0,1]
num=input('how many numbers do you want?')
for i in range(num-2):
fibs.append(fibs[-2]+fibs[-1])
print fibs
如果想要这个功能做其他事,并不需要重写同样的循环,而是使用函数
6.2 抽象和结构
抽象可以节省工作量,还可以让人读懂关键 ,计算机处理精确而具体的指令,但人不同。
比如:下载网页,计算频率,打印每个单词的频率
page=download_page()
freqs=computer_frequencies(page)
for word,freq in freqs:
print word,freq
虽然没有明确说怎么做到的,但代码读完知道程序做了什么,具体的细节应该在其他地方写出(即独立的函数定义中)

6.3 创建函数
函数可以调用(可以包含参数,即放在圆括号内的值),它执行某种行为并返回一个值,内建的callable函数可以用来判断函数是否可以调用
eg: import math
x=1
y=math.sqrt
print callable(x) #False
print callable(y) #True
定义函数:使用def
eg: def hello(name):
return 'Hello,'+name+'!'
print hello('world') #Hello,world!
def fibs(num): #6.1中例子转成函数
result=[0,1]
for i in range(num-2):
result.append(result[-2]+result[-1])
return result
print fibs(10)
return语句很重要,是用来从函数中返回值的
6.31 记录函数
如果想要给函数写文档,让后面使用该函数的人能理解的话,可以直接加入注释。另外可以直接写字符串,比如在def后面或者模块/类的开头,具体内容见第7,10章。如果在函数开头写字符串,它就会作为函数的一部分进行存储,称为文档字符串
eg: def square(x):
'Calulates the square of the number x'
return x*x
文档字符串可以按如下方式访问:
>>>square.__doc__
__doc__是函数属性,详见第7章,属性中的__表示它为特殊属性,详见第9章
内建help函数也可以访问:
help(square) #square(x)
    # Calulates the square of the number x
6.32 并非真正函数的函数
python有些函数并不返回任何东西,在其他语言(比如Pascal)中,这类函数称为过程
eg: def test():
print 'this is printed'
return
print 'this is not'
x=test() #this is printed
print x #None
这里return只起到结束函数作用,'this is not'没有被打印,x为None,即当不需要返回值的时候,返回None

6.4 参数魔法
6.41 值从哪里来
在def语句中函数名后的变量通常叫函数的形式参数,而调用函数的时候提供的值是实际参数
6.42 我能改变参数么
函数内为参数赋新值不会改变外部任何变量的值
eg: def change(n):
n='Mr.A'
name='Mr.B'
change(name) #此处传参了,即n=name
print name #Mr.B
参数存储在局部作用域内(local scope)
字符串,元组等是不可变的,但如果列表做为参数时,
eg: def change(n):
n[0]='Mr.C'
name=['Mr.A','Mr.B']
change(name) #此处传参了,即n=name
print name #Mr.C,Mr.B
和上例不同,此处参数被改了,当两个变量同时引用一个列表时,即修改了
如何防止这种情况:复制列表副本
eg: def change(n):
n[0]='Mr.C'
names=['Mr.A','Mr.B']
n=names[:]
change(names[:])
print names #['Mr.A', 'Mr.B']
1.为什么我想要修改参数
使用函数改变数据结构(列表、字典)是将程序抽象化的好方法
eg: storage={}
storage['first']={}
storage['middle']={}
storage['last']={}
icon='Lana Del Rey'
storage['first']['Lana']=[icon]
storage['middle']['Del']=[icon]
storage['last']['Rey']=[icon]
storage['middle']['Del']
print storage['middle']['Del'] #['Lana Del Rey']
icon1='Anne Del Rey'
storage['first'].setdefault('Anne',[]).append(icon1)
storage['middle'].setdefault('Del',[]).append(icon1)
storage['last'].setdefault('Rey',[]).append(icon1)
print storage['middle']['Del'] #['Lana Del Rey', 'Anne Del Rey']
2.如果我的参数不可改变
函数只能修改参数对象本身,但如果参数本身不可变,比如数字,这时候只能从函数中返回你需要的值
eg: def inc(x):return x+1
foo=10
foo=inc(foo)
print foo #11
如果真想改变参数,只能将值放在列表中:
eg: def inc(x):x[0]=x[0]+1
foo=10
inc(foo)
print foo #11
6.43 关键字参数和默认值
目前所有使用的参数都是位置参数,因为它们的位置很重要,本节引入的这个功能可以回避位置问题,当习惯后会发现程序规模越大,它们的作用也就越大
eg: def hello_1(greeting,name):
print '%s,%s!' % (greeting,name)
def hello_2(name,greeting): 
print '%s,%s!' % (name,greeting)
hello_1('hello','world') #hello,world!
hello_2('hello','world') #hello,world!
有时候参数的顺序是很难记住的,为了让事情简单,可以提供参数名字:
eg: hello_1(greeting='hello',name='world') #hello,world!
这类使用参数名提供的参数叫做关键字参数,主要作用在于可以明确每个参数的作用,可以避免如下情况:
eg: store('Mr.Brainsample',10,20,13,5)
可以变成:
eg: store(patient='Mr.Brainsample',hour=10,minute=20,day=13,month=5)
关键字参数最厉害的地方在于可以在函数中给参数提供默认值:
eg: def hello_3(greeting='hello',name='world')
print '%s,%s!' % (greeting,name)
hello_3() #hello,world!
hello_3('greetings') #greetings,world!
hello_3('what','why') #what,why!
6.44 收集参数
让用户提供任意数量的参数:store(data,name1,name2,name3)
eg: def print_params(*params):
print params
print_params('testing','test','ttt') #('testing', 'test', 'ttt')
print_params(1,1,1,2,3) #(1, 1, 1, 2, 3)
def print_params_2(title,*params): #*表示收集其余的位置参数
print title
print params
print_params_2('testing','test','ttt')
print_params_2('nothing') #如果不提供任何元素,就是空元组
print_params_2('hmm...',something=42) #报错,无法处理关键字参数
def print_params_3(**params):
print params
print_params_3(x=1,y=2,z=3) #{'x'=1,'y'=2,'z'=3},返回的是字典而不是元组
6.45 反转过程
可以将参数收集为元组和字典,如果使用*和**,可以执行相反的操作
eg: def add(x,y):
return x+y
params=(1,2)
print add(*params) #3
def hello_3(greeting,name):
print '%s,%s!' % (greeting,name)
params={'name':'Sir Robin','greeting':'Well met'}
hello_3(**params) #Well met,Sir Robin!
在定义或调用函数时使用*仅传递元组和字典
eg: def with_stars(**kwds):
print kwds['name'],'is',kwds['age'],'year old'
def without_stars(kwds):
print kwds['name'],'is',kwds['age'],'year old'
args={'name':'Miss A','age':25}
with_stars(**args) #Miss A is 25 year old
without_stars(args) #Miss A is 25 year old
如上例,*只在定义函数(允许使用不定数目的参数)或者调用(分隔字典或序列)时才有用
6.46 练习使用参数
def story(**kwds):
return 'Once upon a time,there was a %(job)s called %(name)s.' %kwds
print story(job='king',name='Gumby') #Once upon a time,there was a king called Gumby.
print story(name='Linus',job='engineer') #Once upon a time,there was a engineer called Linus.
params={'name':'Mary','job':'singer'}
print story(**params) #Once upon a time,there was a singer called Mary.
del params['job']
print story(job='dancer',**params) #Once upon a time,there was a dancer called Mary.

def power(x,y,*others):
if others:
print 'received redundant parameters:',others
return pow(x,y)
print power(30,3,'xx') #received redundant parameters: ('xx',) \n27000
print power(1,1) #1
params=(5,)*2 #5,5
print power(*params) #3125
def interval(start,stop=None,step=1):
'Imitates range() for step > 0'
if stop is None:
start,stop=0,start
result=[]
i=start
while i < stop:
result.append(i)
i+=step
return result
print interval(10) #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print interval(11,20) #[11, 12, 13, 14, 15, 16, 17, 18, 19]
print interval(11,20,2) #[11, 13, 15, 17, 19]
print power(*interval(3,7,3)) #729

6.5 作用域
在执行x=1的赋值语句后,名称x引用值1,很像字典,键引用值,但变量和所对应的值用的是个‘不可见’的字典,但内建vars函数可以返回这个字典。
eg: x=1
scope=vars()
print scope['x'] #1
scope['x']+=1
print x #2
一般而言vars返回的字典是不可修改的,这类“不可见”字典叫做命名空间或者作用域
除了全局作用域外,每个函数调用都会创建一个新的作用域
函数内的变量称为局部变量,一般而言,函数内读取全局变量没有问题,但是如果局部变量或者参数名和全局变量名称相同的话,就无法直接访问,可以使用globals函数获取全局变量
eg: def combine(params):
print params+globals()['params']
params='doit'
combine('just') #justdoit
重新绑定全局变量(使变量引用其他新值)如果在函数内将值赋予一个变量,会自动变成局部变量,如何才能变成全局变量
eg: x=1
def change_global():
global x
x=x+1
change_global()
print x #2
嵌套作用域:将一个函数放在另一个里面
eg: def foo():
def bar():
print "hello world"
bar()
嵌套一般不怎么有用,但有一个突出应用,如需要用一个函数“创建”另一个:
eg: def multiplier(factor):
def multipyByFactor(number):
return number*factor
return multipyByFactor
double=multiplier(2)
print double(5) #10
test=multiplier(3)
print test(3) #9
print multiplier(5)(4) #20
6.6 递归
递归简单说就是引用自身
无穷递归:类似于while true开始的无穷循环
eg: def recursion():
return recursion()
有用的递归应包含:1.当函数直接返回值时有基本实例(最小可能性问题);2.递归实例包括1个或者多个最小部分的递归调用
6.61 两个经典:阶乘和幂
阶乘:n*(n-1)*(n-2)*...*1
普通实现:
def factorial(n):
result=n
for i in range(1,n):
result*=i
return result
print factorial(5) #120
递归实现:
def factorial_r(n):
if n==1:
return 1
else:
return n*factorial_r(n-1)
print factorial_r(1) #1
print factorial_r(5) #120
幂:
普通实现:
def power(x,n):
result=1
for i in range(n):
result*=x
return result
递归实现:
def power(x,n):
if n==0:
return 1
else:
return x * power(x,n-1)
递归更易读,而循环比较高效
6.62 二元查找
标准库的bisect模块可以非常有效的实现二元查找
阅读(474) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~