简体   繁体   English

当列表用作Python中的属性时,当您更改列表中的单个值时,实际上不会调用设置方法

[英]When a list is used as a property in Python, the setter isn't actually called when you change an individual value in the list

Essentially what I'm trying to do is create a class that represents a robot arm. 本质上,我想做的是创建一个代表机械臂的类。

Inside of the arm there's a list that represents the joints, and my hope was that whenever those joints are 'set', it would transmit the values to a secondary microcontroller that controls the PWM signals that physically set the servos. 手臂内部有一个表示关节的列表,我希望每当“设置”这些关节时,它将这些值传输到辅助微控制器,该微控制器控制物理设置伺服器的PWM信号。

My problem is that when I only want to move 1 joint, but leave the others to be the same, I can't just say arm.joints[0] = 5 , because it sets the value but doesn't actually call the setter. 我的问题是,当我只想移动1个关节,而让其他关节保持不变时,我不能只说arm.joints[0] = 5 ,因为它设置了值但实际上并未调用setter 。

Is there a better way to structure this? 有没有更好的方法来构造它?

class RobotArm(object):

    """An object that resembles a robotic arm with n joints"""
    def __init__(self):

        # Empty list of zeros representing each joint   
        self.joints = [0]*5

    @property
    def joints(self):
        return self.__joints

    @joints.setter
    def joints(self, vals):
        print "setting values"
        self.__joints = vals
        self.serial_transmission(vals)

One solution is to use a custom list : 一种解决方案是使用自定义list

class Joints(list):
    """A custom list owned by another object. The owner should have
    a before_set_joints() method and an after_set_joints() method.
    """
    def __init__(self, owner, *args):
        self.owner = owner
        list.__init__(self, *args)

    def __setitem__(self, key, value):
        self.owner.before_set_joints()
        list.__setitem__(self, key, value)
        self.owner.after_set_joints()


# Define the onwer's methods cooperatively
class RobotArm(object):

    def __init__(self):
        self.__joints = Joints(self, [0] * 5)  # make self the owner

    def before_set_joints(self):
        print 'setting values'

    def after_set_joints(self):
        self.serial_transmission(self.joints)  # note a slight change here

The property definition can be just as before, but the setter needs to be modified: 属性定义可以和以前一样,但是需要修改设置器:

    @joints.setter
    def joints(self, vals):
        self.before_set_joints()
        self.__joints = Joints(self, vals)
        self.after_set_joints()

Demo (I defined serial_transmission to simply print "serial_transmission" and the list content): 演示(我定义了serial_transmission以仅打印"serial_transmission"和列表内容):

>>> arm = RobotArm()
>>> print(arm.joints)
[0, 0, 0, 0, 0]
>>> arm.joints = [1] * 5
setting joints
serial_transmission [1, 1, 1, 1, 1]
>>> arm.joints[0] = 5
setting joints
serial_transmission [5, 1, 1, 1, 1]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM