要实现的目标,简单示例:
from functools import partial def func1(f): return f def func2(f1): return f1 def func(n): return n p = partial(func2, partial(func1, partial(func, 5))) print(p()()()) # 输出5
简化嵌套式的partial对象p,不要调用三次
p() # 输出5
可以到最后的看解决方法
场景:
为了实现一个通用性较高的sql生成方法,我写了一个通用的转换时间格式的方法,简略版大概如下:
def date_trunc(time_unit: str, field): return f'date_trunc("{time_unit}", `{field}`)' print(date_trunc("WEEK", "event_date")) print(date_trunc("DAY", "event_date")) ...
实际就是sql
中的date_trunc
方法
输出:
date_trunc("WEEK", `event_date`)
date_trunc("DAY", `event_date`)
由于校验日期参数和日期截断是前后挨着执行的
我把上面的几个方法写进了一个Enum
对象TimeFormatter
使用partial将date_trunc方法包起来以充当Enum的成员,实现用Enum类校验日期参数,用Enum
类成员的date_trunc方法执行日期截断
这样在校验完日期参数后立马调用它本身的date_trunc方法执行日期截断:执行日期截断date_trunc
方法时需要传入参数time_unit
,也就是"DAY", “WEEK
”, "MONTH
"等字符串
from enum import Enum from functools import partial def date_trunc(time_unit: str, field): # 注意这里的date_trunc和上面简略版举例的有所不同,需要两个参数 return f'date_trunc("{time_unit}", `{field}`)' class TimeFormatter(Enum): DAY = partial(date_trunc, "DAY") WEEK = partial(date_trunc, "WEEK") MONTH = partial(date_trunc, "MONTH") def __call__(self, *args, **kwargs): return self.value(*args, **kwargs)
这里的call方法让Enum
对象TimeFormatter
的成员变得可以被调用(callable),关于Enum的一些用法可以参考我上期的文章
到这里我依然可以正常调用我的date_trunc方法
field = "event_time" tf_wk = TimeFormatter.__getattr__("WEEK") # 先校验格式 print(tf_wk(field)) # 传入相应的field对象就会执行对应的date_trunc方法截断时间 tf_day = TimeFormatter.__getattr__("DAY") # 校验格式 print(tf_day(field)) # 执行date_trunc
输出:
date_trunc("WEEK", `event_time`)
date_trunc("DAY", `event_time`)
直到我想要使用二次的时间格式转换时,也就是在date_trunc之后再执行一个from_timestamp将sql中的日期对象event_time转换为指定的"yyyy-MM-dd"格式
from_timestamp(date_trunc("DAY", `event_time`), "yyyy-MM-dd")
发现好像没那么顺利地执行时间格式转换:
from enum import Enum from functools import partial def from_timestamp(field, time_fmt: str): return f'from_timestamp(`{field}`, "{time_fmt}")' class TimeFormatter(Enum): HOUR = partial(from_timestamp, partial(date_trunc, "HOUR")) def __call__(self, *args, **kwargs): return self.value(*args, **kwargs) tf_hour = TimeFormatter.__getattr__("HOUR") print(tf_hour("event_hour"))
输出:
from_timestamp(`functools.partial(
, 'HOUR')`, "event_hour")
不是想要的结果
查了一些解决办法,有循环调用,有用组合函数(function composition)的,
最后发现可以用一个简单的方法解决:
from enum import Enum from functools import partial def date_trunc(time_unit: str, field): return f'date_trunc("{time_unit}", `{field}`)' def from_timestamp(field, time_fmt: str): return f'from_timestamp(`{field}`, "{time_fmt}")' def fts(time_fmt, time_unit, field): return from_timestamp(date_trunc(time_unit, field), time_fmt) class TimeFormatter2(Enum): month = partial(fts, "yyyy-MM", "month") def __call__(self, *args, **kwargs): return self.value(*args, **kwargs)
输出:
from_timestamp(`date_trunc("month", `acmonth`)`, "yyyy-MM")
焯!原来只要多写一个函数就可以了!
前面简单示例的解决方法:
def nested_partials(f2, f1, n): return f2(f1(n)) p = partial(nested_partials, func2, func1) print(p(5))
输出:
5
到此这篇关于python 嵌套型partials的使用的文章就介绍到这了,更多相关python 嵌套型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!