stay hungry stay foolish

python(函数)

常用内置函数

>>> abs(100)
100
>>> abs(-20)
20
>>> abs(12.34)
12.34
>>> max(1, 2)
2
>>> max(2, 3, 1, -5)
3
>>> int('123')
123
>>> int(12.34)
12
>>> float('12.34')
12.34
>>> str(1.23)
'1.23'
>>> str(100)
'100'
>>> bool(1)
True
>>> bool('')
False
>>> hex(100)
'0x64'

定义函数

def my_abs(x):
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x

pass

pass可以用来定义空函数

def fn():
	pass

也可以用来当做占位符

if(x>1):
	pass

导入math库

import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

默认参数

def power(x, n=2):
    print(x,n)

当默认参数是引用时,如果每次调用都使用默认参数,则默认参数引用时不变的

>>> def test(a=[]):
...  a.append(1)
...  return a
...
>>> test()
[1]
>>> test()
[1, 1]
>>> test()
[1, 1, 1]
>>>

可变参数

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuplex

>>> def calc(*numbers):
...     sum = 0
...     for n in numbers:
...         sum = sum + n * n
...     return sum
...
>>> calc(1,2,3)
14
>>>

可以在一个数组前加一个*号将数组变成可变参数

>>> nums = [1, 2, 3]
>>> calc(*nums)
14
>>>

关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

>>> def person(name, age, **kw):
...     print('name:', name, 'age:', age, 'other:', kw)
...
>>> person('lisong','18',sex='man',city='hunan')
name: lisong age: 18 other: {'sex': 'man', 'city': 'hunan'}
>>>

和可变参数类似,也可以先组装出一个dict,然后,用**把该dict转换为关键字参数传进去

>>> other={'sex':'man','city':'hunan'}
>>> person('lisong','18',**other)
name: lisong age: 18 other: {'sex': 'man', 'city': 'hunan'}
>>>

命名关键字参数

命名关键字参数用来限制关键字参数的名字,需要使用一个*号来分割,代表后面的参数为命名关键字参数

>>> def person(name, age, *, city, sex):
...  print(name,age,city,sex)
...
>>> person('lisong',18,sex='man',city='hunan')
lisong 18 hunan man

此时仍然可以使用**把dict转换为关键字参数传进去

>>> other={'sex':'man','city':'hunan'}
>>> person('lisong',18,**other)
lisong 18 hunan man
>>>

参数的组合

>>> def f1(a, b, c=0, *args, **kw):
...     print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
...
>>> f1('a','b','c',d='d',e='e')
a = a b = b c = c args = () kw = {'d': 'd', 'e': 'e'}
>>>
>>> def f2(a, b, c=0, *, d, **kw):
...     print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
...
>>> f2('a','b',d='d',e='e')
a = a b = b c = 0 d = d kw = {'e': 'e'}
>>>

递归函数

def fact(n):
    if n==1:
        return 1
    return n * fact(n - 1)

如果n太大,很容易造成堆栈溢出。其实所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。

上面的fact(n)函数由于return n \* fact(n - 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:

def fact(n):
    return fact_iter(n, 1)

def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)

可以看到,return fact_iter(num - 1, num * product)仅返回递归函数本身,num - 1和num \* product在函数调用前就会被计算,不影响函数调用。

fact(5)对应的fact_iter(5, 1)的调用如下:

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120

尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。