functools.partial хочет использовать позиционный аргумент в качестве ключевого аргумента

Поэтому я пытаюсь понять partial:

import functools

def f(x,y) :
    print x+y

g0 = functools.partial( f, 3 )
g0(1)

4 # Works as expected

В:

g1 = functools.partial( f, y=3 )
g1(1)

4 # Works as expected

В:

g2 = functools.partial( f, x=3 )
g2(1)

TypeError: f() got multiple values for keyword argument 'x'

TypeError исчезает, если я использую y в качестве ключевого аргумента:

В:

g2( y=1 )

4

Что вызывает TypeError?

2 ответа

Решение

Это не имеет ничего общего с functools.partial, действительно. По сути, вы вызываете свою функцию следующим образом:

f(1, x=3)

Python сначала выполняет позиционные аргументы, а ваш первый аргумент x, Затем ключевые аргументы применяются, и вы снова предоставили x,

functools.partial() не имеет средств обнаружить, что вы уже указали первый позиционный аргумент в качестве ключевого аргумента. Это не увеличит ваш вызов, заменив позиционный аргумент на y= Ключевой аргумент.

При смешивании позиционных и ключевых аргументов вы должны позаботиться о том, чтобы не использовать один и тот же аргумент дважды.

Чтобы расширить ответ @Martijn-Pieters, это то, как вы можете сохранить позиционную природу второго параметра. Здесь аргумент g2 передается позиционно как y:

def f(x,y) :
    print x+y

g2 = functools.partial( f, *[3] )
g2(1)

Это работает, когда мы пытаемся заменить начальный набор аргументов f. Я не знаю как пользоваться partial заменить, например, только второй аргумент трехпараметрической функции, и разрешить позиционировать первый и третий аргументы. Но вы можете сделать это с лямбда-выражением.

Не ответ, а дополнительный вопрос (поскольку я не могу добавить комментарий без репутации 50), не могли бы вы уточнить или использовать простые термины, поскольку ответы здесь выше моего понимания. У меня аналогичная проблема с использованием кнопки в Maya

import maya.cmds as cmds
from functools import partial

class Myclass(object):
    def __init__(self):
        pass
    def createui(self):
        derp = cmds.window()
        cmds.formLayout()
        cmds.button(label = "w/e", c = partial(self.f, x = 3))
        cmds.showWindow(derp)
    def f(self, x = 5, y = 3, *_):
        print(x+y)

herp = Myclass()
herp.createui()

нажатие на кнопку приведет к той же ошибке "получено несколько значений для аргумента ключевого слова 'x'"

хотя я думал, что в качестве аргументов отправляется вызов класса, какой-то глупый вызов самого элемента пользовательского интерфейса (обычно значение False), который должен быть помещен в аргумент *_ catch all, а затем аргумент ключевого слова x.

Другие вопросы по тегам