fluent Python (六)读书笔记

这周由于期末考的压力,读书的进度暂时拖缓了一会。

主要讲讲函数这一节学到的东西吧,因为字符串那一节感觉自己只学了一些概念。

首先是一等对象的定义:

1.在运行时创建

2.能赋值给变量或者数据结构中的元素

3.能作为参数传给函数

4.能作为函数的返回结果


函数就是一等对象,也就是说上面所有的点它都能做得到。

5.1 把函数看成对象

    1.函数名.__doc__读取函数的文档信息

    2.函数名字其实就和普通变量没什么2样,只是调用函数时得加括号,这是因为它实现了callable方法。也就是说我们完全可以把现有的函数名称赋值给某个变量,那那个变量能更这个函数做同样的工作。


5.2 高阶函数

    1.sort 和 sorted 的key 方法

    2.列表推导是在某种程度上可以代替map + filter 的组合的

list(map(factorial, filter(lambda n: n%2, range(6))))

    如上面这个例子,先过滤掉偶数, 再对剩下的元素进行阶乘运算。


    3.用reduce 和 add代替sum

    sum(list1)

    reduce(add, list1)

    以上两句话是等价的

    reduce曾经是内置的,现在在functools 里


    5.3匿名函数

    lambda 语句, 但是其中不能赋值也不能用while ,try

   

    5.4可调用对象

    调用运算符()

    callable()函数可判断一个对象能否被调用,返回值是一个bool

    想能用() 实现 __call__就好了

   

    5.5 用户定义的可调用类型

    在这里我们将实现一个通过类创造出的实例能够加调用运算符的例子

   

import random

class BingoCage:
    def __init__(self, items):
        self.data = list(items)
        random.shuffle(self.data)

    def pick(self):
        try:
            return self.data.pop()
        except:
            raise LookupError

    def __call__(self):
        return self.pick()

    以上会让我们在 调用 实例 + ()时能随机Pick一个值

   

    5.6    函数内省  

    之前我们说过,函数是一类对象,那这种对象和我们平常定义的类有哪些不同呢?

    

def a ():
pass

class B :
pass

b = B()
print ( set ( dir (a)) - set ( dir (b)))


    5.7 从定位参数到仅限关键字参数

体会一下python灵活的参数处理机制

用*args, **attrs 展开可迭代对象,并映射到单个参数

接下来看如何简洁地写出制作html标签的做法

def tag ( name , * content , cls = None , ** attrs ):
if cls is not None :
attrs[ 'class' ] = cls
if attrs:
attr_str = '' .join( ' %s =" %s "' % (attr, value) for attr, value in sorted (attrs.items()))
else :
attr_str = ''
if content:
return ' \n ' .join( '< %s%s > %s %s >' % (name, attr_str, c, name) for c in content)
else :
return '< %s%s />' % (name, attr_str)


print (tag( 'br' ))
print (tag( 'p' , 'hello' ))
print (tag( 'p' , 'hello' , 'world' ))
print (tag( name = 'p' , 'hello' , id = 33 ))
#通过拆字典
my_tag = { 'name' : 'img' , 'src' : 'sunset.jpg' , 'cls' : 'dramed' }
print (tag( ** my_tag))

(目前还不是太理解为什么*content这个参数不能以content=...的方式来接收参数,
如果这样操作的话,实参将被归在**attrs 那一类)

不通过标准库来实现记录函数的签名
1.__defaults__
查看函数的参数默认值

2.__code__.co_varnames
查看函数的参数和在内部定义的一些变量

3.__code__.co_argcount
查看参数数量

接下来通过inspect来更好地提取函数的信息
from inspect import signature
sig = signature(函数)
sig.parameters.items()里储存了名字和参数组成的元组
用.default 去访问参数的默认值
用.kind 去访问参数的类型, 以上都是基于参数而不是名字的操作

通过绑定的形式
新函数 = signature(原函数).bind(**args)
这时这个新函数变成了绑定某些信息的信息体
可以用for name, value in 新函数.arguments.items()来访问参数映射关系。

函数注解
def clip(text, max_len=80)
def clip(text:str, max_len:'int>0'=80) --> str
这个注解就是加在参数:后面,可能就是一种解释的作用,同时箭头表明的是返回的注解类型

5.10
支持函数式编程的包
operator

书中主要说这个包为算术运算符提供了函数,于是我们可以不用递归写出阶乘

def fact ( n ):
return reduce (mul, range ( 1 , n + 1 ))



operator还有一个就是它提供了itemgetter和attrgetter
itemgetter(1) 其实 与 lambda x: x[1] 是等价的
不过它避免了使用匿名函数
例子:sorted(L, key=itemgetter(1))按可迭代对象的第1号索引来排序
但如果是itemgetter(0,1)则是提取出只包含0,1号位的元组
两个元素及以上则是提取出相对应的元组了

attrgetter也是差不多的
但不同的是他接受属性
sorted(metro_areas, key=attrgetter('coord.lat'))
这时候读取的是metro_areas里的每一个对象的.coord.let属性
同样,当接受多个参数时会返回对应属性组成的元组

method caller
这个与attrgetter, itemgetter 一样,它们都返回一个元素
变成 Upper:
a= methodcaller('upper')
a函数就像str.upper()一样

b = methodcaller('replace', ' ', '-')
b就像.replace(' ', '-')一样

使用functools.partial来冻结参数
可以使函数构建更加方便,比如我们要算一个列表中所有元素的三倍,但是不能用乘法


from operator import mul
from functools import partial
triple = partial(mul , 3 )
print ( list ( map (triple, range ( 1 , 10 ))))

同样我们也可以用partial来让我们的函数变得更具体
比如我们之前定义的tag函数,现在我们只想让它生成img标签
picture = partial(tag, 'img', cls='pic-frame')
可以用picture,func来访问原函数    

你可能感兴趣的:(Python学习)