【问题标题】:__getattr__ unexpectedly updates instance of a non-inherited class__getattr__ 意外更新非继承类的实例
【发布时间】:2017-04-11 18:46:56
【问题描述】:

我正在尝试复制 Java 库的 API 以解决车辆路线问题,它突出显示了我对 Python 类不了解的内容。

车队可以分为两个基本标准;第一个是您拥有的车辆类型(例如VehicleType 定义容量、运行成本等)和单个车辆(Vehicle 具有不同的班次模式等)。

在我的简化示例中,我想定义一个VehicleType,然后定义一个Vehicle,它将VehicleType 的属性传递给构造函数。按照 Lennart here 的回答,在一般情况下使用 __getattr__ 效果很好。但是,假设我有一个司机,他驾驶 50 辆货车中的一辆,具有携带危险物品的特殊资格,所以我想在 Vehicle 实例上添加一个额外的容量属性。我尝试了以下方法:

class VehicleType(object):

    def __init__(self, fixed_cost=0, cost_per_distance=0, cost_per_time=0):
        self.capacities = {}
        self.fixed_cost = fixed_cost
        self.cost_per_distance = cost_per_distance
        self.cost_per_time = cost_per_time

    def add_capacity_dimension(self, dimension_id, dimension_size):
        """ Define a package type and how many of them this vehicle type can carry """
        self.capacities[dimension_id] = dimension_size


class Vehicle(object):

    def __init__(self, vehicle_type=None, identifier=None):
        self._vehicle_type = vehicle_type
        self.identifier = identifier

    def add_capacity_dimension(self, dimension_id, dimension_size):
        self.capacities[dimension_id] = dimension_size

    def __getattr__(self, name):
        return getattr(self._vehicle_type, name) 


if __name__ == '__main__':
    van_type = VehicleType()
    van_type.add_capacity_dimension("general items", 34)

    special_van = Vehicle(vehicle_type=van_type)
    special_van.add_capacity_dimension("hazardous chemicals", 50)

    print("Capacities of special van: {}".format(special_van.capacities))
    print("Capacity of van_type:      {}".format(van_type.capacities)) # Why?

我不明白为什么我的方法也影响了capacitiesvan_typeVehicle 不直接继承自 VehicleType,我在 Vehicle 类中定义了 add_capacity_dimension。这也与我对the docs__getattr__ 的理解相矛盾:

当属性查找没有找到属性中的属性时调用 通常的地方(即它不是实例属性,也不是在 自我的类树)。 name 是属性名。

有人能解释一下为什么实例van_type也在这里受到影响吗?

【问题讨论】:

  • 这其中的哪一部分让您感到惊讶?你对van_type 有一个capacities 感到惊讶吗?你对它的变异感到惊讶吗?
  • @user2357112 你是对的,我错过了链接,因为看起来太长了。 capacities for Vehicle 本身需要 __getattr__。在这种情况下,这样做的唯一方法是在 Vehicle 中定义 capacities,然后将 __getattr__ 用于其余属性?
  • @roganjosh 他们匹配。如果他们不这样做,那么您的 MCVE 是错误的。
  • @wim MCVE 是正确的,我在尝试编写时验证了 id() 错误。再次检查。谢谢大家,对于 时刻感到抱歉。

标签: python python-2.7


【解决方案1】:

Vehicle 实例没有“容量”属性。

special_van 上的self.capacities 属性查找(来自Vehicle.add_capacity_dimension 实现)不是在Vehicle 上解决,而是在VehicleType 上通过自定义__getattr__ 解决。

因此,special_van.capacitiesvan_type.capacities 是同一个字典。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    • 2022-07-28
    • 2011-12-08
    • 2018-05-10
    • 1970-01-01
    相关资源
    最近更新 更多