[英]How to call method from a derived class in the base class?
我正在尝试编写一个干净的代码,并通过这样做学习一两件事。
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
return field
class Apartment(Building):
def __init__(self, db):
super().__init__(db)
def decode(self, str_value):
field = super().decode(str_value)
field = self.scaling(field)
return field
def scaling(self, field):
field['size'] /= 1000
return field
class Home(Building):
def __init__(self, db):
super().__init__(db)
def decode(self, str_value):
field = super().decode(str_value)
field = self.scaling(field)
return field
def scaling(self, field):
field['garden'] /= 25
return field
def main():
apartment_db = { 'size' : None}
home_db = { 'garden' : None}
app = Apartment(apartment_db)
home = Home(home_db)
print(app.decode('5'))
print(home.decode('100'))
if __name__ == "__main__":
main()
Output:
{'size': 0.005} {'garden': 4.0}
可以看出,每个派生的 class 都有自己的数据库和自己的缩放比例(我认为没有缩放比例也是缩放比例)。
我的思考问题是基础 class 不知道缩放实现,它在派生的 class 中定义。
如果我可以将派生 class 的缩放实现传递给基础 class,那么我在派生 class 中的解码方法将非常简单:
class Apartment(Building):
def decode(self,str_value):
return super().decode(str_value)
有没有办法在 python3.7 中做到这一点?
对的,这是可能的。
如果您对向Building
class 添加新方法感到满意,那么一种简单的方法就是向其添加scaling
方法。 现在派生类没有自己的scaling
定义,将只使用Building
的简单实现:
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
return self.scaling(field)
def scaling(self, value):
return value
如果您不想向Building
添加方法,您仍然有一些选择。 在你跳跃之前的方法是检查self
是否具有属性'scaling'
,然后将field
传递self.scaling
如果这是真的。 这是因为self
始终是我们调用该方法的实例,因此它将具有为该对象的 class 定义的属性。 这是一个快速的实现:
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
if hasattr(self, 'scaling'):
field = self.scaling(field)
return field
或者,比许可更容易请求宽恕的方式是使用try-except
,并在方法不存在时捕获AttributeError
并且不进行缩放:
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
try:
field = self.scaling(field)
except AttributeError:
pass
return field
这也可以在不添加任何方法甚至不使用if
-statement 或try-except
的情况下完成,带有一种有趣的 hack。 这将传递一个 lambda,它只返回其参数(=identity 函数),作为gettattr
function 的第三个参数。 第 3 个参数是gettattr
在找不到给定属性时返回的默认值。 然后我们简单地以field
作为参数调用gettattr
的返回值并返回结果:
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
return getattr(self, 'scaling', lambda x: x)(field)
以上所有方法都可以让您从派生类中删除__init__
和decode
方法,并让它们在必要时实现scaling
。 像这里这样使用时,它们也会给出相同的结果:
class Building:
# Any of the above implementations,
# will give the exact same results.
class Apartment(Building):
def scaling(self, field):
field['size'] /= 1000
return field
class Home(Building):
def scaling(self, field):
field['garden'] /= 25
return field
def main():
apartment_db = { 'size' : None}
home_db = { 'garden' : None}
app = Apartment(apartment_db)
home = Home(home_db)
print(app.decode('5'))
print(home.decode('100'))
if __name__ == "__main__":
main()
Output:
{'size': 0.005} {'garden': 4.0}
Inheritance 从 Base class 工作到 Derived class,所以简而言之,我不相信你可以从 Base-class 调用 Derived-class 方法。 如果我们在谈论实例,那么也许有一些技巧。
将 Derived class 视为 Base class 的专业化也是一种很好的做法,因此常见行为仍保留在 Base class 中,您只需调整(也称为覆盖)一些特定目的和方法的参数和方法。 这使得整个代码更具可读性和可维护性。
对于您的特定情况,我可以想到一个不同的解决方案,您可以将缩放直接嵌入到 Base class 中,并仅在派生类中更改缩放因子,例如:
class Base(object):
def __init__(self):
self.scaling = 1
def decode(self, value):
field = { 'distance' : int(value)/self.scaling }
return field
class Derived(Base):
def __init__(self):
self.scaling = 1000
base = Base()
print(base.decode(5))
derived = Derived()
print(derived.decode(5))
在这种情况下,您需要更改的只是从Base
派生的任何 class 中的self.scaling
值。 您的现实世界场景可能更复杂,但我相信这种范式会更好地为您服务。
您可以采取两种方法。 首先,将scaler
设为 function 参数以进行decode
; 它不需要是一个方法,因为你没有使用它的self
参数。 (Although for each derived class implementation, I'll define each class's scaler as a private static method. Note, though, that you don't need a derived class simply to define a scaler; you can instantiate Building
directly and pass an appropriate function直接到Building.decode
)
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value, scaler=lambda x: x):
field = dict()
for key in self.__db:
field[key] = int(value)
return scaler(field)
class Apartment(Building):
@staticmethod
def _scale_by_1000(d):
d['size'] /= 1000
return d
def decode(self, str_value):
return super().decode(str_value, self._scale_by_1000)
class Home(Building):
@staticmethod
def _scale_by_25(d):
d['garden'] /= 25
return d
def decode(self, str_value):
return super().decode(str_value, self._scale_by_25)
或者,在Building
中定义一个无操作scaling
方法,并根据需要让派生的 class 覆盖它。
class Building:
def __init__(self, db):
self.__db = db
def decode(self, value):
field = dict()
for key in self.__db:
field[key] = int(value)
return self.scaling(field)
def scaling(self, d):
return d
class Apartment(Building):
def scaling(self, field):
field['size'] /= 1000
return field
class Home(Building):
def scaling(self, field):
field['garden'] /= 25
return field
请注意,在这两种情况下,我都放弃了像__init__
这样的重写方法,其中派生的 class 什么都不做,只是使用super
调用具有相同 arguments 的父方法。 Inheritance 确保在未定义覆盖时调用父级。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.