Python的典型辅助函数集合。
项目描述
Ebbe
Ebbe是一个Python的典型辅助函数集合,这些函数在标准库中无法找到。
安装
您可以使用以下命令使用pip安装ebbe
:
pip install ebbe
使用方法
迭代函数
- as_chunks
- as_grams
- fail_fast
- uniq
- distinct
- with_prev
- with_prev_and_next
- with_next
- with_is_first
- with_is_last
- without_first
- without_last
实用工具
函数式编程
格式化
TODO: format_repr, format_filesize
装饰器
基准测试
as_chunks
通过分组项目并按迭代顺序遍历它们来迭代所需大小的块。
from ebbe import as_chunks
list(as_chunks(3, [1, 2, 3, 4, 5]))
>>> [[1, 2, 3], [4, 5]]
as_grams
迭代给定可迭代对象的gram(有时称为n-gram或q-gram等)。它适用于字符串、列表以及其他大小序列,以及用于惰性可迭代对象而不消耗任何多余内存。
from ebbe import as_grams
list(as_grams(3, 'hello'))
>>> ['hel', 'ell', 'llo']
list(as_grams(2, (i * 2 for i in range(5))))
>>> [(0, 2), (2, 4), (4, 6), (6, 8)]
fail_fast
获取可迭代对象(但此功能主要针对生成器),并尝试访问第一个值以查看是否会引发异常,然后在返回等效迭代器之前返回。
这对于某些设计不当的生成器很有用,这些生成器检查参数并在它们无效时引发异常,例如,如果您不想在迭代块中包裹整个try/except。
此逻辑还可用作装饰器。
from ebbe import fail_fast
def hellraiser(n):
if n > 10:
raise TypeError
yield from range(n)
# You will need to do this to catch the error:
gen = hellraiser(15)
try:
for i in gen:
print(i)
except TypeError:
print('Something went wrong when creating the generator')
# With fail_fast
try:
gen = fail_fast(hellraiser(15))
except TypeError:
print('Something went wrong when creating the generator')
for i in gen:
print(i)
uniq
根据键(可选)过滤相邻重复项,在给定迭代器中。
from ebbe import uniq
list(uniq([1, 1, 1, 2, 3, 4, 4, 5, 5, 6]))
>>> [1, 2, 3, 4, 5, 6]
# BEWARE: it does not try to remember items (like the `uniq` command)
list(uniq([1, 2, 2, 3, 2]))
>>> [1, 2, 3, 2]
# Using a key
list(uniq([(1, 2), (1, 3), (2, 4)], key=lambda x: x[0]))
>>> [(1, 2), (2, 4)]
distinct
根据键(可选)在给定迭代器中过滤重复项。
from ebbe import distinct
list(distinct([0, 3, 4, 4, 1, 0, 3]))
>>> [0, 3, 4, 1]
list(distinct(range(6), key=lambda x: x % 2))
>>> [0, 1]
with_prev
遍历与上一个元素一起的项目。
from ebbe import with_prev
for previous_item, item in with_prev(iterable):
print(previous_item, 'came before', item)
list(with_prev([1, 2, 3]))
>>> [(None, 1), (1, 2), (2, 3)]
with_prev_and_next
遍历与上一个和下一个元素一起的项目。
from ebbe import with_prev_and_next
for previous_item, item, next_item in with_prev_and_next(iterable):
print(previous_item, 'came before', item)
print(next_item, 'will come after', item)
list(with_prev_and_next([1, 2, 3]))
>>> [(None, 1, 2), (1, 2, 3), (2, 3, None)]
with_next
遍历与下一个元素一起的项目。
from ebbe import with_next
for item, next_item in with_next(iterable):
print(next_item, 'will come after', item)
list(with_next([1, 2, 3]))
>>> [(1, 2), (2, 3), (3, None)]
with_is_first
遍历包含当前元素是否为第一个元素的信息的项目。
from ebbe import with_is_first
for is_first, item in with_is_first(iterable):
if is_first:
print(item, 'is first')
else:
print(item, 'is not first')
list(with_is_first([1, 2, 3]))
>>> [(True, 1), (False, 2), (False, 3)]
with_is_last
遍历包含当前元素是否为最后一个元素的信息的项目。
from ebbe import with_is_last
for is_last, item in with_is_last(iterable):
if is_last:
print(item, 'is last')
else:
print(item, 'is not last')
list(with_is_last([1, 2, 3]))
>>> [(False, 1), (False, 2), (True, 3)]
without_first
跳过其第一个元素后遍历给定的迭代器。例如,如果要跳过CSV文件的标题,这可能很有用。
from ebbe import without_first
list(without_first([1, 2, 3]))
>>> [2, 3]
for row in without_first(csv.reader(f)):
print(row)
without_last
遍历给定的迭代器,但跳过其最后一个元素。
from ebbe import without_last
list(without_last([1, 2, 3]))
>>> [1, 2]
get
类似于 operator.getitem
的操作符函数,但可以接受默认值。
from ebbe import get
get([1, 2, 3], 1)
>>> 2
get([1, 2, 3], 4)
>>> None
# With default value
get([1, 2, 3], 4, 35)
>>> 35
getter
类似于 operator.itemgetter
的操作符工厂,但可以接受默认值。
from ebbe import getter
get_second_or_thirty = getter(1, 30)
get_second_or_thirty([1, 2, 3])
>>> 2
get_second_or_thirty([1])
>>> 30
# Overriding default on the spot
get_second_or_thirty([1], 76)
>>> 76
getpath
用于检索嵌套结构中给定路径的值或找不到该值时的默认值的操作符函数。
from ebbe import getpath
data = {'a': {'b': [{'c': 34}, 'test'], 'd': 'hello'}}
getpath(data, ['a', 'b', 0, 'c'])
>>> 34
getpath(data, ['t', 'e', 's', 't'])
>>> None
# Using a default return value
getpath(data, ['t', 'e', 's', 't'], 45)
>>> 45
# Using a string path
getpath(data, 'a.b.d', split_char='.')
>>> 'hello'
参数
- target any:目标对象。
- path iterable:获取路径。
- default ?any [
None
]:返回的默认值。 - items ?bool [
True
]:是否尝试遍历键和索引。 - attributes ?bool [
False
]:是否尝试遍历属性。 - split_char ?str:如果提供,将拆分路径字符串而不是引发
TypeError
。 - parse_indices ?bool [
False
]:是否在拆分字符串路径时解析整数索引。
pathgetter
返回一个作为 getpath 工作的getter函数,并部分应用于使用提供的路径或路径。
from ebbe import pathgetter
data = {'a': {'b': [{'c': 34}, 'test'], 'd': 'hello'}}
getter = pathgetter(['a', 'b', 0, 'c'])
getter(data)
>>> 34
getter = pathgetter(['t', 'e', 's', 't'])
getter(data)
>>> None
# Using a default return value
getter = pathgetter(['t', 'e', 's', 't'])
getter(data, 45)
>>> 45
# Using a string path
getter = pathgetter('a.b.d', split_char='.')
getter(data)
>>> 'hello'
# Using multiple paths
getter = pathgetter(
['a', 'b', 0, 'c'],
['t', 'e', 's', 't'],
['a', 'b', 'd']
)
getter(data)
>>> (34, None, 'hello')
参数
- paths list:获取路径。
- items ?bool [
True
]:是否尝试遍历键和索引。 - attributes ?bool [
False
]:是否尝试遍历属性。 - split_char ?str:如果提供,将拆分路径字符串而不是引发
TypeError
。 - parse_indices ?bool [
False
]:是否在拆分字符串路径时解析整数索引。
getter参数
- target any:目标对象。
- default ?any [
None
]:返回的默认值。
indexed
在类似字典的结构中索引给定迭代器的函数。这基本上只是在 dict
构造函数上的一些函数式糖。
from ebbe import indexed
indexed(range(3), key=lambda x: x * 10)
>>> {
0: 0,
10: 1,
20: 2
}
grouped
按键对给定迭代器进行分组的函数。
from ebbe import grouped
grouped(range(4), key=lambda x: x % 2)
>>> {
0: [0, 2],
1: [1, 3]
}
# Using an optional value
grouped(range(4), key=lambda x: x % 2, value=lambda x: x * 10)
>>> {
0: [0, 20],
1: [10, 30]
}
# Using the items variant
from ebbe import grouped_items
grouped_items((x % 2, x * 10) for i in range(4))
>>> {
0: [0, 20],
1: [10, 30]
}
partitioned
按键对给定迭代器进行划分的函数。
from ebbe import partitioned
partitioned(range(4), key=lambda x: x % 2)
>>> [
[0, 2],
[1, 3]
]
# Using an optional value
partitioned(range(4), key=lambda x: x % 2, value=lambda x: x * 10)
>>> [
[0, 20],
[10, 30]
]
# Using the items variant
from ebbe import partitioned_items
partitioned_items((x % 2, x * 10) for i in range(4))
>>> [
[0, 20],
[10, 30]
]
sorted_uniq
对给定迭代器进行排序然后通过单次线性遍历数据删除其重复项的函数。
from ebbe import sorted_uniq
numbers = [3, 17, 3, 4, 1, 4, 5, 5, 1, -1, 5]
sorted_uniq(numbers)
>>> [-1, 1, 3, 4, 5, 17]
# It accepts all of `sorted` kwargs:
sorted_uniq(numbers, reverse=True)
>>> [17, 5, 4, 3, 1, -1]
pick
返回只包含所选键的给定字典的函数。
from ebbe import pick
# Selected keys must be an iterable:
pick({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
>>> {'a': 1, 'c': 3}
# If you need the function to raise if one of the picked keys is not found:
pick({'a': 1, 'b': 2, 'c': 3}, ['a', 'd'], strict=True)
>>> KeyError: 'd'
omit
返回不包含所选键的给定字典的函数。
from ebbe import omit
# Selected keys must be a container:
omit({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
>>> {'b': 2}
# If need to select large numbers of keys, use a set:
omit({'a': 1, 'b': 2, 'c': 3}, {'a', 'c'})
>>> {'b': 2}
noop
Noop函数(可以带任何参数调用而不做任何事情的函数)。有时用作默认值,以避免在某些情况下使代码复杂化。
from ebbe import noop
noop() # Does nothing...
noop(4, 5) # Still does nothing...
noop(4, index=65) # Nothing yet again...
compose
返回其可变参数的组合函数的函数。
def times_2(x):
return x * 2
def plus_5(x):
return x + 5
compose(times_2, plus_5)(10)
>>> 30
# Reverse order
compose(times_2, plus_5, reverse=True)(10)
>>> 25
rcompose
返回其可变参数的逆组合函数的函数。
def times_2(x):
return x * 2
def plus_5(x):
return x + 5
rcompose(times_2, plus_5)(10)
>>> 25
and_join
可以将最后的项目与自定义积(如“and”)一起组合的连接函数。
from ebbe import and_join
and_join(['1', '2', '3'])
>>> '1, 2 and 3'
and_join(['1', '2', '3'], separator=';', copula="y")
>>> '1; 2 y 3'
format_int
将给定数字格式化为带千位分隔符的整数。
from ebbe import format_int
format_int(4500)
>>> '4,500'
format_int(10000, separator=' ')
>>> '10 000'
format_time
使用自定义精度和单位从年到纳秒格式化时间。
from ebbe import format_time
format_time(57309)
>>> "57 microseconds and 309 nanoseconds"
format_time(57309, precision="microseconds")
>>> "57 microseconds
format_time(78, unit="seconds")
>>> "1 minute and 18 seconds"
format_time(4865268458795)
>>> "1 hour, 21 minutes, 5 seconds, 268 milliseconds, 458 microseconds and 795 nanoseconds"
assert format_time(4865268458795, max_items=2)
>>> "1 hour and 21 minutes"
format_time(4865268458795, short=True)
>>> "1h, 21m, 5s, 268ms, 458µs, 795ns"
decorators.fail_fast
通过将其包装在另一个生成器函数中来装饰生成器函数,该函数在执行迭代逻辑之前将快速失败(如果运行了某些验证),以便可以提前捕获异常。
此逻辑也可以作为 函数 提供。
from ebbe.decorators import fail_fast
def hellraiser(n):
if n > 10:
raise TypeError
yield from range(n)
# This will not raise until you consume `gen`
gen = hellraiser(15)
@fail_fast()
def hellraiser(n):
if n > 10:
raise TypeError
yield from range(n)
# This will raise immediately
gen = hellraiser(15)
decorators.with_defer
通过带有 defer
kwarg 调用函数来装饰它,这有点像 Go 的 defer 语句,以便您可以在函数结束或异常发生时“延迟”要执行的操作以进行清理或拆除。
这依赖于 ExitStack,当然也可以通过上下文管理器来完成,但有时这种方式声明要延迟的操作可以很有用,以避免在复杂函数中嵌套。
from ebbe.decorators import with_defer
@with_defer()
def main(content, *, defer):
f = open('./output.txt', 'w')
defer(f.close)
f.write(content)
计时器
打印包装代码执行所需时间的上下文管理器(默认情况下为stderr)。非常适合运行基准测试。
from ebbe import Timer
with Timer():
some_costly_operation()
# Will print "Timer: ...s etc." on exit
# To display a custom message:
with Timer('my operation'):
...
# To print to stdout
import sys
with Timer(file=sys.stdout):
...