質問

誰かのコードでこれを見ました。それはどういう意味ですか?

    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文で簡単に使用できるオブジェクトを実装することができます。

アイデアは、それはいくつかの「cleandown」コード実行を(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()
        ...

としては、(あなたは、Python 2.5にしている場合は、ファイルの先頭にwithを行う必要があります)from __future__ import with_statement文で、このオブジェクトを使用して、上記で説明します。

with DatabaseConnection() as mydbconn:
    # do stuff

PEP343 - すてきな過去記事を持っているの声明 ' 'と'同様ます。

他のヒント

何かわかっていれば コンテキストマネージャー では、それ以上理解する必要はありませんか __enter__ そして __exit__ 魔法の方法。非常に簡単な例を見てみましょう。

この例では開いています マイファイル.txt の助けを借りて 開ける 関数。の 試してみて/ついに ブロックにより、予期しない例外が発生した場合でも確実に マイファイル.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) 

コードを見ると、ファイルを閉じていないので、ファイルがありません。 試してみて/ついに ブロック。なぜなら ステートメントは自動的に閉じます マイファイル.txt 。電話でも確認できます print(fp.closed) 属性 -- を返す True.

これは、ファイル オブジェクト (この例では fp) が返されるためです。 開ける 関数には 2 つの組み込みメソッドがあります __enter__ そして __exit__. 。コンテキストマネージャーとも呼ばれます。 __enter__ メソッドは開始時に呼び出されます ブロックして、 __exit__ 最後にメソッドが呼び出されます。注記: ステートメントは、コンテキスト管理プロトコルをサポートするオブジェクトでのみ機能します。つまり、彼らは持っている __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__ 魔法の方法。

は、私はそれが妙に難しいグーグルで__enter____exit__方法のためのpythonのドキュメントを検索したので、ヘルプ他の人にここにリンクがあります

https://docs.python.org/ 2 /参照/ datamodel.html#と文・コンテキスト・マネージャー
https://docs.python.org/3/reference /datamodel.html#with-statement-context-managers
(詳細は、両方のバージョンについても同様である)

  

object.__enter__(self)
  このオブジェクトに関連したランタイム・コンテキストを入力します。 with文があれば、文のよう句で指定されたターゲット(複数可)に、このメソッドの戻り値をバインドします。

     

object.__exit__(self, exc_type, exc_value, traceback)
  このオブジェクトに関連したランタイム・コンテキストを終了します。パラメータは、コンテキストが終了したことが原因となった例外を説明します。コンテキストが例外なく終了した場合は、すべての3つの引数がNoneになります。

     例外は(すなわち、伝播されるのを防ぐ)供給され、この方法は、例外を抑制することを希望している場合、

、それは真の値を返す必要があります。そうでない場合、例外は、この方法から終了時に正常に処理されます。

     

__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であるA Pythonのトレースバックの対象ます。

起動順序を例示するために上記の回答に加えて、簡単な実行例

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 ステートメント" (PEP343)、両方の実装はコンテキスト マネージャーと呼ばれます。

with ステートメントは、tryfinally 節のフロー制御を隠し、コードをわかりにくくすることを目的としています。

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

サーバー側の結果は前と同じ

私の下手な英語と不明確な説明で申し訳ありませんが、ありがとうございます...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top