0

我想知道如何在不同的函数中访问描述符?当我初始化 Vehicle 类时,我可以将速度初始化为描述符,但是我无法在 Vehicle 函数 (calc_speed()-> self.speed.value) 中访问它的值返回AttributeError: 'int' object has no attribute 'value'。此外,不应该更改值audi.speed = 120触发set功能(以及打印应该触发get功能)?

class SpeedDesc(object):

    def __init__(self, name, val):
        self.var_name = name
        self.value = val

    def __get__(self, obj, objtype):
        print('Getting', self.var_name)
        return self.value

    def __set__(self, obj, value):
        msg = 'Setting {name} to {value}'
        print(msg.format(name=self.var_name, value=value))
        self.value = value

class Vehicle(object):

    def __init__(self, vType):
        self.vehicle_type = vType
        self.speed = SpeedDesc('speed desc', 100)

    def calc_speed(self, accel):
        return self.speed.value * accel

if __name__ == '__main__':

    audi = Vehicle('sedan')
    print('vehicle speed:', audi.speed.value)
    audi.speed = 120
    print(audi.calc_speed(1.5))
vehicle speed: 100
Traceback (most recent call last):
  File "descriptor_example.py", line 31, in <module>
    audi.calc_speed(1.5)
  File "descriptor_example.py", line 24, in calc_speed
    return self.speed.value * accel
AttributeError: 'int' object has no attribute 'value'

我的期望

Getting speed desc
vehicle speed: 100
Setting speed desc to 120
180
4

1 回答 1

0

speed应该是类属性;__get__当您通过实例而不是类访问它时,将传递您想要的速度的实例。我SpeedDesc稍微调整了 的定义,以强调您仍然可以从Vehicle.__init__.

您永远不需要显式访问描述符的属性:这是和value的实现细节。实际上,因为只有一个的所有实例共享一个实例,所以您不想将速度存储在. 您应该将它存储在一个将速度与特定实例相关联的字典中,这很容易通过将其附加到作为参数接收的对象上来完成。__get____set__SpeedDescVehicleself.valueobj

class SpeedDesc(object):

    def __init__(self, name, val=None):
        self.var_name = name
        self.default = val
        self.attr_name = "_" + name  # e.g.

    def __get__(self, obj, objtype):
        if obj is None:
            return self
        print('Getting', self.var_name)
        return getattr(obj, self.attr_name, self.default)

    def __set__(self, obj, value):
        msg = 'Setting {name} to {value}'
        print(msg.format(name=self.var_name, value=value))
        setattr(obj, self.attr_name, value)


class Vehicle(object):
    speed = SpeedDesc('speed desc')

    def __init__(self, vType):
        self.vehicle_type = vType
        self.speed = 100

    def calc_speed(self, accel):
        return self.speed * accel


if __name__ == '__main__':

    audi = Vehicle('sedan')
    # Produces a call to Vehicle.speed.__get__(audi, Vehicle)
    print('vehicle speed:', audi.speed)
    # Produces a call to Vehicle.speed.__set__(audi, 120)
    audi.speed = 120
    print(audi.calc_speed(1.5))

请注意,您不一定需要显式传递名称;该__set_name__方法可用于获取描述符分配到的属性的名称。

class SpeedDesc(object):

    def __init__(self, val=None):
        self.default = val

    def __get__(self, obj, objtype):
        if obj is None:
            return self
        print('Getting', self.var_name)
        return getattr(obj, self.attr_name, self.default)

    def __set__(self, obj, value):
        msg = 'Setting {name} to {value}'
        print(msg.format(name=self.var_name, value=value))
        setattr(obj, self.attr_name, value)

    def __set_name__(self, owner, name):
        self.var_name = name
        self.attr_name = "_" + name  # e.g.
        print(f"Created {self.var_name} for {owner}, backed by {self.attr_name}")

class Vehicle(object):
    speed = SpeedDesc()

    def __init__(self, vType):
        self.vehicle_type = vType
        self.speed = 100

    def calc_speed(self, accel):
        return self.speed * accel

定义类型后,Vehicle.speed.__set_name__(Vehicle, "speed")代表您调用。

于 2020-06-04T17:16:23.827 回答