Python 如何从基类中的派生类调用方法?
我试图写一个干净的代码,通过这样做,我学到了一两件事Python 如何从基类中的派生类调用方法?,python,python-3.x,oop,Python,Python 3.x,Oop,我试图写一个干净的代码,通过这样做,我学到了一两件事 班级建设: 定义初始化(自我,数据库): self.\uu db=db def解码(自身,值): 字段=dict() 对于键入的self.\uu db: 字段[键]=int(值) 返回场 等级公寓(楼): 定义初始化(自我,数据库): super().\uuuu init\uuuu(db) def解码(自身、str_值): field=super().解码(str_值) 字段=自缩放(字段) 返回场 def缩放(自身、字段): 字段['siz
班级建设:
定义初始化(自我,数据库):
self.\uu db=db
def解码(自身,值):
字段=dict()
对于键入的self.\uu db:
字段[键]=int(值)
返回场
等级公寓(楼):
定义初始化(自我,数据库):
super().\uuuu init\uuuu(db)
def解码(自身、str_值):
field=super().解码(str_值)
字段=自缩放(字段)
返回场
def缩放(自身、字段):
字段['size']/=1000
返回场
班级宿舍(大楼):
定义初始化(自我,数据库):
super().\uuuu init\uuuu(db)
def解码(自身、str_值):
field=super().解码(str_值)
字段=自缩放(字段)
返回场
def缩放(自身、字段):
字段['garden']/=25
返回场
def main():
公寓_db={“大小”:无}
home_db={“花园”:无}
app=公寓(公寓\ db)
home=home(home\u db)
打印(应用程序解码('5'))
打印(home.decode('100'))
如果名称=“\uuuuu main\uuuuuuuu”:
main()
输出:
{'size':0.005}
{'garden':4.0}
可以看出,每个派生类都有自己的数据库和自己的缩放(我认为没有缩放也是缩放)
我认为问题在于基类不知道在派生类中定义的伸缩实现
如果我可以将派生类的缩放实现传递给基类,那么我在派生类中的解码方法将非常简单:
等级公寓(建筑):
def解码(自身、str_值):
返回super().解码(str_值)
在python3.7中有这样做的方法吗?是的,这是可能的
如果您对向Building
类添加新方法很满意,那么一个简单的方法就是将scaling
方法也添加到该类中。现在,派生类没有自己的缩放定义
,只使用构建
的简单实现:
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
如果不想将方法添加到建筑
,您仍然有一些选项。三思而后行的方法是检查self
是否具有属性'scaling'
,然后通过self.scaling
传递字段。这是因为self
始终是我们调用方法的实例,因此它将具有为该对象的类定义的属性。下面是一个快速实现:
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
-语句或try except
,这有点滑稽。这将传递一个lambda,它只返回其参数(=标识函数),作为getattr
函数的第三个参数。第三个参数是getattr
在找不到给定属性时返回的默认值。然后,我们只需调用getattr
的返回值,并将字段作为参数,然后返回结果:
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)
上述所有方法都将允许您从派生类中删除\uuuu init\uuuu
和解码
方法,并在必要时让它们只实现缩放
。在这里使用时,它们也会给出相同的结果:
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()
输出:
{'size':0.005}
{'garden':4.0}
继承是从基类到派生类的,所以简而言之,我不相信您可以从基类调用派生类方法。如果我们讨论的是实例,那么可能有一些技巧
将派生类视为基类的专门化也是一种很好的做法,这样常见的行为仍保留在基类中,您只需在需要时调整(也称为重写)某些参数和方法,并用于特定目的。这使得整个代码更具可读性和可维护性
对于您的特定情况,我可以考虑一种不同的解决方案,您可以将缩放直接嵌入基类中,并仅在派生类中更改缩放因子,例如:
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
派生的任何类中的self.scaling
值。您的真实场景可能更复杂,但我相信这种模式会更好地为您服务。您可以采取两种方法。首先,使定标器
成为解码
的函数参数;它不需要是一个方法,因为您没有使用它的self
参数。(尽管对于每个派生类实现,我将把每个类的scaler定义为一个私有静态方法。但是,请注意,您不需要一个派生类来定义scaler;您可以直接实例化Building
,并将适当的函数直接传递给Building.decode
)
或者,在Building
中定义一个donothingscaling
方法,并根据需要让派生类重写它
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
请注意,在这两种情况下,我都省略了重写方法,如\uuuu init\uuuu
,其中派生类只使用super
调用具有相同参数的父方法。继承确保在未定义覆盖的情况下调用父级。DefineBase。作为一个简单的、不做任何事情的操作进行缩放。然后,派生的
根本不需要覆盖解码
;它只需要覆盖缩放
就可以做一些不平凡的事情。请注意,简化的派生。解码
不会
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