나는 누군가의 코드에서 이것을 보았다. 무슨 뜻이에요?
def __enter__(self):
return self
def __exit__(self, type, value, tb):
self.stream.close()
from __future__ import with_statement#for python2.5
class a(object):
def __enter__(self):
print 'sss'
return 'sss111'
def __exit__(self ,type, value, traceback):
print 'ok'
return False
with a() as s:
print s
print s
답변
이러한 마법 메서드 ( __enter__
, __exit__
)를 사용하면 with
명령문 과 함께 쉽게 사용할 수있는 객체를 구현할 수 있습니다 .
아이디어는 실행 된 ‘정리’코드가 필요한 코드를 쉽게 빌드 할 수 있도록하는 것입니다 ( try-finally
블록 으로 생각하십시오 ). 여기에 더 많은 설명이 있습니다 .
유용한 예는 데이터베이스 연결 객체 일 수 있습니다 (해당 ‘with’문이 범위를 벗어나면 자동으로 연결을 닫습니다).
class DatabaseConnection(object):
def __enter__(self):
# make a database connection and return it
...
return self.dbconn
def __exit__(self, exc_type, exc_val, exc_tb):
# make sure the dbconnection gets closed
self.dbconn.close()
...
위에서 설명한 것처럼,이 객체를 with
명령문 과 함께 사용하십시오 ( from __future__ import with_statement
Python 2.5를 사용하는 경우 파일 맨 위에서 수행해야 할 수도 있음 ).
with DatabaseConnection() as mydbconn:
# do stuff
PEP343- ‘with’문 은 잘 쓰여져 있습니다.
답변
컨텍스트 관리자 가 무엇인지 아는 경우 더 이상 마술 __enter__
과 __exit__
방법 을 이해할 필요가 없습니다 . 아주 간단한 예를 보자.
이 예제에서는 open 함수를 사용 하여 myfile.txt 를 엽니 다 . 시도는 / 마지막으로 예기치 않은 예외가 발생하더라도 보장하지만 차단 MYFILE.TXT가 폐쇄됩니다.
fp=open(r"C:\Users\SharpEl\Desktop\myfile.txt")
try:
for line in fp:
print(line)
finally:
fp.close()
이제 문을 사용 하여 동일한 파일을 엽니 다 .
with open(r"C:\Users\SharpEl\Desktop\myfile.txt") as fp:
for line in fp:
print(line)
코드를 보면 파일을 닫지 않았으며 시도 / 결국 차단 이 없습니다 . 때문에 함께 문이 자동으로 닫힙니다 MYFILE.TXT를 . print(fp.closed)
attribute-를 반환 하여 확인할 수도 있습니다 True
.
파일에 의해 반환 (내 예제에서 FP) 오브젝트 때문이다 개방 이 내장 된 방법 기능 __enter__
과 __exit__
. 컨텍스트 관리자라고도합니다. with 블록 __enter__
의 시작 부분 에__exit__
메소드가 호출되고 마지막에 메소드가 호출됩니다. 참고 : with 문은 컨텍스트 결합 프로토콜을 지원하는 객체 (예 : 객체 __enter__
및 __exit__
메소드) 에서만 작동 합니다. 두 가지 방법을 모두 구현하는 클래스를 컨텍스트 관리자 클래스라고합니다.
이제 자체 컨텍스트 관리자 클래스를 정의하십시오 .
class Log:
def __init__(self,filename):
self.filename=filename
self.fp=None
def logging(self,text):
self.fp.write(text+'\n')
def __enter__(self):
print("__enter__")
self.fp=open(self.filename,"a+")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("__exit__")
self.fp.close()
with Log(r"C:\Users\SharpEl\Desktop\myfile.txt") as logfile:
print("Main")
logfile.logging("Test1")
logfile.logging("Test2")
나는 이제 당신이 마술 방법 __enter__
과 기본적인 __exit__
방법 을 모두 이해하기를 바랍니다 .
답변
Googling 이 파이썬 문서 __enter__
와 __exit__
메소드 를 찾는 것이 이상하게 어렵다는 것을 알았 으므로 다른 사람들을 돕기 위해 링크가 있습니다.
https://docs.python.org/2/reference/datamodel.html#with-statement-context-managers
https://docs.python.org/3/reference/datamodel.html#with-statement-context-managers
(세부 사항 모두 동일합니다)
object.__enter__(self)
이 객체와 관련된 런타임 컨텍스트를 입력하십시오.with
문은 명령문의 같은 절에 지정된 대상 (들)이 메소드의 반환 값 (있는 경우)를 결합합니다.
object.__exit__(self, exc_type, exc_value, traceback)
이 객체와 관련된 런타임 컨텍스트를 종료하십시오. 매개 변수는 컨텍스트를 종료시킨 예외를 설명합니다. 컨텍스트가 예외없이 종료 된 경우 세 인수는 모두None
입니다.예외가 제공되고 메소드가 예외를 억제 (예 : 전파되지 않도록)하려는 경우 true 값을 리턴해야합니다. 그렇지 않으면이 메소드를 종료하면 예외가 정상적으로 처리됩니다.
참고
__exit__()
방법은 리 레이즈 안 전달 된 예외; 이것이 발신자의 책임입니다.
__exit__
메소드 인수 에 대한 명확한 설명을 원했습니다 . 이것은 부족하지만 우리는 그들을 추론 할 수 있습니다 …
아마도 exc_type
예외의 클래스 일 것입니다.
전달 된 예외를 다시 발생시키지 말아야합니다. 이것은 우리에게 인수 중 하나가 실제 예외 인스턴스 일 수 있음을 제안합니다 … 또는 아마도 유형과 값에서 직접 인스턴스화해야합니까?
우리는이 기사를보고 대답 할 수 있습니다 :
http://effbot.org/zone/python-with-statement.htm
예를 들어 다음
__exit__
메소드는 모든 TypeError를 삼키지 만 다른 모든 예외는 통과시킵니다.
def __exit__(self, type, value, traceback):
return isinstance(value, TypeError)
… value
예외 인스턴스입니다.
그리고 아마도 traceback
파이썬 역 추적 객체 일 것입니다.
답변
호출 순서를 예시하는 위의 답변 외에도 간단한 실행 예
class myclass:
def __init__(self):
print("__init__")
def __enter__(self):
print("__enter__")
def __exit__(self, type, value, traceback):
print("__exit__")
def __del__(self):
print("__del__")
with myclass():
print("body")
출력을 생성합니다.
__init__
__enter__
body
__exit__
__del__
알림 : 구문을 사용할 때 with myclass() as mc
변수 mc는 __enter__()
위의 경우에 의해 반환 된 값을 가져옵니다 None
! 이러한 용도로 사용하려면 다음과 같은 반환 값을 정의해야합니다.
def __enter__(self):
print('__enter__')
return self
답변
내 답변을 추가하십시오 (학습에 대한 생각) :
__enter__
그리고 [__exit__]
둘 다 ” with statement “( PEP 343 ) 본문에 들어오고 나갈 때 호출되는 메소드 이며 둘 다 구현을 컨텍스트 관리자라고합니다.
with 문은 try finally 절의 흐름 제어를 숨기고 코드를 조사 할 수 없게 만듭니다.
with 문의 구문은 다음과 같습니다.
with EXPR as VAR:
BLOCK
(PEP 343에서 언급 한 바와 같이) :
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)
몇 가지 코드를 사용해보십시오.
>>> import logging
>>> import socket
>>> import sys
#server socket on another terminal / python interpreter
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.listen(5)
>>> s.bind((socket.gethostname(), 999))
>>> while True:
>>> (clientsocket, addr) = s.accept()
>>> print('get connection from %r' % addr[0])
>>> msg = clientsocket.recv(1024)
>>> print('received %r' % msg)
>>> clientsocket.send(b'connected')
>>> continue
#the client side
>>> class MyConnectionManager:
>>> def __init__(self, sock, addrs):
>>> logging.basicConfig(level=logging.DEBUG, format='%(asctime)s \
>>> : %(levelname)s --> %(message)s')
>>> logging.info('Initiating My connection')
>>> self.sock = sock
>>> self.addrs = addrs
>>> def __enter__(self):
>>> try:
>>> self.sock.connect(addrs)
>>> logging.info('connection success')
>>> return self.sock
>>> except:
>>> logging.warning('Connection refused')
>>> raise
>>> def __exit__(self, type, value, tb):
>>> logging.info('CM suppress exception')
>>> return False
>>> addrs = (socket.gethostname())
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> with MyConnectionManager(s, addrs) as CM:
>>> try:
>>> CM.send(b'establishing connection')
>>> msg = CM.recv(1024)
>>> print(msg)
>>> except:
>>> raise
#will result (client side) :
2018-12-18 14:44:05,863 : INFO --> Initiating My connection
2018-12-18 14:44:05,863 : INFO --> connection success
b'connected'
2018-12-18 14:44:05,864 : INFO --> CM suppress exception
#result of server side
get connection from '127.0.0.1'
received b'establishing connection'
이제 수동으로 시도하십시오 (번역 구문에 따라).
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #make new socket object
>>> mgr = MyConnection(s, addrs)
2018-12-18 14:53:19,331 : INFO --> Initiating My connection
>>> ext = mgr.__exit__
>>> value = mgr.__enter__()
2018-12-18 14:55:55,491 : INFO --> connection success
>>> exc = True
>>> try:
>>> try:
>>> VAR = value
>>> VAR.send(b'establishing connection')
>>> msg = VAR.recv(1024)
>>> print(msg)
>>> except:
>>> exc = False
>>> if not ext(*sys.exc_info()):
>>> raise
>>> finally:
>>> if exc:
>>> ext(None, None, None)
#the result:
b'connected'
2018-12-18 15:01:54,208 : INFO --> CM suppress exception
이전과 동일한 서버 측의 결과
나의 나쁜 영어와 나의 불명확 한 설명에 대해 죄송합니다, 감사합니다 ….
답변
이것을 컨텍스트 관리자라고하며 다른 프로그래밍 언어에 대해 비슷한 접근법이 존재한다고 덧붙이고 싶습니다. 그것들을 비교하면 파이썬의 컨텍스트 관리자를 이해하는 데 도움이 될 수 있습니다. 기본적으로 컨텍스트 관리자는 초기화해야하는 일부 리소스 (파일, 네트워크, 데이터베이스)를 처리 할 때 사용되며 어느 시점에서 해제 (처리)됩니다. Java 7 이상 에는 다음 과 같은 형식의 자동 자원 관리 기능이 있습니다.
//Java code
try (Session session = new Session())
{
// do stuff
}
Session AutoClosable
은 (다수의) 하위 인터페이스 중 하나 를 구현해야합니다 .
C # 에서는 다음 과 같은 형식의 리소스를 관리하기위한 명령문을 사용합니다.
//C# code
using(Session session = new Session())
{
... do stuff.
}
어느 Session
것을 구현해야합니까 IDisposable
?
에 파이썬 , 우리가 사용하는 클래스를 구현해야 __enter__
하고 __exit__
. 따라서 다음과 같은 형태를 취합니다.
#Python code
with Session() as session:
#do stuff
그리고 다른 사람들이 지적했듯이 모든 언어에서 try / finally 문을 사용하여 동일한 메커니즘을 구현할 수 있습니다. 이것은 단지 구문 설탕입니다.