Python 带有可选数据 class 参数的函数调用导致错误
Python function call with optional Data class parameter causes error
我试图将数据 class 对象作为可选参数传递给函数,但卡住了。
因此,这是描述问题的简化代码。
首先,我定义了一个数据 class:
@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
通常情况下,应该避免第二次函数调用,因为它比较error-prone。
但由于默认参数值在这种情况下是可变的(见下文),这样做更安全
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=SomeObject('A')):
print(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
中的模式,或者小心不要写入关键字参数。
我试图将数据 class 对象作为可选参数传递给函数,但卡住了。 因此,这是描述问题的简化代码。 首先,我定义了一个数据 class:
@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
通常情况下,应该避免第二次函数调用,因为它比较error-prone。
但由于默认参数值在这种情况下是可变的(见下文),这样做更安全
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=SomeObject('A')):
print(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
中的模式,或者小心不要写入关键字参数。