通过类方法的数据类和可调用初始化问题
Dataclass and Callable Initialization Problem via Classmethods
我发现了这种奇怪的行为,我不知道是我的问题还是这是 python/数据类/可调用的错误。
这是一个最小的工作示例
from dataclasses import dataclass
from typing import Callable
import numpy as np
def my_dummy_callable(my_array, my_bool):
return 1.0
@dataclass()
class MyDataClassDummy:
my_data: int = 1
my_callable: Callable[[np.ndarray, bool], float] = my_dummy_callable
def __init__(self):
print("I initialized my Class!")
@classmethod
def my_factory_with_callable_setting(cls):
my_dummy = MyDataClassDummy()
my_dummy.my_callable = my_dummy_callable
return my_dummy
@classmethod
def my_factory_without_callable_setting(cls):
my_dummy = MyDataClassDummy()
return my_dummy
def do_something(self):
print("This is my data", self.my_data)
print("This is the name of my callable", str(self.my_callable))
return self.my_callable(np.empty(shape=(42, 42)), True) + self.my_data
@dataclass()
class MySecondDataClassDummy:
my_data: int = 4
my_callable: Callable[[np.ndarray, bool], float] = my_dummy_callable
@classmethod
def my_factory(cls):
my_dummy = MySecondDataClassDummy()
return my_dummy
def do_something(self):
print("This is my data", self.my_data)
print("This is the name of my callable", str(self.my_callable))
return self.my_callable(np.empty(shape=(42, 42)), True) - self.my_data
if __name__ == '__main__':
# this works
my_first_dummy = MyDataClassDummy.my_factory_with_callable_setting()
my_first_dummy.do_something()
# this also works
my_second_dummy = MySecondDataClassDummy.my_factory()
my_second_dummy.do_something()
# this does not work
my_other_dummy = MyDataClassDummy.my_factory_without_callable_setting()
my_other_dummy.do_something()
案例 1:用工厂初始化,用我自己的 init 初始化,然后在初始化后显式设置可调用对象(虽然有默认值)- 有效
案例 2:使用工厂进行初始化但不自己明确编写 init() 代码 - 有效
案例 3:用工厂初始化,用我自己的 init 初始化并且在初始化后没有显式设置可调用对象(因为这就是为什么我有默认值,不是吗?!) - 不起作用但抛出错误:
Traceback (most recent call last):
File "my_path/dataclass_dummy.py", line 63, in <module>
my_other_dummy.do_something()
File "my_path/dataclass_dummy.py", line 33, in do_something
return self.my_callable(np.empty(shape=(42, 42)), True) + self.my_data
TypeError: my_dummy_callable() takes 2 positional arguments but 3 were given
所以现在我想知道,第三种情况我做错了什么。
我正在使用 Python 3.8 和 numpy 1.20.2
@dataclass
装饰器默认为 class 提供 __init__()
方法。此方法将类型注释 class 变量转换为 class 实例的属性。这种机制是在classMySecondDataClassDummy
的情况下使用的。实际上,此 class 的每个实例都有一个属性 my_callable
。由于这个属性是一个函数,你可以像案例2那样调用它,一切正常。
class MyDataClassDummy
有自己的 __init__()
方法,它覆盖 @dataclass
提供的 __init__()
。这个 class 的实例然后或多或少地被初始化,就像它们没有 @dataclass
装饰器一样。特别是,作为函数的 class 变量成为 class 实例的绑定方法。结果,my_callable
变成了这样一个绑定方法,而在情况 3 中执行时
self.my_callable(np.empty(shape=(42, 42)), True)
然后self
被用作my_callable
的第一个参数。由于此函数仅接受两个参数,因此会产生错误。
情况1不会出现同样的问题,因为在这种情况下你修改
my_dummy.my_callable
使其成为 my_dummy
的一个属性,其值是一个函数。修改后不再是绑定方法
我发现了这种奇怪的行为,我不知道是我的问题还是这是 python/数据类/可调用的错误。
这是一个最小的工作示例
from dataclasses import dataclass
from typing import Callable
import numpy as np
def my_dummy_callable(my_array, my_bool):
return 1.0
@dataclass()
class MyDataClassDummy:
my_data: int = 1
my_callable: Callable[[np.ndarray, bool], float] = my_dummy_callable
def __init__(self):
print("I initialized my Class!")
@classmethod
def my_factory_with_callable_setting(cls):
my_dummy = MyDataClassDummy()
my_dummy.my_callable = my_dummy_callable
return my_dummy
@classmethod
def my_factory_without_callable_setting(cls):
my_dummy = MyDataClassDummy()
return my_dummy
def do_something(self):
print("This is my data", self.my_data)
print("This is the name of my callable", str(self.my_callable))
return self.my_callable(np.empty(shape=(42, 42)), True) + self.my_data
@dataclass()
class MySecondDataClassDummy:
my_data: int = 4
my_callable: Callable[[np.ndarray, bool], float] = my_dummy_callable
@classmethod
def my_factory(cls):
my_dummy = MySecondDataClassDummy()
return my_dummy
def do_something(self):
print("This is my data", self.my_data)
print("This is the name of my callable", str(self.my_callable))
return self.my_callable(np.empty(shape=(42, 42)), True) - self.my_data
if __name__ == '__main__':
# this works
my_first_dummy = MyDataClassDummy.my_factory_with_callable_setting()
my_first_dummy.do_something()
# this also works
my_second_dummy = MySecondDataClassDummy.my_factory()
my_second_dummy.do_something()
# this does not work
my_other_dummy = MyDataClassDummy.my_factory_without_callable_setting()
my_other_dummy.do_something()
案例 1:用工厂初始化,用我自己的 init 初始化,然后在初始化后显式设置可调用对象(虽然有默认值)- 有效
案例 2:使用工厂进行初始化但不自己明确编写 init() 代码 - 有效
案例 3:用工厂初始化,用我自己的 init 初始化并且在初始化后没有显式设置可调用对象(因为这就是为什么我有默认值,不是吗?!) - 不起作用但抛出错误:
Traceback (most recent call last):
File "my_path/dataclass_dummy.py", line 63, in <module>
my_other_dummy.do_something()
File "my_path/dataclass_dummy.py", line 33, in do_something
return self.my_callable(np.empty(shape=(42, 42)), True) + self.my_data
TypeError: my_dummy_callable() takes 2 positional arguments but 3 were given
所以现在我想知道,第三种情况我做错了什么。
我正在使用 Python 3.8 和 numpy 1.20.2
@dataclass
装饰器默认为 class 提供 __init__()
方法。此方法将类型注释 class 变量转换为 class 实例的属性。这种机制是在classMySecondDataClassDummy
的情况下使用的。实际上,此 class 的每个实例都有一个属性 my_callable
。由于这个属性是一个函数,你可以像案例2那样调用它,一切正常。
class MyDataClassDummy
有自己的 __init__()
方法,它覆盖 @dataclass
提供的 __init__()
。这个 class 的实例然后或多或少地被初始化,就像它们没有 @dataclass
装饰器一样。特别是,作为函数的 class 变量成为 class 实例的绑定方法。结果,my_callable
变成了这样一个绑定方法,而在情况 3 中执行时
self.my_callable(np.empty(shape=(42, 42)), True)
然后self
被用作my_callable
的第一个参数。由于此函数仅接受两个参数,因此会产生错误。
情况1不会出现同样的问题,因为在这种情况下你修改
my_dummy.my_callable
使其成为 my_dummy
的一个属性,其值是一个函数。修改后不再是绑定方法