2014-02-25 3 views
1

테스트 목적으로 다른 테스트 메소드를 실행하기 전에 삭제할 임시 클래스를 만듭니다. 문제는 [superclass].__subclasses__()가 가비지 수집을 실행 한 후에도 삭제 된 클래스를 계속 나열한다는 것입니다.가비지 수집은 인스턴스 할당 후 클래스의 del을 인식하지 못합니다.

class Apple(Fruit): 
    @staticmethod 
    def mass(size): 
     return size 

class Orange(Fruit): 
    @staticmethod 
    def mass(size): 
     return size 

try: 
    Apple() 
    Orange() 
    a1 = Apple(type='fuji') 
finally: 
    if 'a1' in locals(): 
     print 'del a1' 
     del a1 
    print gc.get_referrers(Apple) 
    print gc.get_referrers(Orange) 
    del Apple 
    del Orange 
    print Fruit.__subclasses__() 
    gc.collect() 
    print Fruit.__subclasses__() 

출력은 다음과 같다 :

여기처럼 내 시험 방법은 어떻게 표시되는지를 보여줍니다 Fruit__metaclass__ = abc.ABCMeta를 사용 않지만, 관련된 클래스의

del a1 
[<frame object at 0xabcdef0>, (<class 'Apple'>, <class 'Fruit'>, <type 'object'>), <Apple object at 0x4443331>, {'a1': <Apple object at 0x4443331, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}]  
[<frame object at 0xabcdef0>, (<class 'Orange'>, <class 'Fruit'>, <type 'object'>), {'a1': <Apple object at 0x4443331, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}] 
[<class 'Apple'>, <class 'Orange'>] 
[<class 'Apple'>, <class 'Orange'>] 

없음이 __del__()을 명시 적으로 정의가 없으며, a @abc.abstractmethod 데코레이터 사용시 Fruit.mass().

나머지 클래스 참조는 변수에 Fruit 인스턴스의 할당을 함께 할 수있는 뭔가가 : 나는 a1, 최종 Fruit.__subclasses__() 반환 []을 포함하는 모든 행을 제거하는 경우 - 베어 생성자 Apple()은 여전히 ​​실행되는 경우에도. 또 다른 시험 (관련 메소드 실험용 blends() 전화) 과일의 상호 작용에 관심을, 그리고 그 Fruit의 다른 유형의 조합을 확인하는 Fruit.__subclasses__() 전화를 사용하기 때문에

이 나를 위해 문제입니다. 나는이 테스트 클래스들과의 상호 작용을 정의하는데 신경 쓰지 않았고, 그것은 혼란 스럽다. blends().

이러한 참조가 왜 고수하고 있는지에 대한 힌트를 주시면 감사하겠습니다.

편집 : gc.collect() 후에 gc.get_referrers (Apple)을 호출하면 할당 전에 "UnboundLocalError : 로컬 변수 'Apple'이 참조됩니다."Fruit이 "@classmethod"및 "@property"장식, 참고 문헌 또 "블렌드()"처리 클래스 ... 쓰레기 수거 후

, gc.get_referrers(Fruit.__subclasses__()[0]) 반환

[{'a1': <Apple object at 0x4443331>, 'self': <FruitTests testMethod=test_pass_Fruit_core>, 'Orange': <class 'Orange'>, 'Apple': <class 'Apple'>}, <Apple object at 0x4443331>, (<class 'Apple'>, <class 'Fruit'>, <type 'object'>)] 

편집 : 난 그냥이 하나 개의 시험 방법 실행할 때 문제가 발생합니다 . (여러 테스트를 큐에 넣을 때도 발생합니다.) IDE (PyCharm)를 재부팅하고 명령 줄에서 "./manage.py test FruitTests.test_pass_Fruit_core"를 실행 해 보았습니다. 특정 메모리 주소는 다양하지만 모든 경우에 동일한 결과가 산출됩니다. 지역 주민()이 직접 전화를 받고 있습니다. 아무데도 별명을 지정하지 않았습니다.

편집 : 과일 정의 전체 모듈 : 시험 방법

from abc import abstractmethod, ABCMeta 


class Fruit(object): 
    __metaclass__ = ABCMeta 

    def __init__(self, **kwargs): 
     super(Fruit, self).__init__() 

    @abstractmethod 
    def mass(self, size): 
     raise NotImplementedError 

는 test_pass_Fruit_core()는 'A1 = 애플()'및 'A1 = 애플 (타입 ='후지 ') "를 생산 같은 결과. "a1"에 할당을 취소해도 아무런 효과가 없지만 "locals()"에 대한 호출을 중단하면 가비지 수집이 예상대로 작동합니다. Apple은 메소드의 끝에서 더 이상 Fruit의 하위 클래스로 사용할 수 없습니다.

+0

그리고'gc.get_referrers는 (애플)'쓰레기 수거 후 무엇을 인쇄 않습니다 클래스 애플 (과일) : @staticmethod 데프 질량 (크기) 위의 첫 번째 코드 블록과 비교? –

+0

하위 클래스에 대한 참조는 약한 참조이므로 다른 *는 여전히이 클래스를 참조합니다. ABC 아키텍처에도 참조가 있고 약한 참조가 사용됩니다. –

+0

'gc.gen_referrers (과일 .__ 하위 클래스 __() [0])'을 사용하십시오. –

답변

0

locals() 호출에서 영구 참조가 생성됩니다. "del a1"이 "try :"블록 내에 작성된 경우 오류를 생성하지 않으려면 블록 앞에 "a1 = None"을 할당하고 locals()에 대한 호출을 건너 뜁니다.

최종 작업 코드는 다음과 같습니다. 반환 크기

class Orange(Fruit): 
    @staticmethod 
    def mass(size): 
     return size 

a1 = None 
try: 
    Apple() 
    Orange() 
    a1 = Apple(type='fuji') 
finally: 
    del a1 
    print gc.get_referrers(Apple) 
    print gc.get_referrers(Orange) 
    del Apple 
    del Orange 
    print Fruit.__subclasses__() 
    gc.collect() 
    sc = Fruit.__subclasses__() 
    print sc 
    if len(sc) > 0: 
     print 42, gc.get_referrers(sc[0]) 
0

가비지 수집 환경에서 개체의 수명이 이 아니므로을 담당해야합니다. 그리고 이것 때문에, 당신은 그것에 의지해서는 안됩니다. 단위 테스트는 비즈니스 논리를 테스트해야하며 각 단위 테스트는 단위 책임 중 하나를 테스트해야합니다. 개체 수명 시간은 책임이 될 수 없으며 논리에 의존하는 경우 잘못된 환경을 사용하거나 현재 환경을 잘못 사용하는 것입니다.

아마도 Pool 또는/및 Factory과 같은 패턴을 사용하여 구현에 "활성"Fruit이라는 개념을 도입하려고합니다. "활성"객체의 목록에서 객체를 삭제하면 GS의 "비결정론"에 대해 걱정할 필요가 없습니다.

+0

테스트에서만 사용되는 속성을 소개하는 것은 어색합니다. 위 테스트의 목적은 @ abc.abstractmethod 데코레이터가 있고 광고 된대로 작동하는지 확인하는 것입니다. (즉,이 클래스는 서브 클래스가 질량의 명시적인 정의를 제공하는 경우에만 인스턴스화 할 수 있습니다.) –

+0

@SarahMesser 다시 사용자의 책임이 아닌 것을 테스트하는 것으로 보입니다. 'abc' 모듈은 올바르게 작동 하는지를 증명하는 자체 단위 테스트를 가져야합니다. – BartoszKP