class 个本地函数中的访问描述符
access descriptor in class local functions
我想知道如何在不同的函数中访问描述符?我可以在初始化 Vehicle class 时将速度初始化为描述符,但是我无法在 Vehicle 函数中访问它的值 (calc_speed()-> self.speed.value) returns 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
speed
应该是 class 属性;当您通过实例而不是 class 访问它时,__get__
会传递您想要其速度的实例。我稍微调整了 SpeedDesc
的定义以强调您仍然可以从 Vehicle.__init__
.
初始化它
您永远不需要显式访问描述符的 value
属性:这是 __get__
和 __set__
的实现细节。事实上,因为 Vehicle
的所有实例共享 one 个 SpeedDesc
实例,所以您不想将速度存储在 self.value
.您应该将它存储在一个将速度与特定实例相关联的字典中,这最容易通过将其附加到作为 obj
参数接收的对象来完成。
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")
被代为调用。
我想知道如何在不同的函数中访问描述符?我可以在初始化 Vehicle class 时将速度初始化为描述符,但是我无法在 Vehicle 函数中访问它的值 (calc_speed()-> self.speed.value) returns 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
speed
应该是 class 属性;当您通过实例而不是 class 访问它时,__get__
会传递您想要其速度的实例。我稍微调整了 SpeedDesc
的定义以强调您仍然可以从 Vehicle.__init__
.
您永远不需要显式访问描述符的 value
属性:这是 __get__
和 __set__
的实现细节。事实上,因为 Vehicle
的所有实例共享 one 个 SpeedDesc
实例,所以您不想将速度存储在 self.value
.您应该将它存储在一个将速度与特定实例相关联的字典中,这最容易通过将其附加到作为 obj
参数接收的对象来完成。
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")
被代为调用。