如何在两个方向上实现对象属性

时间:2012-05-15 22:08:57

标签: python data-binding properties

如果我将一个对象分配给另一个对象的属性,那么获得给定第二个对象的第一个对象的自然方法是什么?我认为这有点像外键在数据库中的作用。

class Box(object):
    things = []

class Thing(object):
    box = None

thing = Thing()
box = Box()

# thing.box updates the box.things
thing.box = box
thing in box.things # should be true

# box.things updates thing.box
box.things.append(thing)
thing.box == box # should be true

我也希望通过一对一和多对多的关系实现这一目标。这可能吗?

我一直在保留所有“事物”的全球集合,然后在“盒子”上提供一个属性,以便所有属于仅在一个地方的信息。然而,事物的集合是如此巨大,我想把指针放在“盒子”对象本身的“事物”对象中。

3 个答案:

答案 0 :(得分:1)

对于“东西”的情况,你只想跟踪一个单独的对象, Python的属性将为您提供开箱即用的功能。

对于许多“东西”的容器,单个属性不会 work - 因为您想跟踪指向对象属性的容器的更改 (属性适用于属性本身的更改)。因此,一个小的自定义容器类可以对要添加到容器的对象进行更改,这是一种简单的方法。 (我认为“套装”对你来说比列表更好)

class Thing(object):
    def get_box(self):
        return self._box
    def set_box(self, box):
        self._box = box
        if not self in box.things:
            box.things.add(self)
    box = property(get_box, set_box)

class CallbackSet(set):
    def __new__(cls, box, *args, **kw):
        self = set.__new__(cls, *args, **kw)
        self.box = box
    def add(self, item):
        item.box = self.box
        return set.add(self, item)

class Box(object):
    def __init__(self):
        self.things = CallbackSet(self)

答案 1 :(得分:0)

您可能希望使用python weakref。否则,您将最终获得循环引用,这可能会导致垃圾收集器(即内存泄漏)出现问题。

最重要的问题是,谁将保持对象强引用(保持它不被垃圾收集的那个。)它是一个“世界”对象还是“盒子”对象?谁持有盒子对象?除此之外,所有其他人都会对其他人提供弱引用。或者你可以通过python id()来引用每个人,但是在使用int和字符串时要小心(如果你a=a+1 id(a)已经改变了)。在weakref文档的末尾寻找想法。

要实现所需的语法,请查看emulating container types

答案 2 :(得分:0)

这就是描述符的用途,如下所示:

class Box(object):

    things = []


class BoxManager(object):

    def __set__(self, instance, value):
        if isinstance(value, Box):
            instance._box = value
            Box.things.append(instance)

    def __get__(self, instance, type_=None):
        return instance._box


class Thing(object):
    box = BoxManager()


thing = Thing()
box = Box()

# thing.box updates the box.things
thing.box = box
print 'Thing is in box.things', thing in box.things  # should be true

# box.things updates thing.box
box.things.append(thing)
thing.box == box  # should be true
print 'thing.box == box is', thing.box == box

import pdb
pdb.set_trace()