Python:如何将第三个类的调用更新为原始类的重写方法?

时间:2014-07-21 18:08:08

标签: python

class ThirdPartyA(object):
    def __init__(self):
        ...
    def ...():
    ...
-------------------
from xxx import ThirdPartyA

class ThirdPartyB(object):
    def a(self):
        ...
        #call to ThirdPartyA
        ....

    def b(self):
        ...
        #call to ThirdPartyA
        ...

    def c(self):
        ...
        #call to ThirdPartyA
        ...
-----------------------------------
from xxx import ThirdPartyA

class MyCodeA(ThirdPartyA):
    def __init__(self):
        # overriding code

当覆盖A类的__init__方法时,我如何指示B类应该在其所有方法中调用MyCodeA而不是ThirdPartyA?

真正的代码在这里:

CLass Geoposition: ThirdPartyA

Class GeopositionField: ThirdPartyB

我对类Geoposition的覆盖,因此返回最多5位小数:

class AccuracyGeoposition(Geoposition):

    def __init__(self, latitude, longitude):
        if isinstance(latitude, float) or isinstance(latitude, int):
            latitude = '{0:.5f}'.format(latitude)
        if isinstance(longitude, float) or isinstance(longitude, int):
            longitude = '{0:.5f}'.format(longitude)

        self.latitude = Decimal(latitude)
        self.longitude = Decimal(longitude)

2 个答案:

答案 0 :(得分:1)

假设您的真实代码就像您的示例一样 - 也就是说,B的每个方法都会创建一个新的A实例,只是为了调用它上面的方法并将其丢弃,这是一个非常奇怪的设计,但如果它对你的用例有意义,你可以使它工作。

这里的关键是类是第一类对象。而不是硬编码A,将您想要的类存储为B实例的成员,如下所示:

class B(object):
    def __init__(self, aclass=A):
        self.aclass = aclass

    def a(self):
        self.aclass().a()

现在,您只需使用子类创建一个B实例:

b = B(OverriddenA)

您编辑的版本有一个不同的奇怪的东西:每次调用方法时都不会构建一个新的A实例,而是在A上调用类方法本身。同样,这可能不是你想要的 - 但是,如果是,你可以这样做:

class B(object):
    def __init__(self, aclass=A):
        self.aclass = aclass

    def a(self):
        self.aclass.a()

然而,你更有可能不想要其中任何一个。您希望在构建时采用A 实例,存储它并重复使用它。像这样:

class B(object):
    def __init__(self, ainstance):
        self.ainstance = ainstance

    def a(self):
        self.ainstance.a()

b1 = B(A())
b2 = B(OverriddenA())

如果这一切看起来很抽象而且难以理解......那就是因为我们使用了无意义的名称,如ABOverriddenA。如果你告诉我们你正在考虑的实际类型,或者只是机械地插入这些类型,它应该更有意义。

例如:

class Vehicle(object):
    def move(self):
        print('I am a vehicle, and I am moving')

class Operator(object):
    def __init__(self, vehicle):
        self.vehicle = vehicle
    def move(self):
        print('I am moving my vehicle')
        self.vehicle.move()

class Car(object):
    def move(self):
        print('I am a car, and I am driving')

driver = Operator(Car())
driver.move()

答案 1 :(得分:1)

从您更新的代码中,我认为您尝试要做的是更改GeopositionField. to_python(),以便它返回AccuracyGeoposition值而不是Geoposition值。

没有办法直接这样做; GeopositionField中的代码明确表示要构建Geoposition,这就是发生的事情。

最干净的解决方案是将GeopositionField子类化,因此您可以包装该方法:

class AccuracyGeopositionField(GeopositionField):
    def topython(self, value):
        geo = super(AccuracyGeopositionField, self).topython(value)
        return AccuracyGeoposition(geo.latitude, geo.longitude)

如果创建Geoposition然后重新包装AccuracyGeoposition中的值是不够的(因为准确性已经丢失),您可以在调用super方法之前预处理事情同样/相反。例如,如果它处理list的方式是不可接受的(我意识到这里不是真的,但它只是一个简单的例子),但是其他一切你可以让它做它的事情并包装结果,你可以这样做:

class AccuracyGeopositionField(GeopositionField):
    def topython(self, value):
        if isinstance(value, list):
            return AccuracyGeoposition(value[0], value[1])
        geo = super(AccuracyGeopositionField, self).topython(value)
        return AccuracyGeoposition(geo.latitude, geo.longitude)

如果最糟糕的情况发生,您可能必须重新实现整个方法(可能通过复制,粘贴和修改其代码),但希望很少出现。


有一些黑客替代品。例如,您可以将模块monkeypatch以全局替换Geoposition类与您的AccuracyGeoposition类但是,虽然这可能会预先保存一些工作,但当您'时,您几乎肯定会对它感到不满意。稍后重新调试。专为面向方面编程而设计的系统(基本上是受控制的monkeypatching)非常棒,但是试图将其塞进旨在抵制它的系统中会让你头疼。