跳转到主要内容

Python的典型辅助函数集合。

项目描述

Build Status

Ebbe

Ebbe是一个Python的典型辅助函数集合,这些函数在标准库中无法找到。

安装

您可以使用以下命令使用pip安装ebbe

pip install ebbe

使用方法

迭代函数

实用工具

函数式编程

格式化

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):
  ...

由以下支持