funcy中的实用API

Published on
8

funcy的设计宗旨就是汇集一系列花哨的实用函数,其在不断地迭代过程中,已经积累下相当多的功能

无限计数器

funcy中的count()可以生成一个可指定起点和步长的无限迭代器,默认参数start=0step=1,我们可以用它来替代常规的while循环+自增变量的逻辑:

import funcy as fc

for i in fc.count():
    print(i, end='\r')
    # 当i大于等于5时停止迭代,否则继续
    if i >= 5:
        break

展平嵌套数组

funcy中的flatten()可以用来展平任意的嵌套数组:

import funcy as fc

arr1=[1,2,3,[4,5,6,[8,7,6,7,2],[23,12,1]],234,12]
arr2=[[123,456],'123','a','b','c']

print(list(fc.flatten(arr1)))
print(list(fc.flatten(arr2)))
#[1, 2, 3, 4, 5, 6, 8, 7, 6, 7, 2, 23, 12, 1, 234, 12]
#[123, 456, '123', 'a', 'b', 'c']

在指定数组中插其它

funcy中的interpose()可以用来将指定元素插入到对应数组的两两元素之间:

import funcy as fc

arr=['1','123','a','b','c']

print(list(fc.interpose("test",arr)))
#['1', 'test', '123', 'test', 'a', 'test', 'b', 'test', 'c']

批量删除满足指定条件的元素

funcy中有两种从原始列表中删除指定元素的方法,方式1是使用remove()来传入条件判断函数来删除满足条件的元素,类似filter()的方式:

import funcy as fc

arr=[None,'1','123','a','b','c','']

print(list(fc.remove(lambda  x: x == None or x == "",arr)))
#['1', '123', 'a', 'b', 'c']

第二种方式是利用funcy中的without(),它可以帮我们从原始数组中排除指定的1个或多个元素,譬如下面我们把2、5、7、9排除掉:

import funcy as fc

print(list(fc.without(list(range(10))*2, 2,5,7,9)))
#[0, 1, 3, 4, 6, 8, 0, 1, 3, 4, 6, 8]

等长度拆分数组

  • 等长度拆分数组,丢弃末尾长度不足的部分

funcy中的partition()帮助我们对输入的数组做指定长度的切片划分,譬如下面的例子,我们对列表[0, 1, ..., 10]进行长度为3的切片拆分,剩余不足长度3的部分就会被丢弃:

import funcy as fc

print(list(fc.partition(3,list(range(11)))))
#[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
  • 等长度拆分数组,并保留长度不足的部分

partition()功能相似,funcy中的chunks()会在等长度拆分数组的同时,保留末尾长度不足的部分单独输出:

import funcy as fc

print(list(fc.chunks(3,list(range(11)))))
#[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]

合并多个同类型对象

利用merge(),我们可以将传入的多个同类型数据结构拼成一个完整的,这在合并集合或字典时尤其受用:

import funcy as fc

l1= list(range(6))
l2= list(range(6,10))
print(list(fc.merge(l1,l2)))
#[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

阻止函数遇到错误时的常规报错方式

如果我们并不希望遇到错误就中断的话,就需要自己写额外的try...except...逻辑,而funcy中的silent()则可以让这个过程变得很省事:

import funcy as fc

def func(num):
    if fc.silent(int)(num) or num ==0:
        print('ok,It`s int')
    else:
        print("not int")


func(-66.3)
#ok,It`s int

阻止函数遇到指定错误时的常规报错方式

上面介绍的silent()会帮助传入函数遇到任意错误时返回None,而funcy中的ignore()则赋予我们指定错误类型,以及报错时设定返回值的能力:

import funcy as fc

def func(num):
    return 100/num

# print(func(0))
#ZeroDivisionError: division by zero

print(fc.ignore(errors=(ZeroDivisionError),default="被除数不能为0")(func)(0)
#被除数不能为0

装饰指定函数,使其记忆历史执行记录值

下面要介绍的方法非常的实用,想象一下这样的场景:你书写的某个函数接受输入,然后经过一段耗时不菲的计算过程输出结果,但在函数实际调用过程中经常遇到重复的传入参数。
这种时候你肯定希望自己的函数可以“记忆”下执行过的参数与输出结果,省得大量重复计算,而funcy中的memoize装饰器就可以帮助我们快速改造自己的函数:

import funcy as fc
import math

@fc.memoize
def job(x):
    return round(math.log(x**2 /10),4)

test = [job(5) for i in range(1000000)]
test = [job(10) for i in range(1000000)]

print(job.memory)
#{(5,): 0.9163, (10,): 2.3026}

#清空缓存
job.memory.clear()

约束某个函数的可执行次数

有些情况下,我们希望程序中的某个函数在整个程序的生命周期中只执行一次,譬如创建数据库连接等操作时,而funcy中提供的装饰器once就可以帮助我们快速实现这个功能,并且保证了线程安全:

import funcy as fc

@fc.once
def job(x):
    return round(math.log(x**2 /10),4)

print(job(10))
print(job(12))
#2.3026
#None

更多技巧参考:

https://funcy.readthedocs.io/en/stable/