Передать параметр в самый внутренний вызов составной функции - PullRequest
0 голосов
/ 03 июня 2019

Я создаю инструмент конвейерной обработки данных и хочу иметь возможность компилировать серию функций вместе.

Все функции действуют на итерируемое и передают итерируемое как полученное значение.

Так что, если 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.

1 Ответ

2 голосов
/ 03 июня 2019

Звучит так, будто вы просто хотите функцию compose():

def compose(f, g):
    return lambda x: f(g(x))

p_compiled = compose(p_f, compose(p_g, p_h))
for result in p_compiled(iterator):
    print (result)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...