Python函数
2015-06-24 16:09
721 查看
关于函数
1. 一个好的习惯
在函数前面说明:加注释 / 直接写上字符串(作为函数一部分:文档字符串)
def listx(string): 'change string to list' return list(string) print listx.__doc__
2. 函数返回值
return 可以返回值,然而只有return 的效果跟没有return是一样的:None对于简单地变量,将其作为参数传递给函数,函数在内部改变(实际上这里的参数相当于函数内部的变量,然后传参相当于将值赋给函数内部变量)其值不会影响到该变量,同时字符串和元组不能被改变。
def norChange(c): c = 'Change!' change = 'No change' norChange(change) print change #similar process with code above change = 'No change' c = change c = 'Change!' print change而列表不是普通变量
listc = ['no change','no change'] def lChange(l): l[0] = 'Change!' lChange(listc) print listc #similar process with code above listc = ['no change','no change'] l = listc l[0] = 'Change!' print listc所以要想改变原值,则可以使用 return 返回赋值 / 使用列表作为参数。当需要返回两个值的时候,使用元组,列表,字典,都可以
3. 关键字参数
关键字参数可以提供参数的初始化,使用默认值:def greet(greeting = 'Hello', name = 'world'): print '%s,%s!' % (greeting,name) greet() greet(name = 'jessy')
4. 参数不定量的解决方法——收集参数
def print_params(x,y,z = 3,*pospar,**keypar): print x,y,z print pospar # there is no * print keypar # there is no ** print_params(1,2,3,4,5,6,7,foo=1,bar= 2) print print_params(1,2)
其中可以看到,参数 z=3 是关键字参数,根据结果:
没有给收集参数赋值,将会得到一个空元组 / 字典
* 表示收集剩余的值(除了关键字参数),以元组形式表示
** 表示收集剩余的关键字参数,以字典形式表示(参数名为key,参数值为value)
所以针对不同的参数就有了不同的应对方案了。没有关键字参数、收集参数的就一定要给参数赋值
参数的应用:
注意 ** 针对的参数是关键字参数(param=x 的形式)
因为** 会将参数变成字典,而在print 后面可以看到其应用了格式化字符串的字典用法 %(key),而字典没有顺序,只按照关键字来查找值
def x(*num): print num x() # will print () x(1) x(x=1) def y(**num): print num y() # will print {} y(1) y(y=1)
注意上面的 x(x=1) / y(1) 将会出错,因为定义x的时候参数是 *——不能是关键字参数;定义y的时候参数是**——必须是关键字参数
当然,如果使用字典,然后将字典作为参数传过去也是可以的,不过字典前面要加上 **,算是逆向操作(因为传**param到函数里呈现出来是字典),将其变成普通的关键字参数:
def story(**kwds): print kwds print 'Once upon a time, there was a %(job)s called %(name)s'\ % kwds story(job='king', name='Gummy') #dict has no sequence,key can find value story(name='Sir Robin',job='brave knight') params = {'job':'language', 'name':'Python'} #story(params) can't work story(**params) del params['job'] # del: name and reference #story(job='stroke of genius', params) can't work story(job='stroke of genius', **params)
同样,将本来是 tuple 当做参数加上 * 传值回去,也会变成普通的非关键字参数:
def power(x,y,*others): print 'Receive redundant parameters', others return pow(x,y) print power(3,2) print power(y=3,x=2) params = (5,)*2 print power(*params) # tuple is empty listx = [3,4,5,6] print power(*listx)
5. 作用域
vars() ——将变量和值的关系形成字典在函数内部引用全局变量的方法:
globals()['x'] ——返回一个全局变量的字典,通过全局变量名字查找value
global x 内部声明为全局变量
6. 递归函数
因为每次调用函数都会用掉内存,所以足够的函数调用发生后,内存空间不够——程序将以“超过最大深度”结束;递归函数大多数情况下都可以使用循环来代替,且循环可能更加有效率:
计算一个数的n次方,使用递归就需要先进行分析,找到特殊的情况(终止情况)
-对于任意数字 num 来说, num 的零次方是1
-对于任何大于0的数来说,num ^n = num^(n-1) * num
def power(num,n):
if n == 0:
result = 1 # n-1 until n ==0
return result
return num * power(num,n-1)
print power(2,3)使用循环会更简单:
def power(num,n):
result = 1
for i in range(n):
result *= num
return result
print power(2,3)
* reference & inspiration:网易云课程第四周
对于函数,我自己的简便方法便是:先看调用,再看定义。对于递归,我自己的简便方法便是:看return语句,return点就是目的值。
其中调用函数的时候,一定要注意函数是否使用了return语句并且将函数值赋值给了相应的变量的,否则,全局变量是不会改变的。
常见混淆:(其中还有一个概念:局部变量 & 全局变量, 也就是说,函数中的局部变量如果不进行return赋值给全局变量的话,函数外的变量是不会受函数内的变量的影响的)
x = 1 def fun(x): x = 2 fun(x) print x
1. 递归函数
def gcd(m, n): r = m % n if r == 0: return n else: r = m % n return gcd(n, r) print gcd(15, 36)
从这个函数中我获得的是:参数的传递,不仅可以在当前函数中使用参数,还可以将参数继续传递下去,于是直接影响到的就是一道关于斐波那契数列的求解。
斐波那契数列中,需要当前值与前面的一个sum值相加,要获取前面的sum值,就可以使用递归函数传递参数,实现接力棒一样的传递效果。
使用递归函数的时候,因为递归一般是实际问题从后往前(从结果到开始),所以,要注意return的使用(终止点,一般也就是实际问题的初始化),纯粹的调用函数没有 “return” 自己可能会返回value的值是None。
如下:
def bi_search(x, low, high): guess = (low + high) / 2 print lst[guess], x if (x == lst[guess]): return guess elif low > high: return -1 elif lst[guess] > x: bi_search(x, low, guess -1) elif lst[guess] < x: bi_search(x, guess + 1, high)上述函数就是只在前两个判断中 return了。
递归函数中很容易认为,只需要在最后一个结束的地方-需要返回一个具体的值的地方 return 就OK了,但实际上调用递归函数的自身的时候也需要 return。
递归函数跟循环一样,都需要一个终止值,只不过表现得方式不一样。
sub1. 一个斐波那契数列的前10项为 :1, 2, 3, 5, 8, 13, 21, 34, 55, 89,对于一个最大项的值不超过n的斐波那契数列,求值为偶数的项的和。
解:
def fi(fir, second, top, allSum): sum = fir + second if (second % 2 == 0): allSum += second print "now the sum of even num is:", allSum print second #debugging if(sum > top): return allSum #return teminate all function process else: return fi(second, sum, top, allSum) #Just invoke the function without "return" will get value of "None" #http://bbs.csdn.net/topics/390139774 sum0 = fi(1, 2, 100, 0) print "The result is: ",sum0
当然,还有一个递归形式的斐波那契数列是大家认识的、比较常用的:
这种方式是通过数学观察直接得出的程序——
首先,分析斐波那契数列得到规律(一般情况):f(n) = f( n-1 ) + f( n-2 )
其次,分析初始条件(特殊情况:一般都用递归中的最后一个return项,一般用作终止递归的条件):第一、第二项的值均为1
def f(n): if n == 1 or n == 2: return 1 else: return f(n - 2) + f(n - 1) print f(7)
* 说一句题外话:这样的分析实际上与中学学习的构造函数的方式十分的一致,今后也可以考虑使用数学分析的方法来解决程序的问题,毕竟程序语言只是一种工具,而数学思想才是核心
sub2. 非递归斐波那契数列(上面的代码仅仅只是为了介绍关于递归的一种用法,实际上对斐波那契数列的实现还有其他方式)
a. 循环实现:
def fib(n): sum = 0 f1, f2 = 0, 1 while f2 < n: if(f2 % 2 == 0 ): sum += f2 f1, f2 = f2, f1 + f2 return sum print fib(100)
以上为抛砖引玉,实际上斐波那契数列的解决方式还有很多:
Python yield 使用浅析
b. 列表实现:
def fibs(num): result = [0,1] for i in range(num-2): result.append(result[-2]+result[-1]) return result print fibs(10),sum(fibs(10))
sub3. 递归求一个数字n的二进制
对于一个数字n求二进制,基础算法是:数字n / 2,得到余数,得到除数;除数再除以2,得到余数,得到除数...从上到下除,直到除得的数为0或者1,然后余数从下往上依次排列,最后得到的余数排列在最左侧,也就是最大的位数,最先得到的余数排列在最右侧。
那么可以知道:
初始条件(用作终止递归)是除数为0 or 1 —— 实际上每得到一个余数,最后的余数(也就是初始条件返回的值)就向左移一位也就是 x 10;后得到的余数要比之前得到的余数大一个数量级(因为是自底向上排列)
普通规律:后得到的一个数向左移动一位,再加上当前的余数
def binary(n): if( n == 0 or n == 1): return n else: return binary(n / 2) *10 + n % 2
2. 若已知1800年1月1日为星期3,则对于一个给定的年份和月份,输出这个月的最后一天是星期几。
解:
def leapYear(year): if year % 4 ==0 and year % 100 != 0 or year % 400 ==0: return 366 else: return 365 def getMonth(month, year): if month in [1, 3, 5, 7, 8, 10, 12]: return 31 elif month in [4, 6, 9, 11]: return 30 elif month == 2: if leapYear(year) == 365: return 28 else: return 29 else: print 'Error' y = raw_input("year:") m = raw_input("month:") year = int(y) month = int(m) yearCount = 0 monthCount = 0 totalDay = 0 if(year - 1800 > 0): for i in range(1800, year):#bug is "year+1",add excess year,can't count the year you input. yearCount += leapYear(i) print 'year is :', i #debugging for j in range(1, month + 1): monthCount += getMonth(j, year) totalDay = monthCount + yearCount - 1 #coz the known date is 1st print totalDay #debugging result0 = (totalDay % 7 + 3) % 7 print result0
对于星期类的题目,最重要的就是需要算出与给出星期之间所差的天数,在算天数的时候有一个需要注意的是闰年。
算出了所差天数之后,就需要看% 7所差的天数了,7天是一个星期周期,没有余数,就正好与给出的星期数一致。
此题的解法还是跟之前提到过的黑盒思想一样的,分函数解决问题,这个思想还要感谢我的同事ZHT在解决问题时给我的启发。
看到这里,可以发现,我惯用的纠错方法是在合适的位置添加 print。
相关文章推荐
- 举例详解Python中smtplib模块处理电子邮件的使用
- Python核心编程笔记--随机数
- python字符串操作
- Python 实现 淘宝秒杀 聚划算 自动提醒 源码
- 关于python中解决中文字符的问题
- 相同数字
- python ftp操作脚本&常用函数
- Python中file.close()方法的使用与否
- python模拟登录有验证码的网站记录
- python 基本类型list、tuple、dict学习
- python相关的基础知识分享
- Python字符串的encode与decode
- 【Python】Python中的下划线
- python activemq操作: consumer
- Python学习之一【使用Eclipse编写Python】
- golang 和 python 微信菜单设置
- Python模块学习 --- urllib
- MIT python 第二课最后一个例子 求整数的平方数
- python 中面向对象编程简单总结2
- Python程序控制结构