python - 超类 __init__() 中的子类特定属性
问题描述
我环顾四周,但找不到任何答案。我有一个小问题——我有一个带有一些抽象方法的抽象基类,但也有几个对所有子类通用的方法。然而,为了使用这些方法,我需要传递一个特定于子类的属性。这很好用,但是我当然会收到基类没有特定属性的警告:
Unresolved attribute reference 'c' for class 'Foo'
假设我有这个代码:
from abc import ABC
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
def do_stuff(self):
if hasattr(self, 'c'):
return self.a * self.c
elif hasattr(self, 'd'):
return self.a + self.d
class Bar(Foo):
def __init__(self, a, b, c):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.c = c
self.some_dict = {}
def get_value_from_dict(self):
return self.some_dict[self.d]
class Baz(Foo):
def __init__(self, a, b, d):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.d = d
所以,Foo
是一个抽象基类,所以它永远不会被自己调用,但当然有这些警告并不好。然而,如果我将属性添加c
到值为 的基类None
,则会导致错误,因为当子类调用超类的 init 时,该值会被覆盖:
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = None
如果我如上所示更改基类的 init 然后实例化类Bar
并调用get_value_from_dict()
我将得到一个KeyError
,否则如果我保持原始示例中的内容,那么一切正常:
b = Bar(1, 2, 3)
b.do_stuff()
b.get_value_from_dict()
编辑:
这是我正在使用的实际代码。这就是do_stuff
我的示例中的方法所要表示的内容。这self.component
是一个特定于子类的属性,此通用方法将错误值替换为占位符值。
基类中还有其他几个self.component
以类似方式使用的通用方法。
class VariableImputer(ABC):
def __init__(self, data: pd.DataFrame, deposit: str, output_loc: Optional[str] = None) -> None:
self.data = data
self.deposit = deposit
self.output_loc = output_loc
self.err_index: np.ndarray = np.full(self.data.shape[0], True)
def _replace_erroneous_values(self):
"""
Replace calculated component values with -99 for all rows indices of
which are in self.err_index.
"""
err_data = np.where(~self.err_index)[0]
self.data.loc[err_data, self.component] = -99
class PopulateValue(VariableImputer):
def __init__(self, data: pd.DataFrame, deposit: str, output_loc: Optional[str] = None):
super().__init__(data=data, deposit=deposit, output_loc=output_loc)
self.data = data
self.deposit = deposit
self.output_loc = output_loc
self.component = ['porosity', 'sg']
但是警告仍然存在。处理这种情况的正确方法是什么?
解决方案
所以,如果我做这样的事情,我的 linter 就会停止抱怨:
from abc import ABC
class Foo(ABC):
a: int
b: int
c: int
d: int
def __init__(self, a, b):
self.a = a
self.b = b
def _do_stuff(self):
if hasattr(self, 'c'):
return self.a * self.c
elif hasattr(self, 'd'):
return self.a + self.d
class Bar(Foo):
def __init__(self, a, b, c):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.c = c
class Baz(Foo):
def __init__(self, a, b, d):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.d = d
另一种选择,使用哨兵值而不是检查hasattr
:
从 abc 进口 abc
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
def _do_stuff(self):
if self.c is not None:
return self.a * self.c
elif self.d is not None:
return self.a + self.d
但总的来说,这对我来说似乎是代码味道。您只是在避免基本问题,即您的方法可能不应该在 中实现Foo
,而是应该是在子类中实现的抽象方法。
为什么不只是
from abc import ABC, abstractmethod
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
@abstractmethod
def _do_stuff(self):
...
class Bar(Foo):
def __init__(self, a, b, c):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.c = c
def _do_stuff(self):
return self.a * self.c
class Baz(Foo):
def __init__(self, a, b, d):
super().__init__(a=a, b=b)
self.a = a
self.b = b
self.d = d
def _do_stuff(self):
return self.a * self.d
这对我来说似乎是最明智的解决方案。
推荐阅读
- javascript - 节点如何操作 HTML DOM - 找不到文档错误
- javascript - 如何从方法中更改 Vue 应用程序的数据值?
- indexing - IndexedDB 使用索引与键范围?
- kubernetes - eureka pod在kubernetes集群运行一段时间后转为pending状态
- .net - 如何让 ClientAcknowledgement 在 NMS 中工作?
- google-bigquery - 如何根据 bigquery 中的时区列将 UTC 时间转换为本地时区?
- java - 如何通过隐式意图创建内容提供程序以将 PDF 文件共享到另一个应用程序?
- c++ - 非虚拟多重继承示例
- javascript - 由于 iOS 上的商店数量,PouchDB 速度变慢
- javascript - 如何使用 Google Cloud Function 有效删除旧的 Firebase Cloud 文档?