Я создаю инструмент конвейерной обработки данных и хочу иметь возможность компилировать серию функций вместе.
Все функции действуют на итерируемое и передают итерируемое как полученное значение.
Так что, если f(x)
отфильтровывает, g(x)
редактирует и h(x)
генерирует случайное значение, то я хочу иметь возможность составлять их комбинации, чтобы я мог вызвать f(g(h(x)))
или h(f(g(x)))
согласно требованиям.
Я бы хотел подготовить эти композиции (они имеют разные сигнатуры параметров, помимо исходной итерации), прежде чем узнавать, что будет x
.
Чтобы усложнить ситуацию, f
, g
и h
, разделяя итеративный параметр, который они оба принимают и испускают, имеют разные сигнатуры параметров.
Для удобства я могу обернуть эти параметры в оператор partial
, чтобы скрыть грязные параметры - но затем я хочу составить серию функций в соответствии с примером f(g(h(x)))
- идея заключается в том, что яхочу подать конкретный x
итерируемый во время выполнения.
Я обнаружил, что наличие partial
'функций, их последующее вложение означает, что я не могу получить доступ к этому самому глубокому параметру - и я получаю ошибки типа AttributeError: 'generator' object has no attribute 'keywords'
.
Другими словами, есть ли способ объединить или объединить функции таким образом, чтобы можно было отложить указание параметра, требуемого самой внутренней функцией во время выполнения?
Например, следующее работает нормально:
data_source = [ OrderedDict({"id" : "1", "name" : "Tom", "sync" : "a"}),
OrderedDict({"id" : "2", "name" : "Steve", "sync" : "a"}),
OrderedDict({"id" : "3", "name" : "Ulrich", "sync" : "b"}),
OrderedDict({"id" : "4", "name" : "Victor", "sync" : "b"}),
OrderedDict({"id" : "5", "name" : "Wolfgang", "sync" : "c"}),
OrderedDict({"id" : "6", "name" : "Xavier", "sync" : "c"}),
OrderedDict({"id" : "7", "name" : "Yves", "sync" : "c"}),
OrderedDict({"id" : "8", "name" : "Zaphod", "sync" : "d"}),
OrderedDict({"id" : "9", "name" : "Albert", "sync" : "d"})]
def f(x, filt):
for content in x:
if content['name']==filt:
print ("test")
yield content
def g(x,old, new):
for content in x:
if content["name"]==old:
content["name"]=new
yield content
def h(x, which):
for content in x:
if random.random()>0.5:
content[which]=random.randint(0,100)
yield content
p_f = partial(f, filt="Albert")
p_g = partial(g, old="Yves", new="Yeti")
p_h = partial(h, which='id')
iterator=(d for d in data_source)
for result in p_f(p_g(p_h(iterator))):
print (result)
Что выводит:
OrderedDict([('id', '1'), ('name', 'Tom'), ('sync', 'a')])
OrderedDict([('id', 57), ('name', 'Steve'), ('sync', 'a')])
OrderedDict([('id', '3'), ('name', 'Ulrich'), ('sync', 'b')])
OrderedDict([('id', '4'), ('name', 'Victor'), ('sync', 'b')])
OrderedDict([('id', 33), ('name', 'Wolfgang'), ('sync', 'c')])
OrderedDict([('id', '6'), ('name', 'Xavier'), ('sync', 'c')])
OrderedDict([('id', 83), ('name', 'Yeti'), ('sync', 'c')])
OrderedDict([('id', '8'), ('name', 'Zaphod'), ('sync', 'd')])
test
OrderedDict([('id', '9'), ('name', 'Albert'), ('sync', 'd')])
Но я хочу, чтобы я смог написать эту функцию раньше - и связать итератор составной функции позже.
Что-то вроде:
p_compiled = p_f(p_g(p_h))
for result in p_compiled(iterator):
print (result)
Но когда я это делаю, я получаю TypeError: 'generator' object is not callable
.