嵌套型partial,partial对象中包含partial对象的使用
要实现的目标:
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()()())
简化嵌套式的partial对象p ,不要调用三次
p()
可以直接跳到最后的看解决方法 场景: 为了实现一个通用性较高的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的成员 这样在校验格式类型完之后立马调用它本身执行格式转换:校验格式的时候传入的是time_unit ,然后执行相应的格式转换date_trunc
from enum import Enum
from functools import partial
def date_trunc(time_unit: str, field):
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))
tf_day = TimeFormatter.__getattr__("DAY")
print(tf_day(field))
输出
date_trunc("WEEK", `event_time`)
date_trunc("DAY", `event_time`)
直到我想要使用二次时间格式转换时:
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(<function date_trunc at 0x000002538E45E5E0>, '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
|