Python弱引用学習
10109 ワード
参照1.weakref – Garbage-collectable references to objects2.Python弱引用紹介
他の多くの高度な言語と同様に、Pythonはゴミ回収器を使用して、使用されなくなったオブジェクトを自動的に破棄します.各オブジェクトには参照カウントがあり、この参照カウントが0の場合、Pythonはこのオブジェクトを安全に破棄することができます.
参照数は、指定されたオブジェクトの参照数を記録し、参照数がゼロの場合に収集されます.一度に1つのオブジェクトしか回収できないため、リファレンスカウントはループリファレンスのオブジェクトを回収できません.
相互参照されるオブジェクトのセットは、他のオブジェクトに直接参照されず、アクセスできない場合、永続的に生存します.1つのアプリケーションがこのようなアクセス不可能なオブジェクトグループを持続的に生成すると、メモリ漏洩が発生します.
オブジェクトグループ内で弱いリファレンス(すなわち、リファレンスカウントでカウントされないリファレンス)を使用すると、リファレンスリングが回避される場合があるため、弱いリファレンスはループリファレンスの問題を解決するために使用できます.
コンピュータプログラム設計において、弱いリファレンスは、強いリファレンスに対して、そのリファレンスのオブジェクトがゴミ回収器によって回収されないことを確保できないリファレンスを指す.1つのオブジェクトが弱い参照でのみ参照される場合、いつでも回収される可能性があります.弱いリファレンスの主な役割は、ループリファレンスを減らし、メモリ内の不要なオブジェクトの数を減らすことです.
Weakrefモジュールを使用すると、オブジェクトへの弱い参照を作成できます.Pythonは、オブジェクトの参照数が0またはオブジェクトのみの弱い参照がある場合にこのオブジェクトを回収します.
弱い参照の作成
Weakrefモジュールのref(obj[,callback])を呼び出すことで弱参照を作成できます.objは弱参照したいオブジェクトです.callbackはオプションの関数で、参照がないためPythonがこのオブジェクトを破棄しようとしたときに呼び出されます.コールバック関数callbackでは、単一のパラメータ(弱い参照オブジェクト)が必要です.
オブジェクトの弱い参照があれば、弱い参照を呼び出すことで、弱い参照されたオブジェクトを取得できます.
上記のコードでは、sysパッケージの
このオブジェクトに対する他の参照がなくなると、Pythonがオブジェクトを破棄したため、弱い参照を呼び出すとNoneが返されます.注:ほとんどのオブジェクトは弱引用でアクセスできません.
Weakrefモジュールのgetweakrefcount(obj)とgetweakrefs(obj)は、それぞれ弱い参照数と、与えられたオブジェクトに関する参照リストを返します.
弱いリファレンスは、オブジェクト(これらのオブジェクトはリソースがかかります)のキャッシュを作成するのに役立ちます.
プロキシオブジェクトの作成
プロキシオブジェクトは弱いリファレンスオブジェクトであり、リファレンスされたオブジェクトのように動作します.これにより、まず弱いリファレンスを呼び出して背後のオブジェクトにアクセスする必要がなくなります.Weakrefモジュールのproxy(obj[,callback])関数によりプロキシオブジェクトを作成します.プロキシオブジェクトを使用するのは、オブジェクト自体を使用するのと同じです.
callbackパラメータの役割はref関数のcallbackと同じです.Pythonが参照するオブジェクトを削除すると、エージェントを使用するとweakrefになります.ReferenceErrorエラー.
循環参照
前述したように,弱引用を用いることで,循環引用がごみに回収されないという問題を解決できる.まず、通常のループ参照を見て、簡単なGraphクラスを作成し、3つのGraphインスタンスを作成します.
ここではpythonのgcライブラリのいくつかの方法を使用し、以下のように説明します. gc.collect()収集ごみ gc.garbage取得ごみリスト gc.set_debug(gc.DBEUG_LEAK)は、見えないオブジェクト情報 を印刷する.
実行結果は次のとおりです.
結果から、Graphインスタンスのローカルリファレンスを削除しても、ゴミリストに存在し、回収できないことがわかります.次に、弱い参照を使用するWeakGraphクラスを作成します.
結果は次のとおりです.
上記のクラスでは、エージェントを使用して表示されているオブジェクトを示し、demo()がオブジェクトのすべてのローカル参照を削除するにつれてループが切断され、ゴミ回収期間でこれらのオブジェクトを削除できます.
したがって,我々は実際の作業でループリファレンスを用いる必要がある場合は,できるだけ弱いインデックスを用いて実現する.
キャッシュ・オブジェクト
結果は次のとおりです.
他の多くの高度な言語と同様に、Pythonはゴミ回収器を使用して、使用されなくなったオブジェクトを自動的に破棄します.各オブジェクトには参照カウントがあり、この参照カウントが0の場合、Pythonはこのオブジェクトを安全に破棄することができます.
参照数は、指定されたオブジェクトの参照数を記録し、参照数がゼロの場合に収集されます.一度に1つのオブジェクトしか回収できないため、リファレンスカウントはループリファレンスのオブジェクトを回収できません.
相互参照されるオブジェクトのセットは、他のオブジェクトに直接参照されず、アクセスできない場合、永続的に生存します.1つのアプリケーションがこのようなアクセス不可能なオブジェクトグループを持続的に生成すると、メモリ漏洩が発生します.
オブジェクトグループ内で弱いリファレンス(すなわち、リファレンスカウントでカウントされないリファレンス)を使用すると、リファレンスリングが回避される場合があるため、弱いリファレンスはループリファレンスの問題を解決するために使用できます.
コンピュータプログラム設計において、弱いリファレンスは、強いリファレンスに対して、そのリファレンスのオブジェクトがゴミ回収器によって回収されないことを確保できないリファレンスを指す.1つのオブジェクトが弱い参照でのみ参照される場合、いつでも回収される可能性があります.弱いリファレンスの主な役割は、ループリファレンスを減らし、メモリ内の不要なオブジェクトの数を減らすことです.
Weakrefモジュールを使用すると、オブジェクトへの弱い参照を作成できます.Pythonは、オブジェクトの参照数が0またはオブジェクトのみの弱い参照がある場合にこのオブジェクトを回収します.
弱い参照の作成
Weakrefモジュールのref(obj[,callback])を呼び出すことで弱参照を作成できます.objは弱参照したいオブジェクトです.callbackはオプションの関数で、参照がないためPythonがこのオブジェクトを破棄しようとしたときに呼び出されます.コールバック関数callbackでは、単一のパラメータ(弱い参照オブジェクト)が必要です.
オブジェクトの弱い参照があれば、弱い参照を呼び出すことで、弱い参照されたオブジェクトを取得できます.
>>>> import sys
>>> import weakref
>>> class Man:
def __init__(self,name):
print self.name = name
>>> o = Man('Jim')
>>> sys.getrefcount(o)
2
>>> r = weakref.ref(o) #
>>> sys.getrefcount(o) #
2
>>> r
#
>>> o2 = r() #
>>> o is o2
True
>>> sys.getrefcount(o)
3
>>> o = None
>>> o2 = None
>>> r # , 。
de>
上記のコードでは、sysパッケージの
getrefcount()
を使用して、オブジェクトの参照カウントを表示します.パラメータとして参照を使用してgetrefcount()
に渡されると、パラメータは実際に一時的な参照を作成することに注意してください.したがって,getrefcount()で得られた結果は,期待よりも多くなる.このオブジェクトに対する他の参照がなくなると、Pythonがオブジェクトを破棄したため、弱い参照を呼び出すとNoneが返されます.注:ほとんどのオブジェクトは弱引用でアクセスできません.
Weakrefモジュールのgetweakrefcount(obj)とgetweakrefs(obj)は、それぞれ弱い参照数と、与えられたオブジェクトに関する参照リストを返します.
弱いリファレンスは、オブジェクト(これらのオブジェクトはリソースがかかります)のキャッシュを作成するのに役立ちます.
プロキシオブジェクトの作成
プロキシオブジェクトは弱いリファレンスオブジェクトであり、リファレンスされたオブジェクトのように動作します.これにより、まず弱いリファレンスを呼び出して背後のオブジェクトにアクセスする必要がなくなります.Weakrefモジュールのproxy(obj[,callback])関数によりプロキシオブジェクトを作成します.プロキシオブジェクトを使用するのは、オブジェクト自体を使用するのと同じです.
import weakref
class Man:
def __init__(self, name):
self.name = name
def test(self):
print "this is a test!"
def callback(self):
print "callback"
o = Man('Jim')
p = weakref.proxy(o, callback)
p.test()
o=None
p.test()
callbackパラメータの役割はref関数のcallbackと同じです.Pythonが参照するオブジェクトを削除すると、エージェントを使用するとweakrefになります.ReferenceErrorエラー.
循環参照
前述したように,弱引用を用いることで,循環引用がごみに回収されないという問題を解決できる.まず、通常のループ参照を見て、簡単なGraphクラスを作成し、3つのGraphインスタンスを作成します.
# -*- coding:utf-8 -*-
import weakref
import gc
from pprint import pprint
class Graph(object):
def __init__(self, name):
self.name = name
self.other = None
def set_next(self, other):
print "%s.set_next(%r)" % (self.name, other)
self.other = other
def all_nodes(self):
yield self
n = self.other
while n and n.name !=self.name:
yield n
n = n.other
if n is self:
yield n
return
def __str__(self):
return "->".join(n.name for n in self.all_nodes())
def __repr__(self):
return "" % (self.__class__.__name__, id(self), self.name)
def __del__(self):
print "(Deleting %s)" % self.name
def collect_and_show_garbage():
print "Collecting..."
n = gc.collect()
print "unreachable objects:", n
print "garbage:",
pprint(gc.garbage)
def demo(graph_factory):
print "Set up graph:"
one = graph_factory("one")
two = graph_factory("two")
three = graph_factory("three")
one.set_next(two)
two.set_next(three)
three.set_next(one)
print
print "Graph:"
print str(one)
collect_and_show_garbage()
print
three = None
two = None
print "After 2 references removed"
print str(one)
collect_and_show_garbage()
print
print "removeing last reference"
one = None
collect_and_show_garbage()
gc.set_debug(gc.DEBUG_LEAK)
print "Setting up the cycle"
print
demo(Graph)
print
print "breaking the cycle and cleaning up garbage"
print
gc.garbage[0].set_next(None)
while gc.garbage:
del gc.garbage[0]
print collect_and_show_garbage()
ここではpythonのgcライブラリのいくつかの方法を使用し、以下のように説明します.
実行結果は次のとおりです.
Setting up the cycle
Set up graph:
one.set_next()
two.set_next()
three.set_next()
Graph:
one->two->three->one
Collecting...
unreachable objects:g 0
garbage:[]
After 2 references removed
one->two->three->one
Collecting...
unreachable objects: 0
garbage:[]
removeing last reference
Collecting...
unreachable objects: 6
garbage:[,
,
,
{'name': 'one', 'other': },
{'name': 'two', 'other': },
{'name': 'three', 'other': }]
breaking the cycle and cleaning up garbage
one.set_next(None)
(Deleting two)
(Deleting three)
(Deleting one)
Collecting...
unreachable objects: 0
garbage:[]
None
[Finished in 0.4s]c: uncollectable
gc: uncollectable
gc: uncollectable
gc: uncollectable
gc: uncollectable
gc: uncollectable
結果から、Graphインスタンスのローカルリファレンスを削除しても、ゴミリストに存在し、回収できないことがわかります.次に、弱い参照を使用するWeakGraphクラスを作成します.
class WeakGraph(Graph):
def set_next(self, other):
if other is not None:
if self in other.all_nodes():
other = weakref.proxy(other)
super(WeakGraph, self).set_next(other)
return
demo(WeakGraph)
結果は次のとおりです.
Setting up the cycle
Set up graph:
one.set_next()
two.set_next()
three.set_next()
Graph:
one->two->three
Collecting...
unreachable objects:Traceback (most recent call last):
File "D:\apps\platform\demo\demo.py", line 87, in
gc.garbage[0].set_next(None)
IndexError: list index out of range
0
garbage:[]
After 2 references removed
one->two->three
Collecting...
unreachable objects: 0
garbage:[]
removeing last reference
(Deleting one)
(Deleting two)
(Deleting three)
Collecting...
unreachable objects: 0
garbage:[]
breaking the cycle and cleaning up garbage
[Finished in 0.4s with exit code 1]
上記のクラスでは、エージェントを使用して表示されているオブジェクトを示し、demo()がオブジェクトのすべてのローカル参照を削除するにつれてループが切断され、ゴミ回収期間でこれらのオブジェクトを削除できます.
したがって,我々は実際の作業でループリファレンスを用いる必要がある場合は,できるだけ弱いインデックスを用いて実現する.
キャッシュ・オブジェクト
ref
とproxy
は、単一のオブジェクトの弱い参照を維持するためにのみ使用できます.複数のオブジェクトの弱い参照を同時に作成したい場合はどうすればいいですか?この場合、WeakKeyDictionary
およびWeakValueDictionary
を用いて実現することができる.WeakValueDictionary
クラスは、その名の通り、本質的には辞書タイプですが、その値タイプは弱い参照です.これらの値で参照されたオブジェクトが他の弱い参照オブジェクトで参照されなくなった場合、これらの参照されたオブジェクトはゴミ回収器で回収できます.次の例では、従来の辞書とWeakValueDictionary
の違いを説明する.# -*- coding:utf-8 -*-
import weakref
import gc
from pprint import pprint
gc.set_debug(gc.DEBUG_LEAK)
class Man(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return '' % self.name
def __del__(self):
print "deleting %s" % self
def demo(cache_factory):
all_refs = {}
print "cache type:", cache_factory
cache = cache_factory()
for name in ["Jim", 'Tom', 'Green']:
man = Man(name)
cache[name] = man
all_refs[name] = man
del man
print "all_refs=",
pprint(all_refs)
print
print "before, cache contains:", cache.keys()
for name, value in cache.items():
print "%s = %s" % (name, value)
print "
cleanup"
del all_refs
gc.collect()
print
print "after, cache contains:", cache.keys()
for name, value in cache.items():
print "%s = %s" % (name, value)
print "demo returning"
return
demo(dict)
print
demo(weakref.WeakValueDictionary)
結果は次のとおりです.
cache type:
all_refs={'Green': , 'Jim': , 'Tom': }
before, cache contains: ['Jim', 'Green', 'Tom']
Jim =
Green =
Tom =
cleanup
after, cache contains: ['Jim', 'Green', 'Tom']
Jim =
Green =
Tom =
demo returning
deleting
deleting
deleting
cache type: weakref.WeakValueDictionary
all_refs={'Green': , 'Jim': , 'Tom': }
before, cache contains: ['Jim', 'Green', 'Tom']
Jim =
Green =
Tom =
cleanup
deleting
deleting
after, cache contains: []
demo returning
[Finished in 0.3s]