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.创建函数
fibs(10) ---> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
2.Documenting Functions - 方便他人理解
可以用#加以注释,但也可以在函数名后直接加上String,即可成为函数的一部分(docstring),可以用__doc__访问(此机制有点类似于Matlab)
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作为参数传入时,在函数内部改变其形参值不会影响实参的值。
try_to_change(name)
name ---> 'Mrs. Entity'
但是可更改的(mutable)元素,如List、Dictionary
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),即参数的顺序位置是重要的。
通过在传入参数时带上参数的关键字可以忽略这种顺序位置(但尽量不要这样写)
hello_4('Mars', punctuation='.')
#'Mars'没有带上关键字name,但因为它在第一个,因此被认为是传给name的
---> Hello, Mars.
5.参数Collection(参数个数的不确定化)
如下的例子很好地说明了这一概念:
但是此时参数不可以使用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'}
最后看一个综合示例:
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'}
两段对比函数代码:
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.
如果在某个作用域中有变量与全局的某变量重名,可以用全局引用的方法,而且此时可以更改全局变量
以下代码可实现同样的效果:
《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
再来个最经典的阶乘示例:
更经典的二分查找示例(^_^)
#测试
seq = [34, 67, 8, 123, 4, 100, 95]
seq.sort() #bisect模块中有标准的二分查找法实现
search(seq, 34) ---> 2