Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何从基类中的派生类调用方法?_Python_Python 3.x_Oop - Fatal编程技术网

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
中定义一个donothing
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, 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
调用具有相同参数的父方法。继承确保在未定义覆盖的情况下调用父级。

Define
Base。作为一个简单的、不做任何事情的操作进行缩放。然后,
派生的
根本不需要覆盖
解码
;它只需要覆盖
缩放
就可以做一些不平凡的事情。请注意,简化的
派生。解码
不会
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