`

python学习笔记7——第六章 抽象

阅读更多

第六章  抽象

1. 函数 def functionname(para):

   用于def后面的' '添加文档字符串,相当于注释#

>>> def fibs(num):
	'Get fibonaqi 这里的字符串用来注释,一般说明函数功能'
	result = [0, 1]
	for i in range(num - 2):
		result.append(result[-1] + result[-2])
	return result

>>> fibs(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

 

   使用help()可以查询函数的文档字符串

>>> help(fibs)
Help on function fibs in module __main__:

fibs(num)
    Get fibonaqi 这里的字符串用来注释,一般说明函数功能

>>> 

 

   return后不加值,只表示函数的结束,而没有返回值,这样可以避免应该返回序列时,意外返回None

>>> def test():
	print "test"
	return  #无返回值
	print "hello" #不执行

	
>>> x = test()
test

 

2. 参数对外部变量影响

   函数内给参数赋值,不会改变外部变量的值,参数存储在局部作用域中

>>> def try_to_change(n):
	n = 3

	
>>> a = 4
>>> try_to_change(a)  #虽然在函数内部重新赋值,但外部不变, n和a实际上是完全不同的变量,
>>> a
4

 

   但是对于可改变的数据结构,如列表,参数的内部赋值会改变外部变量的值

   内部参数与外部变量指向同一个列表,所以会被修改

   若不想改变外部列表,可以传进一个副本

>>> def change(n):
	n[0] = 'test'

	
>>> names = ['Hello', 'world']
>>> change(names)
>>> names
['test', 'world']
>>>       #采用普通方法进行模拟
>>> names = ['Hello', 'world']
>>> n = names #模拟传参
>>> n[0] = 'test' #改变列表
>>> names
['test', 'world']

 

   完整示例——存储名字,并能用名字、中间名或姓来查找联系人

   若名字为'Magus Lie Hetland'存储格式类似

   data = {

                  'first': { 'Magus': 'Magus Lie Hetland'},

                  'middle': {'Lie': 'Magus Lie Hetland'},

                  'last': {'Hetland': 'Magus Lie Hetland'}

                }

   注意insert(index,value)函数,在列表的索引位置插入值

>>> def init(data):  #data作为存储表,初始化
	data['first'] = {}
	data['middle'] = {}
	data['last'] = {}

>>> def store(data, full_name): #存储,将全名存储到表中
	names = full_name.split()  #将名字按空格(即first,middle,last)分开,返回列表,如'Ma Li He'返回['Ma', 'Li', 'He']
	if len(names) == 2: names.insert(1, '')#若无中间名,则插入空来表示中间名['Mr', 'Zha']返回['Mr', '', 'Zha']
	labels = 'first', 'middle', 'last'  #元组
	for label, name in zip(labels, names):  #元组与序列间也可使用zip
		people = lookup(data, label, name)
		if people:
			people.append(full_name)
		else:
			data[label][name] = [full_name] #当键不存在时,自动添加键值对,
                                                                         #但如果输出不存在键对应值,则报错

>>> def lookup(data, label, name): #查找,根据label查找是name的中间人
	return data[label].get(name)

			
>>> MyNames = {}
>>> init(MyNames)
>>> store(MyNames, 'Magnus Lie Hetland')
>>> lookup(MyNames, 'middle', 'Lie')
['Magnus Lie Hetland']
>>> store(MyNames, 'Robin Hood')
>>> store(MyNames, 'Robin Locksley')
>>> lookup(MyNames, 'first', 'Robin')
['Robin Hood', 'Robin Locksley']
>>> store(MyNames, 'Mr. Gumby')
>>> lookup(MyNames, 'middle', '')
['Robin Hood', 'Robin Locksley', 'Mr. Gumby']

 

   例2. 不可变的数字和可改变的参数

>>> def inc(x): return x + 1

>>> foo = 10
>>> inc(foo)
11
>>> foo #外部变量未发生变化
10
>>> foo = inc(foo) #将foo重新赋值
>>> foo
11

 

   使用列表外部变量foo改变了

>>> def inc(x): x[0] = x[0] + 1

>>> foo = [10]
>>> inc(foo)
>>> foo
[11]

 

3. 关键字参数和默认值

   位置:是指根据参数的对应位置传参,如def a(a,b,c):,调用a(1,2,3),1传给a,2传给b,3传给c,这样参数位置容易记混。

   关键字参数,适用于大规模程序,清晰

>>> def hello(name, greeting):
	print '%s, %s!' %(greeting, name)

	
>>> hello('sun', 'Hello')  #位置参数
Hello, sun!
>>> hello(name = 'Sun', greeting = 'Hello')  #关键字参数
Hello, Sun!
>>> hello(greeting = 'Hello', name = 'Sun') #关键字参数,不必关心位置
Hello, Sun!

 

   默认值

>>> def hello(name = 'world', greeting = 'Hello'):
	print '%s, %s!' %(greeting, name)

	
>>> hello()
Hello, world!
>>> hello('Sun')
Hello, Sun!
>>> hello(greeting = 'Hi')
Hi, world!

 

   位置参数与关键字参数混用,将位置参数放在前面。尽量避免这么用,容易引起混乱。

>>> def hello(name, greeting = 'Hello', punc = '!'):
	print '%s, %s%s' %(greeting, name, punc)

	
>>> hello('Sun')
Hello, Sun!
>>> hello('Sun', 'Hi')
Hi, Sun!
>>> hello('Sun', punc = '..')
Hello, Sun..
>>> hello()   #因为name是必须要有,若有默认值,则可没有

Traceback (most recent call last):
  File "<pyshell#385>", line 1, in <module>
    hello()
TypeError: hello() takes at least 1 argument (0 given)
>>> 

 

4. 收集参数——在定义时使用*或**,用来收集参数,允许使用不定数量的参数

   *:收集其余的位置参数并作为元组 返回

>>> def print_params2(title, *params):
	print title
	print params

	
>>> print_params2('Param:', 1, 2, 3)
Param:
(1, 2, 3)  #以元组形式返回
>>> print_params2('Param:') #不提供收集元素时,返回空元组
Param:
()
>>> print_params2('Param:', 1) 
Param:
(1,) #只有一个元素时,仍为元组

 

   **:收集其余的关键字参数并作为字典 返回,可与其他混用

>>> def print_params3(x, y, z = 3, *pospar, **keypar):
	print x, y, z
	print pospar
	print keypar

	
>>> print_params3(1,2,3,4,5,6,7, fool = 1, bar = 2)
1 2 3
(4, 5, 6, 7)
{'fool': 1, 'bar': 2}
>>> print_params3(1,2)
1 2 3
()
{}

 

5. 收集参数的翻转过程——在调用时使用*或**,将参数分配到定义的参数中,用于字典或列表分割时

   用于列表

>>> def add(x,y): return x + y

>>> params = (1,2)
>>> add(*params)
3

 

   用于字典

>>> def hello(name, greeting):
	print '%s, %s!' %(greeting, name)

	
>>> params = {'name': 'Sir Robin', 'greeting': 'Welcome'}
>>> hello(**params)
Welcome, Sir Robin!

 

 

   参数使用实例

#模拟步长大于0的range()
>>> interval(10)
start = 0 stop = 10 step =  1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> def interval(start, stop=None, step=1):
	'Imitates range() for step > 0'
	if stop is None: #若未给stop指定值
		start, stop = 0, start #多个赋值,0赋值给start,start的值赋值给stop
	result = []
	i = start
	while i < stop:
		result.append(i)
		i += step
	return result

#
>>> def story(**kwds):
	return '%(job)s called %(name)s.' %kwds

>>> def power(x, y ,*others):
	if others:
		print 'Received redundant parameters:',others
	return pow(x,y)

#使用
>>> params = {'job':'language','name':'python'}
>>> print story(**params) #调用时分割字典,定义中收集
language called python.
>>> del params['job']
>>> print story(job='test', **params)

>>> power(2,3,'test')
Received redundant parameters: test

>>> params = (5,) * 2 #即(5,5)
>>> power(*params) #先分割,在赋给x,y
3125

 

6.作用域

   x = 1, 将名字x引用到值1上,类似字典

   内建函数vars()返回这个字典

>>> x = 1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 1 #一般情况下,vars()返回的字典不能修改
>>> x
2

 

   局部变量,全局变量

   函数内部访问全局变量,慎用!

>>> def com(para): print para + external

>>> external = 'external'
>>> com('param ')
param external

 

   若全局变量与局部变量名字相同,会被局部变量覆盖,可使用global()类似vars(),获得全局变量的字典

>>> def com(para): print para + globals()['para']

>>> para = 'berry'
>>> com('test ')
test berry

 

   重绑定全局变量,将变量引用到其他新值——函数内部声明全局变量

>>> x = 1
>>> def change_global():
	global x
	x = x + 1

	
>>> change_global()
>>> x
2
 

   嵌套作用域——函数中定义函数,例如闭包

   外部作用域中的变量一般不能被改变,但是用闭包,每次调用外层函数,内部函数都会被重新绑定,也即外部作用域factor每次都有一个新值

>>> def multiplier(factor):
	def multiplyByFactor(number):
		return number * factor
	return multiplyByFactor  #返回一个函数,这时并未调用

>>> double = multiplier(2)  #double是一个函数
>>> double   #double是一个函数
<function multiplyByFactor at 0x0214C6F0>
>>> double(5)  #调用multiplyByFactor(number)
10
>>> multiplier(2)(5) #效果同上
10
 

   7. 递归——每调用一个函数,都会创建一个新的命名空间,意味着当函数调用自身时,实际上调用的是两个不同的函数

    阶乘

>>> def factorial(n):
	if n == 1:
		return 1
	else:
		return n * factorial(n-1)

>>> factorial(5)
120

    幂

>>> def power(x, n):
	if n == 0:
		return 1
	else:
		return x * power(x, n - 1)

	
>>> power(2,3)
8

 

   递归实例——二元搜索

   前提:排好序

   若上下限相同,则那就是数字所在位置,返回;

   否则,找到两者的中间,查找数字是在左侧还是右侧,继续查找数字所在的那半部分。

>>> def search(sequence, number, lower = 0, upper = None):
	if upper is None: upper = len(sequence) - 1
	if lower == upper:
		assert number == sequence[upper]
		return upper
	else:
		middle = (lower + upper) // 2
		if number > sequence[middle]:
			return search(sequence, number, middle + 1, upper)
		else:
			return search(sequence, number, lower, middle)

		
>>> seq = [34, 67, 8, 123, 4, 100, 95]
>>> seq.sort()
>>> seq
[4, 8, 34, 67, 95, 100, 123]
>>> search(seq, 34)
2
 

总结:

元组输出格式化,直接使用键,而不需要加引号

>>> d = {'a':1, 'b':2}
>>> print '%(a)s corresponds to %(b)s.' %d #注意a有括号,无引号
1 corresponds to 2.
 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics