programing

Python 개체를 올바르게 정리하려면 어떻게 해야 합니까?

firstcheck 2022. 10. 18. 21:44
반응형

Python 개체를 올바르게 정리하려면 어떻게 해야 합니까?

class Package:
    def __init__(self):
        self.files = []

    # ...

    def __del__(self):
        for file in self.files:
            os.unlink(file)

__del__(self)AttributError 예외로 인해 장애가 발생합니다.Python은 다음과 같은 경우에 "글로벌 변수"(이 컨텍스트의 멤버 데이터)의 존재를 보증하지 않는 것으로 알고 있습니다.__del__() 이런 어떻게 요?이것이 예외의 이유일 경우 오브젝트가 올바르게 파괴되도록 하려면 어떻게 해야 합니까?

Python을 하는 것을 with정리해야 하는 리소스를 관리하기 위한 문입니다. 사용 close()이 있는 것을 .finally예외 발생 시 리소스 누출을 방지하기 위해 block을 클릭합니다.

「 」를 withstatement adda, adda의 .

  def __enter__(self)
  def __exit__(self, exc_type, exc_value, traceback)

위의 예에서는 다음을 사용합니다.

class Package:
    def __init__(self):
        self.files = []

    def __enter__(self):
        return self

    # ...

    def __exit__(self, exc_type, exc_value, traceback):
        for file in self.files:
            os.unlink(file)

그런 다음 다른 사람이 당신의 수업을 사용하려고 하면 다음과 같이 합니다.

with Package() as package_obj:
    # use package_obj

유형의 인스턴스가 (Package_obj "Package"에 입니다).__enter__메서드).그것의.__exit__예외 발생 여부에 관계없이 메서드가 자동으로 호출됩니다.

한 걸음 더 나아갈 수도 있습니다.할 수 .이러한 예에서는 생성자를 하지 않아도 .with절을 클릭합니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ PackageResource 클래스를 .__enter__ ★★★★★★★★★★★★★★★★★」__exit__ 클래스는 말하면 패키지 클래스가 됩니다.__enter__메서드를 반환했습니다.는 「」를 할 수 .with★★★★★★★★

class PackageResource:
    def __enter__(self):
        class Package:
            ...
        self.package_obj = Package()
        return self.package_obj

    def __exit__(self, exc_type, exc_value, traceback):
        self.package_obj.cleanup()

다음과 같이 사용할 수 있습니다.

with PackageResource() as package_obj:
    # use package_obj

표준적인 방법은 다음과 같습니다.

# package.py
import atexit
import os

class Package:
    def __init__(self):
        self.files = []
        atexit.register(self.cleanup)

    def cleanup(self):
        print("Running cleanup...")
        for file in self.files:
            print("Unlinking file: {}".format(file))
            # os.unlink(file)

, 이 생성된 는 그대로 해야 합니다.PackagePython 。

패키지로 저장된 위의 코드를 사용하여 데모합니다.py:

$ python
>>> from package import *
>>> p = Package()
>>> q = Package()
>>> q.files = ['a', 'b', 'c']
>>> quit()
Running cleanup...
Unlinking file: a
Unlinking file: b
Unlinking file: c
Running cleanup...

Clint의 답변에 대한 부록으로서PackageResource사용:

@contextlib.contextmanager
def packageResource():
    class Package:
        ...
    package = Package()
    yield package
    package.cleanup()

수도 , ,, 처, 토, 선, 선, 선, 선, 선, 선, 선, 선, 선을 덮어쓸 .Package.__new__:

class Package(object):
    def __new__(cls, *args, **kwargs):
        @contextlib.contextmanager
        def packageResource():
            # adapt arguments if superclass takes some!
            package = super(Package, cls).__new__(cls)
            package.__init__(*args, **kwargs)
            yield package
            package.cleanup()

    def __init__(self, *args, **kwargs):
        ...

사용하시면 됩니다.with Package(...) as package.

을 짧게 기능의 을 대세요.close및 use를 사용합니다.이 경우 수정되지 않은 명령어를 사용할 수 있습니다.Package 통한 with contextlib.closing(Package(...)) 그 「」를 .__new__ 말하면

class Package(object):
    def __new__(cls, *args, **kwargs):
        package = super(Package, cls).__new__(cls)
        package.__init__(*args, **kwargs)
        return contextlib.closing(package)

그리고 이 생성자는 상속되므로 간단히 상속할 수 있습니다.

class SubPackage(Package):
    def close(self):
        pass

더 나은 대안은 weakref를 사용하는 것입니다.마무리짓다Finalizer Objects 및 __del_() 메서드를 사용한 파이널라이저 비교 예제를 참조하십시오.

before스턴 to i i i 、 to to 、 인 members 、 i i 、 i i 、 i i 、 i i 、 i i 、 i i 、 i i 、 i i i 。__del__ 은 다른해서 자신을삭제했을 수도 ).특정 AttributeError의 원인은 다른 곳에 있을 것으로 추측됩니다(실수로 자신을 삭제했을 가능성이 있습니다).하다

다른 처럼 ,, 른, 른, 다, 다, 다, 다, 다, 다, 다, 니, 니, 니, however, however, however, however, however, however, however, however, however, however, however, however, however, however ,__del__는 . 하다, 하다, 하다, 하다, 이런 경우가 있기 __del__가비지가 수집되지 않습니다(refcount가 0에 도달한 경우에만 해방됩니다).따라서 인스턴스가 순환 참조에 관련되어 있는 경우 응용 프로그램이 실행되는 한 해당 인스턴스는 메모리에 계속 남아 있습니다(단, gc 문서를 다시 읽어야 하지만 이렇게 동작할 수 있다고 확신합니다).

다음은 최소한의 동작 스켈레톤입니다.

class SkeletonFixture:

    def __init__(self):
        pass

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        pass

    def method(self):
        pass


with SkeletonFixture() as fixture:
    fixture.method()

중요: 리턴 셀프


이고, 주는 사람이고, 눈감아 주는 이고, 눈감아 주는 사람이고, 눈감아 주는 사람이고, 눈감아 주는 사람이고, 눈감아 주는 사람이고, 눈감아 주는 사람이고, 눈감아 주는 사람이고.return self(클린트 밀러의 정답 중) 당신은 이 말도 안 되는 것을 보게 될 것이다.

Traceback (most recent call last):
  File "tests/simplestpossible.py", line 17, in <module>                                                                                                                                                          
    fixture.method()                                                                                                                                                                                              
AttributeError: 'NoneType' object has no attribute 'method'

다음 사람에게 도움이 되길 바랍니다.

가 될 수 합니다.__init__표시된 것보다 더 많은 코드가 있는 경우

__del__ __init__제대로 실행되지 않았거나 예외가 발생했습니다.

원천

destructor를 try/except 문장으로 감싸기만 하면 글로벌이 이미 폐기된 경우 예외가 발생하지 않습니다.

편집

이것을 시험해 보세요.

from weakref import proxy

class MyList(list): pass

class Package:
    def __init__(self):
        self.__del__.im_func.files = MyList([1,2,3,4])
        self.files = proxy(self.__del__.im_func.files)

    def __del__(self):
        print self.__del__.im_func.files

콜 시에 존재하는 것이 보증되는 del 함수에 파일목록을 채웁니다.weakref 프록시는 Python 또는 자신의 셀프 삭제를 방지하는 것입니다.files variable (삭제해도 원래 파일 목록에는 영향을 주지 않습니다)변수에 대한 참조가 많아도 삭제되지 않으면 프록시 캡슐화를 삭제할 수 있습니다.

이 작업을 수행하는 관용적인 방법은 다음과 같은 정보를 제공하는 것 같습니다.close()방법(또는 유사)을 설명으로 부릅니다.

atexit.register오스트라카흐의 답변에 이미 언급된 표준적인 방법입니다.

단, 아래 예시와 같이 오브젝트가 삭제될 가능성이 있는 순서는 신뢰할 수 없습니다.

import atexit

class A(object):

    def __init__(self, val):
        self.val = val
        atexit.register(self.hello)

    def hello(self):
        print(self.val)


def hello2():
    a = A(10)

hello2()    
a = A(20)

여기서 순서는 프로그램으로 오브젝트가 생성된 순서의 역순으로 다음과 같이 출력됩니다.

20
10

그러나 더 큰 프로그램에서 파이썬의 수명이 다한 오브젝트를 발로 차게 되면 파이썬의 가비지 컬렉션이 먼저 파괴됩니다.

가장 좋은 방법은 두 가지 방법을 결합하는 것입니다.

명시적인 라이프 사이클 처리를 위한 컨텍스트 매니저를 구현합니다.또한 사용자가 이를 잊어버렸거나 문과 함께 사용하는 것이 편리하지 않은 경우에 대비한 청소도 수행합니다.이것은 weakref에 의해 가장 잘 수행된다.마무리짓다

많은 도서관들이 실제로 이렇게 하고 있습니다.또한 심각도에 따라 경고를 보낼 수도 있습니다.

import os
from typing import List
import weakref

class Package:
    def __init__(self):
        self.files = []
        self._finalizer = weakref.finalize(self, self._cleanup_files, self.files)

    @staticmethod
    def _cleanup_files(files: List):
        for file in files:
            os.unlink(file)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self._finalizer()

"weakref.finalize는 obj가 가비지 수집되었을 때 호출되는 호출 가능한 피니셔 객체를 반환합니다.일반적인 약한 레퍼런스와는 달리 피니셔는 레퍼런스 오브젝트가 수집될 때까지 항상 존속하기 때문에 라이프 사이클 관리가 대폭 간소화됩니다."

atexit.register와는 달리 오브젝트는 인터프리터가 셧다운될 때까지 메모리에 유지되지 않습니다.

그리고 물건과는 다르게.__del__,weakref.finalize인터프리터 셧다운 시 콜이 보증됩니다.그래서 훨씬 더 안전하다.

언급URL : https://stackoverflow.com/questions/865115/how-do-i-correctly-clean-up-a-python-object

반응형