[PYTHON] 클래스 인스턴스를 추적하는 방법?
PYTHON클래스 인스턴스를 추적하는 방법?
프로그램의 끝으로 클래스의 모든 인스턴스에서 특정 변수를 사전에로드하려고합니다.
예 :
class Foo():
__init__(self):
x = {}
foo1 = Foo()
foo2 = Foo()
foo...etc.
인스턴스의 수가 달라지고 Foo ()의 각 인스턴스에서 x dict이 새로운 dict에로드되기를 원한다고 가정 해 보겠습니다. 내가 어떻게 그럴 수 있니?
내가 본 예는 이미 인스턴스 목록을 가지고 있다고 가정합니다.
해결법
-
==============================
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.@ 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.인스턴스에 약한 참조를 사용하려고합니다. 그렇지 않으면 클래스는 삭제 된 인스턴스를 추적 할 수 있습니다. 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.@ 조엘 코넷 (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.낮은 수준의 해킹과 디버깅을위한 또 다른 옵션은 gc.get_objects ()가 반환 한 객체 목록을 필터링하고 그 방법으로 사전을 생성하는 것입니다. CPython에서 함수는 가비지 컬렉터가 알고있는 (일반적으로 거대한)리스트를 반환 할 것이므로 특정 사용자 정의 클래스의 모든 인스턴스를 확실히 포함합니다.
낮은 수준의 해킹과 디버깅을위한 또 다른 옵션은 gc.get_objects ()가 반환 한 객체 목록을 필터링하고 그 방법으로 사전을 생성하는 것입니다. CPython에서 함수는 가비지 컬렉터가 알고있는 (일반적으로 거대한)리스트를 반환 할 것이므로 특정 사용자 정의 클래스의 모든 인스턴스를 확실히 포함합니다.
이것은 인터프리터의 내부에 조금 들어가기 때문에 Jython, PyPy, IronPython 등과 같이 작동하지 않을 수도 있고 잘 작동하지 않을 수도 있습니다. 그것은 상관없이 정말 느릴 수도 있습니다. 주의 사항 / YMMV / etc와 함께 사용하십시오.
그러나이 질문에 부딪히는 일부 사람들은 궁극적으로 이상하게 행동하는 코드 조각의 런타임 상태로 어떤 일이 벌어지고 있는지 파악하기 위해 이런 종류의 일을 결국 일회용으로하고 싶어한다고 생각합니다. 이 메소드는 인스턴스 또는 해당 구성에 전혀 영향을 미치지 않는 이점이 있습니다. 문제의 코드가 제 3 자 라이브러리 또는 기타에서 유출되는 경우 유용 할 수 있습니다.
-
==============================
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()
from https://stackoverflow.com/questions/12101958/how-to-keep-track-of-class-instances by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] Matplotlib로 2D 히트 맵 그리기 (0) | 2018.10.13 |
---|---|
[PYTHON] 디버그 모드에서 pyspark를 어떻게 호출 할 수 있습니까? (0) | 2018.10.13 |
[PYTHON] 파이썬 / NumPy 하위 배열의 첫 번째 항목 (0) | 2018.10.13 |
[PYTHON] 연결 할당은 어떻게 작동합니까? (0) | 2018.10.13 |
[PYTHON] 파이썬은 setInterval ()과 동등한가요? (0) | 2018.10.13 |