파이썬 객체를 올바르게 정리하려면 어떻게합니까?
class Package:
def __init__(self):
self.files = []
# ...
def __del__(self):
for file in self.files:
os.unlink(file)
__del__(self)
위의 AttributeError 예외로 실패합니다. 이해 파이썬은 보장하지 않습니다 때 "전역 변수"(이 맥락에서 구성원 데이터?)의 존재를 __del__()
호출됩니다. 그 경우이고 이것이 예외의 이유 인 경우, 객체가 올바르게 파괴되도록하려면 어떻게해야합니까?
with
정리해야 할 리소스를 관리하기 위해 Python의 문장을 사용하는 것이 좋습니다 . 명시 적 close()
진술 을 사용할 때의 문제점 finally
은 예외가 발생했을 때 자원 누출을 방지하기 위해 전화를 잊거나 블록에 배치하는 것을 잊어 버리는 사람들에 대해 걱정해야한다는 것 입니다.
with
명령문 을 사용하려면 다음 메소드를 사용하여 클래스를 작성하십시오.
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는 패키지 유형의 인스턴스입니다 ( __enter__
메소드가 반환 한 값임 ). __exit__
예외 발생 여부에 관계없이 해당 메소드가 자동으로 호출됩니다.
이 접근법을 한 단계 더 발전시킬 수도 있습니다. 위의 예에서 누군가는 with
절 을 사용하지 않고 생성자를 사용하여 패키지를 인스턴스화 할 수 있습니다 . 당신은 그런 일이 일어나기를 원하지 않습니다. __enter__
및 __exit__
메소드 를 정의하는 PackageResource 클래스를 작성하여이 문제를 해결할 수 있습니다 . 그런 다음 Package 클래스는 __enter__
메소드 내부에 엄격하게 정의 되어 리턴됩니다. 이렇게하면 호출자는 with
명령문 을 사용하지 않고 Package 클래스를 인스턴스화 할 수 없습니다 .
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
표준 방법은 다음을 사용하는 것입니다 atexit.register
.
# 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)
그러나 이것은 Package
파이썬이 종료 될 때까지 생성 된 모든 인스턴스를 유지한다는 것을 명심해야 합니다.
package.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
.
@contextlib.contextmanager
def packageResource():
class Package:
...
package = Package()
yield package
package.cleanup()
또는 아마도 Pythonic은 아니지만 다음을 재정의 할 수 있습니다 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
사용하십시오 contextlib.closing
.이 경우 수정되지 않은 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
인스턴스 멤버 __del__
가 호출 되기 전에 제거 될 수 있다고 생각하지 않습니다 . 내 추측은 특정 AttributeError의 원인이 다른 곳 일 것입니다 (아마도 self.file을 다른 곳에서 실수로 제거 할 수 있음).
그러나 다른 사람들이 지적했듯이을 사용하지 않아야합니다 __del__
. 이것의 주된 이유는 __del__
가비지 수집되지 않은 인스턴스입니다 (참조 횟수가 0에 도달 할 때만 해제 됨). 따라서 인스턴스가 순환 참조에 관련된 경우 응용 프로그램이 실행되는 한 메모리에 존재합니다. (하지만이 모든 것에 대해 잘못 생각할 수 있습니다 .gc 문서를 다시 읽어야하지만 오히려 다음과 같이 작동한다고 확신합니다).
__init__
표시된 것보다 더 많은 코드가 있으면 문제가 발생할 수 있다고 생각 합니까?
__del__
__init__
제대로 실행되지 않았거나 예외를 던진 경우에도 호출됩니다 .
더 나은 대안은 weakref.finalize 를 사용하는 것 입니다. Finalizer 객체 및 __del __ () 메서드를 사용 하여 Finalizer 비교 예제를 참조하십시오 .
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 프록시는 파이썬이나 자신이 self.files 변수를 어떻게 든 삭제하지 못하게하는 것입니다 (삭제 된 경우 원래 파일 목록에 영향을 미치지 않음). 변수에 대한 참조가 더 있어도 삭제되지 않는 경우 프록시 캡슐화를 제거 할 수 있습니다.
최소한의 작동 골격이 있습니다.
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'
나는 이것에 반나절을 보냈다. 그것이 다음 사람에게 도움이되기를 바랍니다.
이것을하는 관용적 인 방법은 close()
메소드 (또는 유사한) 를 제공 하고 명시 적으로 호출하는 것 같습니다.
참고 URL : https://stackoverflow.com/questions/865115/how-do-i-correctly-clean-up-a-python-object
도와주세요.
'development' 카테고리의 다른 글
텍스트 영역에서 jQuery 커서 위치 설정 (0) | 2020.02.18 |
---|---|
C #에서 다차원 배열과 배열 배열의 차이점은 무엇입니까? (0) | 2020.02.18 |
파이썬에서 인식하지 못하는 날짜 시간 시간대를 인식시키는 방법 (0) | 2020.02.18 |
collections.defaultdict는 어떻게 작동합니까? (0) | 2020.02.18 |
우분투에서 ssh-add로 개인 키를 영구적으로 추가하는 방법은 무엇입니까? (0) | 2020.02.18 |