복붙노트

[PYTHON] 클래스 인스턴스를 추적하는 방법?

PYTHON

클래스 인스턴스를 추적하는 방법?

프로그램의 끝으로 클래스의 모든 인스턴스에서 특정 변수를 사전에로드하려고합니다.

예 :

class Foo():
    __init__(self):
    x = {}

foo1 = Foo()
foo2 = Foo()
foo...etc.

인스턴스의 수가 달라지고 Foo ()의 각 인스턴스에서 x dict이 새로운 dict에로드되기를 원한다고 가정 해 보겠습니다. 내가 어떻게 그럴 수 있니?

내가 본 예는 이미 인스턴스 목록을 가지고 있다고 가정합니다.

해결법

  1. ==============================

    1.인스턴스를 추적하는 한 가지 방법은 클래스 변수를 사용하는 것입니다.

    인스턴스를 추적하는 한 가지 방법은 클래스 변수를 사용하는 것입니다.

    class A(object):
        instances = []
    
        def __init__(self, foo):
            self.foo = foo
            A.instances.append(self)
    

    프로그램이 끝나면 다음과 같이 사전을 작성할 수 있습니다.

    foo_vars = {id(instance): instance.foo for instance in A.instances}
    

    목록은 하나뿐입니다.

    >>> a = A(1)
    >>> b = A(2)
    >>> A.instances
    [<__main__.A object at 0x1004d44d0>, <__main__.A object at 0x1004d4510>]
    >>> id(A.instances)
    4299683456
    >>> id(a.instances)
    4299683456    
    >>> id(b.instances)
    4299683456    
    
  2. ==============================

    2.@ JoelCornett의 대답은 기초를 완벽하게 다룹니다. 약간 더 복잡한 버전으로 약간의 미묘한 문제를 해결하는 데 도움이 될 수 있습니다.

    @ JoelCornett의 대답은 기초를 완벽하게 다룹니다. 약간 더 복잡한 버전으로 약간의 미묘한 문제를 해결하는 데 도움이 될 수 있습니다.

    주어진 클래스의 모든 "실제"인스턴스에 액세스하려면 다음을 서브 클래스로 작성하십시오 (또는 사용자 고유의 기본 클래스에 동일한 코드를 포함 시키십시오).

    from weakref import WeakSet
    
    class base(object):
        def __new__(cls, *args, **kwargs):
            instance = object.__new__(cls, *args, **kwargs)
            if "instances" not in cls.__dict__:
                cls.instances = WeakSet()
            cls.instances.add(instance)
            return instance
    

    이것은 @JoelCornett가 제시 한보다 간단한 구현으로 두 가지 가능한 문제를 다룹니다.

    몇 가지 편리한 테스트 출력 (인스턴스 세트가 항상 잘 인쇄되지 않기 때문에 항상 목록으로 전달됨) :

    >>> b = base()
    >>> list(base.instances)
    [<__main__.base object at 0x00000000026067F0>]
    >>> class foo(base):
    ...     pass
    ... 
    >>> f = foo()
    >>> list(foo.instances)
    [<__main__.foo object at 0x0000000002606898>]
    >>> list(base.instances)
    [<__main__.base object at 0x00000000026067F0>]
    >>> del f
    >>> list(foo.instances)
    []
    
  3. ==============================

    3.인스턴스에 약한 참조를 사용하려고합니다. 그렇지 않으면 클래스는 삭제 된 인스턴스를 추적 할 수 있습니다. weakref.WeakSet은 죽은 인스턴스를 자동으로 제거합니다.

    인스턴스에 약한 참조를 사용하려고합니다. 그렇지 않으면 클래스는 삭제 된 인스턴스를 추적 할 수 있습니다. weakref.WeakSet은 죽은 인스턴스를 자동으로 제거합니다.

    인스턴스를 추적하는 한 가지 방법은 클래스 변수를 사용하는 것입니다.

    import weakref
    class A(object):
        instances = weakref.WeakSet()
    
        def __init__(self, foo):
            self.foo = foo
            A.instances.add(self)
    
        @classmethod
        def get_instances(cls):
            return list(A.instances) #Returns list of all current instances
    

    프로그램이 끝나면 다음과 같이 사전을 작성할 수 있습니다.

    foo_vars = {id (instance) : instance.foo (예 : A.instances)} 목록은 하나뿐입니다.

    >>> a = A(1)
    >>> b = A(2)
    >>> A.get_instances()
    [<inst.A object at 0x100587290>, <inst.A object at 0x100587250>]
    >>> id(A.instances)
    4299861712
    >>> id(a.instances)
    4299861712
    >>> id(b.instances)
    4299861712
    >>> a = A(3) #original a will be dereferenced and replaced with new instance
    >>> A.get_instances()
    [<inst.A object at 0x100587290>, <inst.A object at 0x1005872d0>]   
    
  4. ==============================

    4.@ 조엘 코넷 (Joe Cornett)의 대답을 사용하면 다음과 같은 것을 생각해 냈습니다. 즉 객체 변수를 합산 할 수 있습니다.

    @ 조엘 코넷 (Joe Cornett)의 대답을 사용하면 다음과 같은 것을 생각해 냈습니다. 즉 객체 변수를 합산 할 수 있습니다.

    import os
    
    os.system("clear")
    
    class Foo():
        instances = []
        def __init__(self):
            Foo.instances.append(self)
            self.x = 5
    
    class Bar():
        def __init__(self):
            pass
    
        def testy(self):
            self.foo1 = Foo()
            self.foo2 = Foo()
            self.foo3 = Foo()
    
    foo = Foo()
    print Foo.instances
    bar = Bar()
    bar.testy()
    print Foo.instances
    
    x_tot = 0
    for inst in Foo.instances:
        x_tot += inst.x
        print x_tot
    

    산출:

    [<__main__.Foo instance at 0x108e334d0>]
    [<__main__.Foo instance at 0x108e334d0>, <__main__.Foo instance at 0x108e33560>, <__main__.Foo instance at 0x108e335a8>, <__main__.Foo instance at 0x108e335f0>]
    5
    10
    15
    20
    
  5. ==============================

    5.낮은 수준의 해킹과 디버깅을위한 또 다른 옵션은 gc.get_objects ()가 반환 한 객체 목록을 필터링하고 그 방법으로 사전을 생성하는 것입니다. CPython에서 함수는 가비지 컬렉터가 알고있는 (일반적으로 거대한)리스트를 반환 할 것이므로 특정 사용자 정의 클래스의 모든 인스턴스를 확실히 포함합니다.

    낮은 수준의 해킹과 디버깅을위한 또 다른 옵션은 gc.get_objects ()가 반환 한 객체 목록을 필터링하고 그 방법으로 사전을 생성하는 것입니다. CPython에서 함수는 가비지 컬렉터가 알고있는 (일반적으로 거대한)리스트를 반환 할 것이므로 특정 사용자 정의 클래스의 모든 인스턴스를 확실히 포함합니다.

    이것은 인터프리터의 내부에 조금 들어가기 때문에 Jython, PyPy, IronPython 등과 같이 작동하지 않을 수도 있고 잘 작동하지 않을 수도 있습니다. 그것은 상관없이 정말 느릴 수도 있습니다. 주의 사항 / YMMV / etc와 함께 사용하십시오.

    그러나이 질문에 부딪히는 일부 사람들은 궁극적으로 이상하게 행동하는 코드 조각의 런타임 상태로 어떤 일이 벌어지고 있는지 파악하기 위해 이런 종류의 일을 결국 일회용으로하고 싶어한다고 생각합니다. 이 메소드는 인스턴스 또는 해당 구성에 전혀 영향을 미치지 않는 이점이 있습니다. 문제의 코드가 제 3 자 라이브러리 또는 기타에서 유출되는 경우 유용 할 수 있습니다.

  6. ==============================

    6.메타 클래스를 사용하여이 문제를 해결할 수도 있습니다.

    메타 클래스를 사용하여이 문제를 해결할 수도 있습니다.

    이 방법의 장점은 인스턴스가없는 경우에도 각 클래스에 레지스트리가 있다는 점입니다. 반대로 __new__ (Blckknght의 답처럼)를 덮어 쓰면 첫 번째 인스턴스가 만들어 질 때 레지스트리가 추가됩니다.

    class MetaInstanceRegistry(type):
        """Metaclass providing an instance registry"""
    
        def __init__(cls, name, bases, attrs):
            # Create class
            super(MetaInstanceRegistry, cls).__init__(name, bases, attrs)
    
            # Initialize fresh instance storage
            cls._instances = weakref.WeakSet()
    
        def __call__(cls, *args, **kwargs):
            # Create instance (calls __init__ and __new__ methods)
            inst = super(MetaInstanceRegistry, cls).__call__(*args, **kwargs)
    
            # Store weak reference to instance. WeakSet will automatically remove
            # references to objects that have been garbage collected
            cls._instances.add(inst)
    
            return inst
    
        def _get_instances(cls, recursive=False):
            """Get all instances of this class in the registry. If recursive=True
            search subclasses recursively"""
            instances = list(cls._instances)
            if recursive:
                for Child in cls.__subclasses__():
                    instances += Child._get_instances(recursive=recursive)
    
            # Remove duplicates from multiple inheritance.
            return list(set(instances))
    

    사용법 : 레지스트리를 작성하고 서브 클래스를 작성하십시오.

    class Registry(object):
        __metaclass__ = MetaInstanceRegistry
    
    
    class Base(Registry):
        def __init__(self, x):
            self.x = x
    
    
    class A(Base):
        pass
    
    
    class B(Base):
        pass
    
    
    class C(B):
        pass
    
    
    a = A(x=1)
    a2 = A(2)
    b = B(x=3)
    c = C(4)
    
    for cls in [Base, A, B, C]:
        print cls.__name__
        print cls._get_instances()
        print cls._get_instances(recursive=True)
        print
    
    del c
    print C._get_instances()
    

    abc 모듈의 추상 기본 클래스를 사용하는 경우 abc.ABCMeta를 서브 클래스 화하여 메타 클래스 충돌을 피하십시오.

    from abc import ABCMeta, abstractmethod
    
    
    class ABCMetaInstanceRegistry(MetaInstanceRegistry, ABCMeta):
        pass
    
    
    class ABCRegistry(object):
        __metaclass__ = ABCMetaInstanceRegistry
    
    
    class ABCBase(ABCRegistry):
        __metaclass__ = ABCMeta
    
        @abstractmethod
        def f(self):
            pass
    
    
    class E(ABCBase):
        def __init__(self, x):
            self.x = x
    
        def f(self):
            return self.x
    
    e = E(x=5)
    print E._get_instances()
    
  7. from https://stackoverflow.com/questions/12101958/how-to-keep-track-of-class-instances by cc-by-sa and MIT license