《Beginning Python From Novice to Professional》学习笔记八:Abstraction

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

 

你可能感兴趣的:(python,search,Parameters,immutable,Dictionary,variables)