Laziness Is a Virtue --- Real programmers are lazy. Not lazy in a bad way, but in the sense that they don’t do unnecessary work.
1.创建函数
def fibs(num): result = [0, 1] for i in range(num-2): result.append(result[-2] + result[-1]) return result #若不写return或return后面不接变量,则默认返回None
fibs(10) ---> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2.Documenting Functions - 方便他人理解
可以用#加以注释,但也可以在函数名后直接加上String,即可成为函数的一部分(docstring),可以用__doc__访问(此机制有点类似于Matlab)
def square(x): 'Calculates the square of the number x.' return x*x
square.__doc__
---> 'Calculates the square of the number x.'
help (square)
---> Help on function square in module __main__:
---> square(x)
Calculates the square of the number x.
3.参数的可更改性
不可更改的(immutable)元素,如Strings、numbers和tuples作为参数传入时,在函数内部改变其形参值不会影响实参的值。
def try_to_change(n): n = 'Mr. Gumby' name = 'Mrs. Entity'
try_to_change(name)
name ---> 'Mrs. Entity'
但是可更改的(mutable)元素,如List、Dictionary
def change(n): n[0] = 'Mr. Gumby' names = ['Mrs. Entity', 'Mrs. Thing']
change(names)
names ---> ['Mr. Gumby', 'Mrs. Thing']
如果想让List元素传入而不受函数内部的影响,可以做一份拷贝,接上例
change(names[:]) #name[:]会返回一份name的拷贝
names ---> ['Mrs. Entity', 'Mrs. Thing']
最后,如果参数是不可更改的,则函数内部的更改无法(Sorry, but it can’t be done.)解决方案有二:
一、将在内部更改过的参数全部返回(超过一个的话可以用Tuple)
def inc(x): return x + 1
foo = 10
foo = inc(foo)
foo ---> 11
二、将参数打包在一个List中作为参数传入
def inc(x): x[0] = x[0] + 1
foo = [10]
inc(foo)
foo ---> [11]
4.带关键字的参数(Keyword Parameters)和参数默认值
前面所述的参数均为位置性参数(positional parameters),即参数的顺序位置是重要的。
通过在传入参数时带上参数的关键字可以忽略这种顺序位置(但尽量不要这样写)
def hello_4(name, greeting='Hello', punctuation='!'): #顺带说明了参数默认值 print '%s, %s%s' % (greeting, name, punctuation)
hello_4('Mars', punctuation='.')
#'Mars'没有带上关键字name,但因为它在第一个,因此被认为是传给name的
---> Hello, Mars.
5.参数Collection(参数个数的不确定化)
如下的例子很好地说明了这一概念:
def print_params(*params): #此时参数前加了一个*,说明这之后的参数将被看成一个Tuple print params print_params('Testing') #---> ('Testing',) print_params(1, 2, 3) #---> (1, 2, 3) def print_params_2(title, *params): print title, params print_params_2('Params:', 1, 2, 3) #---> Params: (1, 2, 3)
但是此时参数不可以使用Keyword了:
print_params_2('Hmm...', something=42) #解释器会将会报错unexpected keyword argument 'something'
若想使用Keyboard,可以使用以下版本:
def print_params_3(**params): #此时参数前加了两个*,说明这之后的参数将被看成一个Dictionary
print params
print_params_3(name='thy', age=30) #但此时参数不可以像Dictionary一样用number作key
---> {'age': 30, 'name': 'thy'}
最后看一个综合示例:
def print_params_4(x, y, z=3, *pospar, **keypar): print x, y, z, pospar, keypar
print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2)
---> 1 2 3 (5, 6, 7) {'foo': 1, 'bar': 2}
print_params_4(1, 2)
---> 1 2 3 () {}
6.参数解包(5的逆过程)
Tuple的解包:
def add(x, y): return x + y
params = (1, 2)
add(*params) ---> 3
Dictionary的解包:(接5中的print_params_3函数)
params = {'name': 'Sir Robin', 'greeting': 'Well met'}
print_params_3(**params)
---> {'name': 'Sir Robin', 'greeting': 'Well met'}
两段对比函数代码:
def with_stars(**kwds): print kwds['name'], 'is', kwds['age'], 'years old' def without_stars(kwds): print kwds['name'], 'is', kwds['age'], 'years old' args = {'name': 'Mr. Gumby', 'age': 42} with_stars(**args) #---> Mr. Gumby is 42 years old without_stars(args) #---> Mr. Gumby is 42 years old
7.作用域Scoping
内置函数vars()可返回作用域,其结构为Dictionary。
x = 1
scope = vars() #scope为Dictionary,其中包含'x':1这一项
scope['x'] ---> 1
scope['x'] += 1 #仅作为示例,实际中不建议使用
x ---> 2
除了全局作用域之外,每一个函数均会构建自己的一个作用域。
在函数中可以访问全局变量,但不可以更改全局变量
def combine(parameter):
external = 'mark'
print parameter + external
external = 'berry'
combine('Shrub')
---> Shrubmark
external
---> 'berry' #external的全局值未受影响
作者的提醒:■Caution Referencing global variables like this is a source of many bugs. Use global variables with care.
如果在某个作用域中有变量与全局的某变量重名,可以用全局引用的方法,而且此时可以更改全局变量
def combine(parameter): print parameter + globals()['parameter'] globals()['parameter'] = 'thyU' parameter = 'berry' combine('Shrub') #---> Shrubberry parameter #---> 'thyU'
以下代码可实现同样的效果:
x = 1 def change_global(): global x x = x + 1 change_global() x #---> 2
《Python技术参考大全》:LGB规则,名字引用搜寻顺序为Local->Global->Built-in。
8.递归(书上都是说的递归的原理,也没讲什么新的内容,直接贴一点关键内容吧)
A useful recursive function usually consists of the following parts:
A base case (for the smallest possible problem) when the function returns a value directly
A recursive case, which contains one or more recursive calls on smaller parts of the problem
再来个最经典的阶乘示例:
def factorial(n): '非递归版本' result = n for i in range(1,n): result *= i return result def factorial(n): '递归版本' if n == 1: return 1 else: return n * factorial(n-1)
更经典的二分查找示例(^_^)
def search(sequence, number, lower, upper): 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() #bisect模块中有标准的二分查找法实现
search(seq, 34) ---> 2