web-dev-qa-db-ja.com

クラスのすべてのインスタンスを印刷する

Pythonのクラスで、関数で定義された形式でクラスのすべてのインスタンスを印刷する関数を定義するにはどうすればよいですか?

53
user33061

この場合、2つのオプションが表示されます。

ガベージコレクター

import gc
for obj in gc.get_objects():
    if isinstance(obj, some_class):
        dome_something(obj)

これには、多くのオブジェクトがある場合に非常に遅いという欠点がありますが、制御できない型では機能します。

Mixinとweakrefを使用する

from collections import defaultdict
import weakref

class KeepRefs(object):
    __refs__ = defaultdict(list)
    def __init__(self):
        self.__refs__[self.__class__].append(weakref.ref(self))

    @classmethod
    def get_instances(cls):
        for inst_ref in cls.__refs__[cls]:
            inst = inst_ref()
            if inst is not None:
                yield inst

class X(KeepRefs):
    def __init__(self, name):
        super(X, self).__init__()
        self.name = name

x = X("x")
y = X("y")
for r in X.get_instances():
    print r.name
del y
for r in X.get_instances():
    print r.name

この場合、すべての参照はリスト内の弱い参照として保存されます。多数のインスタンスを頻繁に作成および削除する場合、反復後にweakrefのリストをクリーンアップする必要があります。そうしないと、多くの問題が発生します。

この場合の別の問題は、基本クラスコンストラクターを必ず呼び出す必要があることです。 __new__をオーバーライドすることもできますが、インスタンス化では最初の基本クラスの__new__メソッドのみが使用されます。これは、制御下にあるタイプでのみ機能します。

編集:特定の形式に従ってすべてのインスタンスを印刷する方法は演習として残されていますが、基本的にはfor- loopsのバリエーションにすぎません。

86
Torsten Marek

クラスに静的リストを作成し、weakrefを各インスタンスに追加して、ガベージコレクターが不要になったインスタンスをクリーンアップできるようにします。

import weakref

class A:
    instances = []
    def __init__(self, name=None):
        self.__class__.instances.append(weakref.proxy(self))
        self.name = name

a1 = A('a1')
a2 = A('a2')
a3 = A('a3')
a4 = A('a4')

for instance in A.instances:
    print(instance.name)
22
MirkoT

非常に便利で便利なコードですが、大きな問題があります:リストは常に大きく、クリーンアップされることはありません。テストするにはprint(len(cls.__refs__[cls]))を追加してくださいget_instancesメソッドの終わり。

get_instancesメソッドの修正:

__refs__ = defaultdict(list)

@classmethod
def get_instances(cls):
    refs = []
    for ref in cls.__refs__[cls]:
        instance = ref()
        if instance is not None:
            refs.append(ref)
            yield instance
    # print(len(refs))
    cls.__refs__[cls] = refs

または、WeakSetを使用して行うこともできます。

from weakref import WeakSet

__refs__ = defaultdict(WeakSet)

@classmethod
def get_instances(cls):
    return cls.__refs__[cls]
6
Fabio Caccamo

他のほとんどすべてのOO言語と同様に、クラスのすべてのインスタンスを何らかのコレクションに保持します。

この種のものを試すことができます。

class MyClassFactory( object ):
    theWholeList= []
    def __call__( self, *args, **kw ):
         x= MyClass( *args, **kw )
         self.theWholeList.append( x )
         return x

これでできます。

object= MyClassFactory( args, ... )
print MyClassFactory.theWholeList
3
S.Lott

PythonにはSmallktalkの#allInstancesに相当するものがありません。アーキテクチャにはこのタイプの中央オブジェクトテーブルがないためです(ただし、現代のsmalltalkも実際には機能しません)。

他のポスターが言っているように、コレクションを明示的に管理する必要があります。レジストリを維持するファクトリメソッドの彼の提案は、それを行うための完全に合理的な方法です。 weak reference で何かをしたい場合があるので、オブジェクトの破棄を明示的に追跡する必要はありません。

すべてのクラスインスタンスを一度に印刷する必要があるのか​​、それらが初期化されたのか、また、サードパーティライブラリのクラスに対して制御するクラスについて話しているのかどうかは明らかではありません。

いずれにしても、Pythonメタクラスサポートを使用してクラスファクトリを記述することでこれを解決します。クラスを制御できない場合は、手動で__metaclass__追跡しているクラスまたはモジュール。

詳細については、 http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html を参照してください。

1
Daniel Naab

何もインポートする必要はありません! 「自己」を使用してください。これがあなたのやり方です

class A:
    instances = []
    def __init__(self):
        self.__class__.instances.append(self)

    @classmethod
    def printInstances(cls):
        for instance in cls.instances:
            print(instance)
A.printInstances()

これは簡単です。モジュールまたはライブラリがインポートされていません