超类 __init__() 中特定于子类的属性
Subclass-specific attributes in superclass __init__()
我环顾四周,但找不到任何答案。我有一个小问题——我有一个抽象基础 class,它有一些抽象方法,但也有几个对所有子 class 都是通用的方法。然而,为了使用这些方法,我需要传递一个特定于 subclass 的属性。这工作正常,但我当然会收到警告,指出基本 class 没有特定属性:
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
是一个抽象基础 class,所以它永远不会被自己调用,但当然有这些警告并不是一件好事。然而,如果我将属性 c
添加到值为 None
的基 class,这将导致错误,因为当 subclass 调用 superclass' init ,值被覆盖:
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = None
如果我像上面那样改变base class' init 然后实例化class Bar
并调用get_value_from_dict()
我会得到一个KeyError
,否则如果我保留原始示例中的内容,那么一切正常:
b = Bar(1, 2, 3)
b.do_stuff()
b.get_value_from_dict()
编辑:
这是我正在使用的实际代码。这就是我示例中的 do_stuff
方法的意思。这里 self.component
是子 class 特定的属性,此通用方法用占位符值替换错误值。
基础 class 中还有其他几个以类似方式使用 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
这对我来说似乎是最明智的解决方案。
如果 Foo
中没有 attr
。您仍然尝试调用它。 IDE 会警告它。
有两个选项:
- 关闭 IDE lint 检查...(不好。)
- 将这些
attr
声明为抽象属性。
pytho3 below
from abc import ABC, abstractmethod
class Foo(ABC):
@property
@abstractmethod
def c(self):
pass
我环顾四周,但找不到任何答案。我有一个小问题——我有一个抽象基础 class,它有一些抽象方法,但也有几个对所有子 class 都是通用的方法。然而,为了使用这些方法,我需要传递一个特定于 subclass 的属性。这工作正常,但我当然会收到警告,指出基本 class 没有特定属性:
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
是一个抽象基础 class,所以它永远不会被自己调用,但当然有这些警告并不是一件好事。然而,如果我将属性 c
添加到值为 None
的基 class,这将导致错误,因为当 subclass 调用 superclass' init ,值被覆盖:
class Foo(ABC):
def __init__(self, a, b):
self.a = a
self.b = b
self.c = None
如果我像上面那样改变base class' init 然后实例化class Bar
并调用get_value_from_dict()
我会得到一个KeyError
,否则如果我保留原始示例中的内容,那么一切正常:
b = Bar(1, 2, 3)
b.do_stuff()
b.get_value_from_dict()
编辑:
这是我正在使用的实际代码。这就是我示例中的 do_stuff
方法的意思。这里 self.component
是子 class 特定的属性,此通用方法用占位符值替换错误值。
基础 class 中还有其他几个以类似方式使用 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
这对我来说似乎是最明智的解决方案。
如果 Foo
中没有 attr
。您仍然尝试调用它。 IDE 会警告它。
有两个选项:
- 关闭 IDE lint 检查...(不好。)
- 将这些
attr
声明为抽象属性。
pytho3 below
from abc import ABC, abstractmethod
class Foo(ABC):
@property
@abstractmethod
def c(self):
pass