Effective python(二):函数

1,遇到特殊情况抛出异常而不是返回None

 

2,有些情况需要将重要的消息优先显示在其它内容前面,例如在用户界面绘制的时候,实现方法如下

def sort_priority(values,group):
    def helper(x):
        if x in group: # 如果在优先组内,那就排到最前面
            return (0,x) # python会以特殊的形式比较两个元组,解释看下面
        return (1,x)
    values.sort(key=helper)

Python比较元组(或列表):可以想象比较的过程[(0,7),(0,8),(1,3)],那么Python进行比较的时候,会先进行元组的一个元素排序,然后再根据排序结果,对元组中第二个元素基于第一个元素的位置进行排序,当然最后输出的结果还是正常的列表[7,8,3],这只是其中比较的过程

 

3,nonlocal声明获取闭包内的数据,但它不能延伸至模块级别,而且复杂的函数情况下应该尽量少用,如果越写越复杂,可以将相关状态封装成辅助类

class Sorter(object):
    def __init__(self,group):
        self.group=group
        self.found=False
    
    def __call__(self,x): #修改这个后能够使得将类的实例当函数一样调用
        if x in self.group:
            self.found=True
            return (0,x)
        return (1,x)

 

4,对于返回列表的函数,可以使用yield改写return,同时要注意,返回的是一个迭代器,若有需要可以使用list()进行转换。若数据量非常大,不建议使用list转换而占用内存,若需要使用部分数据,可以使用list(islice(iter,start,end))进行对迭代器的切片操作。

 

5,处理迭代器参数注意事项

  1. 处理迭代器参数的时候应该注意,迭代器只能产生一轮结果,对其进行两次遍历操作是没有效果的,而且不会报错
  2. 迭代器是有状态的,应该避免多次对其操作
  3. 处理如上问题有两个解决方法:(1) 对迭代器进行一次复制转换为列表,(2) 参数设置为一个产生迭代的函数,(3) 编写一种新的实现迭代器的协议的容器类
  4. 在执行for x in y这样的语句时,python实际上会调用iter(y),内置的iter函数又会调用y.__iter__这个方法,该方法必须返回迭代器对象,而迭代器本身,又实现了特殊的__next__方法,for会反复的调用迭代器内置的next函数,直到耗尽产生StopIteration异常
  5. 实现新容器类只需要在__iter__方法中使用yeild即可
  6. 这种迭代器容器类使用方法和使用迭代器函数一样,实例化的容器类就可以当迭代器使用
  7. 为了防止传入的参数变成迭代器而不是容器的实例对象,可以使用语句判断是否是迭代器而报错if iter(arg) is iter(arg): #当传给iter函数的是迭代器时,会返回它本身,当传给iter函数是容器实例对象时,会返回一个新的迭代器
  8. 代码如下

 

6,可变长参数

  1. 对*arg参数传参时要记得对迭代器使用*解包
  2. 可变长参数传给函数时,总是会先转化成元组,这就意味着python会先把该生成器完整的迭代一轮,所以只使用于数据量较小的情况,否则可能会导致内存耗尽

 

7,关键字参数

  1. 位置参数必须出现在关键字参数前(不管是在调用时候,还是命名时)
  2. 所有位置参数都可以用关键字参数形式传递
  3. 使用关键字参数的好处是,可以与原有代码兼容,这样,添加新参数的时候就不需要去修改原有的调用传参,或者迁移大量参数
  4. 可选参数,也可以通过位置传参指定,但尽量不用

 

8,动态默认值参数

  1. def log(message,when=datetime.now()): #这种形式并不会在每次函数调用时多次定义默认值,而是会在函数定义时只执行一次创建默认值
  2. 若想实现动态的默认值,习惯上是先写成None,然后用文档字符串把参数的行为描述处理,在函数内写when=datetime.now()
  3. def decode(data,default={}) 这样定义也有BUG,所有使用默认形式调用decode的代码都将共享一份字典,解决方法是将其定义为None,在文档字符串中描述其行为

 

9,定义只能以关键字形式指定参数

  1. def func(n,d,*,i=False,c=False)  # 其中的*号,代表位置参数就此终结,后面的不能用位置传参的形式指定,只能用关键字形式指定
  2. 如果同时使用*args和**kwargs时,必须*args参数列要在**kwargs前
  3. takes 0 positional arguments but 1 was given注意出现这类错误要记得解包**,*
posted @ 2020-03-23 12:43  石天放  阅读(210)  评论(0编辑  收藏  举报