问题描述
我试图将数据类对象作为可选参数传递给函数,但被卡住了。 因此,这是描述问题的简化代码。 首先,我要定义一个数据类:
@dataclass
class SomeObject:
A: str
如果我将参数设为非可选,则没有问题:
def printObject0 (Index,AnyObject):
print(Index,AnyObject.A)
Object1 = SomeObject ("A")
printObject0 (1,Object1)
# gives:
# 1 A
但是,如果我尝试将其设为可选参数* args这样...
def printObject1 (Index,*AnyObject):
print(Index,AnyObject.A)
Object1 = SomeObject ("A")
printObject1 (1,Object1)
# gives:
# AttributeError: 'tuple' object has no attribute 'A'
...或者带有这样的** kwargs ...
def printObject2 (Index,**AnyObject):
print(Index,AnyObject.A)
Object1 = SomeObject ("A")
printObject2 (1,Object1)
# gives:
# TypeError: printObject2() takes 1 positional argument but 2 were given
我得到了上述错误。
有人知道我如何使对象可选吗?
解决方法
函数参数*AnyObject
表示AnyObject
是所有剩余位置参数的元组。所以你可以做
from dataclasses import dataclass
@dataclass
class SomeObject:
A: str
def printObject_1(idx,*objs):
print(idx,objs[0].A)
printObject_1(1,SomeObject('A')) # 1 A
此外,函数参数**AnyObject
表示AnyObject
是所有其余关键字参数的字典。因此,您可以这样做:
def printObject_2(idx,**objs):
print(idx,objs['foo'].A)
printObject_2(1,foo=SomeObject('A')) # 1 A
顺便说一句:通常,可选函数参数具有默认值,例如
def printObject_3(idx,obj=SomeObject('A')):
print(idx,obj.A)
printObject_3(1) # 1 A
printObject_3(1,SomeObject('ABC')) # 1 ABC
printObject_3(1,obj=SomeObject('ABC')) # 1 ABC
通常,应该避免第二个函数调用,因为它更容易出错。
但是由于在这种情况下默认参数值是可变的(请参见下文),所以这样做更安全
def printObject_4(idx,obj=None):
if obj is None:
obj = SomeObject('A')
print(idx,obj.A)
printObject_4(1) # 1 A
printObject_4(1,obj=SomeObject('ABC')) # 1 ABC
printObject_3
的问题在于您可以在函数内部更改默认值:
def printObject_3_buggy(idx,obj.A)
obj.A = 321
printObject_3_buggy.__defaults__ # (SomeObject(A='A'),)
printObject_3_buggy(1) # 1 A
printObject_3_buggy.__defaults__ # (SomeObject(A=312),)
printObject_3_buggy(1) # 1 321
该异常行为的原因是默认值是可变的。因此,当您要使用可变的默认值时,请使用printObject_4
中的模式,或者当心不要写入关键字参数。