我试图通过先提供所有位置和非位置参数,然后再提供其余非关键字参数来覆盖函数。
具有以下步骤的功能:
def foo(a, b, c=3, *args, **kwargs):
print(f"Positional: a={a} | b={b} | c={c}")
print("*args", args)
print("**kwargs", kwargs)
from functools import partial
# a partial callable to supply *args later
part = partial(foo, a=2, b=4, c=3, extra=3)
# Here, I expect that the extra arguments would be called
# but instead raises TypeError
part('a', 'b', 'c')
但是出现了错误。
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-bf0b47424a01> in <module>()
11 # Here, I expect that the extra arguments would be called
12 # but instread raises TypeError
---> 13 part('a', 'b', 'c')
TypeError: foo() got multiple values for argument 'a'
是否有解决此问题的方法,而无需深入研究它
可调用对象的签名(例如使用inspect.signature
等)?
编辑:
这是Traceback的真正问题代码:
import tkinter as tk
from tkinter import ttk
def _builder(parent, label, wtype, *args, **kwargs):
"""
Function to build widgets for configbox.
"""
# creae a container frame with the parent
container = ttk.Frame(parent)
container.pack(fill='x')
# add the elements in the container
# =================================
# pack label
label = ttk.Label(container, text=label)
label.pack(side='left', padx=4, pady=4, fill='x')
# get the widget by name and instantiate
# (fails here)
widget = getattr(ttk, wtype)(container, *args, **kwargs)
# pack and return
widget.pack(side='right', padx=4, pady=4, fill='x')
return widget
class _ConfigBox(tk.Toplevel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
lframe = ttk.Labelframe(self, text="Configurations")
lframe.pack()
# this does not fail - (no *args or **kwargs)
# place extension entry box
ext_entry = _builder(lframe, "Extension", "Entry")
# THIS PART FAILS!
# bind backend variable with option menu
bkndvar = tk.StringVar(lframe, value="# XXX TEST")
bknd_opts = _builder(
lframe,
"Backend",
"OptionMenu",
# give the *args...
*("TEST1", "TEST2"),
# ...and the **kwargs (fails here)
**dict(variable=bkndvar, default=bkndvar.get()),
)
回溯:
>>> x = _ConfigBox(tk.Tk())
>>> x.mainloop()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-d0fface65de6> in <module>()
----> 1 x = _ConfigBox(tk.Tk())
2 x.mainloop()
<ipython-input-6-aad9dde31798> in __init__(self, parent, *args, **kwargs)
45
46 # ...and the **kwargs (fails here)
---> 47 **dict(variable=bkndvar, default=bkndvar.get()),
48 )
<ipython-input-6-aad9dde31798> in _builder(parent, label, wtype, *args, **kwargs)
15 # get the widget by name and instantiate
16 # (fails here)
---> 17 widget = getattr(ttk, wtype)(container, *args, **kwargs)
18
19 # pack and return
TypeError: __init__() got multiple values for argument 'variable'
答案 0 :(得分:0)
partial
的关键字参数与其包装的函数的命名参数不匹配;它只是保存它们以将其添加到partial
对象以后接收的参数中。也就是说,part(foo, a=2, b=4, c=3, extra=3)('a', 'b', 'c')
等同于foo('a', 'b', 'c', a=2, b=4, c=3, extra=3)
。
您需要将位置参数传递给对partial
的调用。
part = partial(foo, 2, 4, 3, extra=3)
然后,您将获得所需的结果:
>>> part('a', 'b', 'c')
Positional: a=2 | b=4 | c=3
*args ('a', 'b', 'c')
**kwargs {'extra': 3}