如何将字典值设置为对另一个字典值的引用?

时间:2015-10-17 15:00:45

标签: python dictionary pass-by-reference

对于我正在制作的游戏,我想创建一个具有可以设置为另一个对象的属性的属性的对象(例如,door.locked = lock.locked)。当我更新第二个对象的属性(在本例中为lock)时,第一个对象(door)的相应属性也应该更新。这样解锁锁也将解锁门。 我目前用字典实现了这个,如下所示:

class Lock():
    def __init___(self, locked = True):
        self.attributes = {'locked': locked}

    def toggleLock():
        self.attributes.update({'locked': not self.attributes['locked']})

class Door():
    def __init__(self, locked = False):
        self.attributes = {'locked': locked}

然后我应该能够做到这一点:

>>>lock1 = Lock(locked = True)
>>>door1 = Door(locked = lock1.attributes['locked'])
>>>
>>>lock1.attributes['locked']
True
>>>door1.attributes['locked']
True
>>>
>>>lock1.toggleLock()
>>>lock1.attributes['locked']
False
>>>door1.attributes['locked']
False

然而,当我调用toggleLock()方法时,锁的状态会发生变化但门却没有。字典是可变的,所以当door1的时候不应该lock1字典更新吗? 我将如何实现它呢?

2 个答案:

答案 0 :(得分:0)

在你的代码中,你真的没有共享同一个字典,你在Door的构造函数中创建了一个新字典,试着这样做:

class Door():
    def __init__(self, attributes):
        self.attributes = attributes

然后按照这样的方式调用它:

>>>lock1 = Lock(locked = True)
>>>door1 = Door(lock1.attributes)

编辑:

如果你想拥有不同的词典并且只共享值,那么你可能想要将值包装在一个类中,然后共享它的一个实例:

class SharedValue(object):
    def __init__(self, val):
        self.value = val

class Lock():
    def __init___(self, locked = True):
        self.attributes = {'locked': SharedValue(locked)}

    def toggleLock():
        self.attributes['locked'].value = not self.attributes['locked'].value

class Door():
    def __init__(self, locked = False):
        if not isinstance(locked, SharedValue):
            locked = SharedValue(locked)
        self.attributes = {'locked': locked}

然后您可以按照自己的意愿创建它,但使用该值的代码必须更改

>>>lock1 = Lock(locked = True)
>>>door1 = Door(locked = lock1.attributes['locked'])
>>>
>>>lock1.attributes['locked'].value
True
>>>door1.attributes['locked'].value
True
顺便说一句,在您提交的具体案例中,我个人会将Lock锁定为Door的成员,并通过@property分享属性 并制作了getter,尝试从self.attributes获取它并且如果它不包含密钥,则从self.lock.attribute获取它

EDIT2:

为不同的解决方案添加示例:

class Lock():
    def __init__(self, locked = True):
        self.attributes = {'locked': locked}

    def toggleLock(self):
        self.attributes.update({'locked': not self.attributes['locked']})

class Door():
    def __init__(self, lock_object):
        self._attributes = {'color':'Blue'}
        self.lock = lock_object

    def get_attribute(self,key):
        if key in self._attributes:
            return self._attributes[key]
        elif key in self.lock.attributes:
            return self.lock.attributes[key]
        raise KeyError(key)

    @property
    def attributes(self):
        """
        Door's attributes
        """
        # return a new dict that contains the keys of itself, and lock (and possibly more objects)
        a = {}
        a.update(self.lock.attributes)
        a.update(self._attributes)
        return a 

    def __getattr__(self, key):
        #nice addition, makes you able to do things like `if Door.locked:`
        return self.get_attribute(key)

用法示例:

>>>l=Lock()
>>>d=Door(l)
>>>d.locked
True
>>>l.toggleLock()
>>>d.locked
False
>>>d.attributes
{'color': 'Blue', 'locked': False}

答案 1 :(得分:0)

这样做的一种可能方式(至少我更喜欢)是定义Singleton。请注意,这对python 2.x有效,我不知道它是否适用于Python 3.x

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args)  # , **kwargs
        return cls._instances[cls]

然后将此类别转移到您的锁类

class Lock():
    __metaclass__ = Singleton

    def __init___(self, locked = True):
        self.attributes = {'locked': locked}

    def toggleLock():
        self.attributes.update({'locked': not self.attributes['locked']})

简单地说,Singleton只允许您创建该对象的一个​​实例。第一次调用将创建一个新对象,之后调用将不会创建一个新对象,但会返回第一次调用创建的旧对象。

door_1_status = Lock()  # will create a Lock object
door_2_status = Lock()  # will not crate a new Lock, but return the already created Lock object.

因此,从Lock类创建的所有锁将共享相同的对象,因此状态相同。