![](/img/trans.png)
[英]How to handle circular references between related objects from different modules in Python?
[英]How to handle python objects built from a web API that have references to each other?
我正在為Web API構建客戶端庫,該庫公開了一些這樣的對象:
# objs/foo/obj_id_1
{id: "foo_id_1"
name: "your momma"
bar: "bar_id_2"}
# objs/bar/obj_id_1
{id: "bar_id_2"
name: "puh-lease"
foo: "foo_id_1"}
因此, foo
類型的對象引用了bar
類型的對象,反之亦然。
在我的python客戶端庫中,我根據此API數據構建了python對象。 一個Foo
實例將具有一個包含Bar
實例的bar
屬性,而不僅僅是bar
的ID,並且一個Bar
實例在foo
屬性中具有對Foo
實例的引用。
我的python類具有save
和refresh
方法,這些方法可以從Web API進行POST或GET,並且它們對子對象執行此操作。 例如,如果我調用a_foo.refresh()
,它也會自動調用a_foo.bar.refresh()
。
上面是一個非常簡化的示例,可能有許多不同的類都引用bar
或foo
或我們得到的許多其他類型的對象的同一實例。
我認為我的問題實際上是兩個問題:
save
或refresh
時,當兩個或多個對象相互引用時,防止無限循環的最佳設計或策略是什么? 這是一個相當廣泛的問題。
1)一種方法是使用工廠方法模式。 例:
def get_foo(_id):
get_foo.foos = dict()
def real_get_foo(_id):
# get foo from the API
get_foo.foos[_id] = foo
return foo
if _id in get_foo.foos:
return get_foo.foos[_id]
return real_get_foo(_id)
2)我認為進行嵌套保存不是一個好主意。 如果我先寫foo.bar.x = 5
然后foo.save()
我不會期望bar
被保存。 為什么? 因為我在foo
上調用了save()
,所以我不必擔心對相關對象進行不必要的保存。
對於#1,您可以使用2級字典來保存獲取的對象
objectCache
|- foo
| |- foo_id_1 : <obj>
| |- foo_id_2 : <obj>
| |- ...
|
|- bar
| |- bar_id_1: <obj>
| |- bar_id_2: <obj>
| |- ...
|
|- baz
| |- baz_id_1: <obj>
| |- baz_id_2: <obj>
| |- ...
|
|- ...
您可以這樣使用它:
def get_or_make_fetched_object(cls, id):
return object_cache.setdefault(cls, {}).setdefault(id, cls())
my_foo = get_or_make_fetched_object(Foo, 'foo_id_1')
這里的技巧部分是如何擺脫不再引用的對象(例如,如果foo_id_1從bar_id_1切換到bar_id_35),以避免內存泄漏,因為object_cache
字典將無限期保留對該對象的引用,除非從該對象中刪除該對象。緩存。
解決內存使用問題的一種可能方法是使用gc.get_referrers()獲取每個緩存對象的refcount
的清理函數。 基本上,緩存中具有refcount
等於2的對象可以從緩存中刪除(1個計數來自gc
,另一個來自緩存)。 不過,這不適用於循環引用...
對於#2,您可以為帶有保存日期的對象添加時間戳,與當前保存時間戳匹配的對象將被跳過,以避免無限遞歸。 但是,僅保存下級對象是有意義的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.