PythonCookbook第七章(函数)

函数(前面已经看过了,这次把博客补上,书中讲的内容并不难)

用def语句定义的函数是所有程序的基石。书中介绍默认参数、可接受任意数量参数的函数、关键字参数、参数注解以及闭包。

7.1 编写可接收任意数量参数的函数

问题:

编写一个可接收任意数量参数的函数

解决方案:

*args,**kwargs

def avg(first, *args):
    # args 返回的是元祖
    return (first + sum(args)) / (1 + len(args))

import html
def make_element(name, value, **kwargs):
    # kwargs返回的是字典
    keyvals = [' %s="%s"' % item for item in kwargs.items()]
    attr_str = ''.join(keyvals)
    element = '<{name} {attrs}>{value}</{name}>'.format(
        name=name,
        attrs = attr_str,
        # 替换value中的<>符号
        value = html.escape(value)
    )
    return element

if __name__ == '__main__':
    print(avg(12, 3, 4, ))
    print(avg(12, 3, 2, 32, 34, 3))

    print(make_element('item', 'Albatross', size='large', quantity=6))
    print(make_element('p', '<spam>'))
    
/usr/local/bin/python3.7 /Users/shijianzhong/study/PythonCookbook/chapter_7/t1_2.py
6.333333333333333
14.333333333333334
<item  size="large" quantity="6">Albatross</item>
<p ><spam></p>

Process finished with exit code 0

 讨论:

在函数定义中,以*打头的参数只能作为最后一个位置参数出现,而以**打头的参数只能作为最后一个参数出现。

不要犯初级的错误了,默认参数的位置,一定要在非默认参数的后面,今天这个小问题尽然卡住我了,丢人丢到家了。

7.2 编写只接收关键字参数的函数

问题

只通过关键字形式接收特定的参数

解决方案

# 传入的参数中,无论多少,第一个maxsize接收第一个参数,后面所有的位置参数全部*接收
# 想给*后面的参数赋值,必须通过关键形式.
def recv(maxsize, *, block):
    ...


def minium(*values, clip=None):
    m = min(values)
    # 如果默认不是空
    if clip is not None:
        m = clip if clip < m else m
    return m


if __name__ == '__main__':
    print(minium(1, 2, 3, 4, clip=5))

    print(recv(1024, block=True))
    print(recv(1024, True))

 讨论

这个叫kewword-only参数常常是一种提高代码可读性的好方法。

7.3 将元数据信息附加到函数上

讨论:

在函数上面添加一些元信息

解决方案:

def add(x:int, y:int) -> int:
    return x+y


if __name__ == '__main__':
    print(help(add))
    # 通过annotations属性输出信息
    print(add.__annotations__)

 讨论:

一般没什么用,我也基本不会用,可以在验证参数的时候用一下,但装饰器更好用。

7.4 从函数中返回多个值

问题:

我们想从函数中返回多个值

解决方案:

返回一个元祖

def myfun(x, y, z):
    # 元祖的定义靠逗号
    return x, y, z


if __name__ == '__main__':
    res = myfun(1, 2, 3)
    print(res)
    print(type(res))
/usr/local/bin/python3.7 /Users/shijianzhong/study/PythonCookbook/chapter_7/t3_4.py
(1, 2, 3)
<class 'tuple'>

 讨论:

没啥讨论的

7.5 定义带有默认参数的函数

问题

定义一个函数或者方法,其中由一个或者多个参数是可选的,并且带有默认值

解决方案:

# 普通默认参数
def spam1(a, b=42):
    print(a, b)

# 定义参数为可变容器的话
def spam2(a, b=None):
    if b is None:
        b = []

_no_value = object()

# 验证参数b有没有填写, 可以赋值一个object实例
def spam3(a, b=_no_value):
    if b is _no_value:
        print('No b value supplied')

if __name__ == '__main__':
    spam3(1)

 讨论:

定义带有默认参数的函数看似容易,但其实并不像看到的那么简单,很有道理。

流畅的Python书中说过,Python的函数传参其实使共享传参,在函数定义好以后,所有的函数参数就好比函数的属性,绑定在函数上面。

In [21]: x = 42                                                                                                                                                                         

In [22]: def spam(a, b=x): 
    ...:     print(a,b) 
    ...:                                                                                                                                                                                

In [23]: spam(1)                                                                                                                                                                        
1 42

In [24]: x = 50                                                                                                                                                                         

In [25]: spam(1)                                                                                                                                                                        
1 42

In [26]: import inspect 

In [31]: inspect.getfullargspec(spam)                                                                                                                                                   
Out[31]: FullArgSpec(args=['a', 'b'], varargs=None, varkw=None, defaults=(42,), kwonlyargs=[], kwonlydefaults=None, annotations={})

 这里x属于不可变参数,定义函数的时候,b也指向了42值,当修改x的时候,并不影响42的值,所以函数的内部属性不会变。

In [32]: def spam(a, b=[]): 
    ...:     print(b) 
    ...:     return b 
    ...:  
    ...:                                                                                                                                                                                

In [33]: x = spam(1)                                                                                                                                                                    
[]

In [34]: x                                                                                                                                                                              
Out[34]: []

In [35]: x.append(99)                                                                                                                                                                   

In [36]: x                                                                                                                                                                              
Out[36]: [99]

In [37]: spam(1)                                                                                                                                                                        
[99]
Out[37]: [99]

In [38]:  

 上面一个定义了可变参数为函数属性的例子,这样使非常不可取的,只要脚本执行中,这个函数无论什么时候执行,这个可变参数都会根据函数的执行而发生变化,所有的函数执行都将共享这个可变参数,这是不对的。

def spam2(a, b=None):
if b not b:
b = []

 在这个函数里这样定义b是否为None是不对的,因为'',[],空数据not以后都会变True

最后的那个ocject()默认值来测试是否提供了参数,还是比较有意思的,object()作为Python中所有对象的基类而存在,这玩意唯一的用处就是检测相等性。

7.6 定义匿名或内联函数

问题:

需要为高阶函数比如(sort)操作,但不想写def

解决方法:

lambda函数

In [44]: add = lambda x, y: x+y                                                                                                                                                         

In [45]: add(2,3)                                                                                                                                                                       
Out[45]: 5

In [46]: add([1,2],[3,4])                                                                                                                                                               
Out[46]: [1, 2, 3, 4]

In [47]: name = ['sidian','wudian','liusidian']                                                                                                                                         

In [48]: sorted(name,key=lambda x: x[0])                                                                                                                                                
Out[48]: ['liusidian', 'sidian', 'wudian']

In [49]:  

 讨论:

lambda不写复杂的逻辑

7.7 在匿名函数中绑定变量的值

问题:

我们利用lambda表达式定义了一个匿名函数,但是希望可以在函数定义的时候完成对特定变量的绑定。

解决方案:

这个还是蛮有意思的,匿名函数在冒号前面的参数,可以直接读取外部的全局变量参数,当匿名函数执行的时候,全部变量是什么他就读取什么。

这个跟定义好的函数,函数内部读取外部参数一样的逻辑。

In [49]: x = 10                                                                                                                                                                         

In [50]: a = lambda y: x+y                                                                                                                                                              

In [51]: x= 20                                                                                                                                                                          

In [52]: b = lambda y: x+y                                                                                                                                                              

In [53]: a(30)                                                                                                                                                                          
Out[53]: 50

In [54]: b(30)                                                                                                                                                                          
Out[54]: 50

In [55]: 

 没有绑定的情况,如果想绑定,可以填写默认参数一样。

In [55]: x = 10                                                                                                                                                                         

In [56]: b = lambda y,x=x: x+y                                                                                                                                                          

In [57]: x= 20                                                                                                                                                                          

In [58]: a = lambda y,x=x: x+y                                                                                                                                                          

In [59]: a(20)                                                                                                                                                                          
Out[59]: 40

In [60]: b(20)                                                                                                                                                                          
Out[60]: 30

In [61]:       

 讨论:

这个还是蛮有意思的,lambda函数还是非常好用的,但流畅的Python里面好像不是很推荐,不知道为什么。

In [61]: func = [lambda x: x+n for n in range(5)]                                                                                                                                       

In [62]: for f in func: 
    ...:     print(f(0)) 
    ...:                                                                                                                                                                                
4
4
4
4
4

 这个是在执行时,读取变量n,那时候n就是4

In [66]: func = [lambda x,n=n: x+n for n in range(5)]                                                                                                                                   

In [67]: for f in func: 
    ...:     print(f(0)) 
    ...:                                                                                                                                                                                
0
1
2
3
4

 这个是在定义的匿名函数的时候设置参数

7.8 让带有N个参数的可调用对象以较少的参数形式调用

问题

我们有一个可调用的对象可能会以回调函数的形式同其他的Python代码交互。但是这个可调用对象的参数过多,如果直接调用的话会产生异常。

解决方案:

用funtools.partail,但我感觉其实lambda就够了,我的感觉,lambda更加好理解,两个返回的都是函数,但lambda学精了,感觉太强大了

猜你喜欢

转载自www.cnblogs.com/sidianok/p/12319811.html
今日推荐