পাইথনের '__enter__' এবং '__exit__' ব্যাখ্যা


360

আমি এটি কারও কোডে দেখেছি। এর মানে কী?

    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

19
এখানে একটি ভাল ব্যাখ্যা: effbot.org/zone/python-with-statement.htm
মনুর

7
@ স্টিভেনভ্যাসেলালো একটি প্রশ্নের কোড সম্পাদনা করা সাধারণত একটি খারাপ ধারণা, বিশেষত যখন কোডটিতে ত্রুটি থাকে are এই প্রশ্নটি পাই 2 কে মাথায় রেখে জিজ্ঞাসা করা হয়েছিল এবং এটি পি 3 তে আপডেট করার কোনও কারণ নেই।
jpaugh

উত্তর:


419

এই যাদু পদ্ধতিগুলি ( __enter__, __exit__) ব্যবহারের সাহায্যে আপনি অবজেক্টগুলি কার্যকর করতে পারবেন যা withবিবৃতি দিয়ে সহজেই ব্যবহার করা যেতে পারে ।

ধারণাটি হ'ল এটি কোড তৈরি করা সহজ করে যার জন্য কিছু 'ক্ল্যান্ডাউন' কোড কার্যকর করা প্রয়োজন (এটিকে একটি try-finallyব্লক হিসাবে মনে করুন )। আরও কিছু ব্যাখ্যা এখানে

একটি দরকারী উদাহরণ একটি ডাটাবেস সংযোগ অবজেক্ট হতে পারে (যা স্বয়ংক্রিয়ভাবে সংশ্লিষ্ট 'উইথ-স্টেটমেন্টের বাইরে চলে যাওয়ার পরে সংযোগটি বন্ধ করে দেয়):

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পাইথন ২.২ এ থাকলে আপনাকে ফাইলের শীর্ষে করতে হবে)।

with DatabaseConnection() as mydbconn:
    # do stuff

পিইপি 343 - 'উইথ স্টেটমেন্ট'- এর পাশাপাশি একটি সুন্দর লেখার ব্যবস্থা রয়েছে।


20
সম্ভবত, __enter__ফেরত পাঠাবেন selfসবসময় তারপর ক্লাসের শুধুমাত্র অন্যান্য পদ্ধতি প্রসঙ্গ আহ্বান করা যেতে পারে।
viFI

3
@ ভিআইএফআই def __enter__(self)পিইপি 343 এর 4 টি উদাহরণ রয়েছে এবং কেউই করেন না return self: পাইথন.আর / দেবদেব / পেপস / পেপ-0343 । আপনি কেন সেটা মনে করেন?
দুঃখ

4
@Grief: 2 কারণে, আমার মতে, 1) আমি অন্য পদ্ধতি কল করতে সক্ষম হবে selfঅবজেক্ট হিসেবে এখানে ব্যাখ্যা করেছিলেন: stackoverflow.com/questions/38281853/... 2) self.XYZ স্ব বস্তুর শুধু অংশ এবং কেবলমাত্র এটির কাছে হ্যান্ডেল ফিরিয়ে দেওয়া আমার কাছে দেখার রক্ষণাবেক্ষণ থেকে অনুচিত। পরিবর্তে আমি সম্পূর্ণ অবজেক্টে হ্যান্ডেলটি ফিরে যেতে পছন্দ করব এবং তারপরে কেবলমাত্র সেই উপাদানগুলির selfঅবজেক্টে পাবলিক এপিআই সরবরাহ করব, যা আমি এর মতো ব্যবহারকারীর কাছে প্রকাশ করতে চাই with open(abc.txt, 'r') as fin: content = fin.read()
viFI

4
ফাইল বস্তু আসতে selfথেকে __enter__, যা কিভাবে যাই হিসাবে ফাইল প্রক্রিয়া করতে পারি fভিতরেwith open(...) as f
holdenweb

2
একটি সূক্ষ্মতা আমাকে বুঝতে হয়েছিল: যদি বস্তুর আরম্ভের জন্য প্যারামিটারগুলির প্রয়োজন হয়, সেগুলি নিজেই নয়, ইনপিতে থাকা উচিত ।
dfrankow

70

আপনি যদি কনটেক্সট ম্যানেজারগুলি কী তা জানেন তবে আপনার __enter__আর __exit__ম্যাজিক পদ্ধতিগুলি বোঝার দরকার নেই । একটি খুব সহজ উদাহরণ দেখতে দিন।

এই উদাহরণে আমি খোলার করছি 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)অ্যাট্রিবিউটকে কল করেও এটি পরীক্ষা করতে পারেন - যা প্রত্যাবর্তন করে True

এটি কারণ খোলা ফাংশন দ্বারা ফিরিয়ে দেওয়া ফাইল অবজেক্টস (আমার উদাহরণে fp) দুটি বিল্ট-ইন পদ্ধতি __enter__এবং __exit__। এটি প্রসঙ্গ পরিচালক হিসাবেও পরিচিত। __enter__পদ্ধতিটিকে ব্লক সহ শুরুতে বলা হয় এবং __exit__ পদ্ধতিটিকে শেষে বলা হয়। নোট: সঙ্গে বিবৃতি শুধুমাত্র বস্তু যা প্রেক্ষাপটে mamangement প্রোটোকল সমর্থন অর্থাত তারা আছে সাথে কাজ করে __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__যাদু পদ্ধতিগুলির প্রাথমিক ধারণা রয়েছে understanding


52

গুগলিংয়ের দ্বারা পাইথন ডক্স __enter__এবং __exit__পদ্ধতিগুলি সনাক্ত করা আমার কাছে আশ্চর্যজনকভাবে জটিল মনে হয়েছিল, তাই অন্যকে এখানে সহায়তা করার জন্য এখানে লিঙ্কটি দেওয়া হয়েছে:

https://docs.python.org/2/references/datamodel.html#with-statement-context-managers
https://docs.python.org/3/references/datamodel.html#with-statement-context-managers
(বিবরণ উভয় সংস্করণের জন্য একই)

object.__enter__(self)
এই অবজেক্ট সম্পর্কিত রানটাইম প্রসঙ্গ লিখুন। withবিবৃতি লক্ষ্য (গুলি) এই পদ্ধতি ফিরে মান বিবৃতির যেমন দফা উল্লেখিত, যদি থাকে বাঁধে হবে।

object.__exit__(self, exc_type, exc_value, traceback)
এই বস্তুর সাথে সম্পর্কিত রানটাইম প্রসঙ্গে প্রস্থান করুন। প্যারামিটারগুলি ব্যতিক্রমটিকে বর্ণনা করে যা প্রসঙ্গে প্রস্থানিত হতে পারে। যদি ব্যতিক্রম ব্যতীত প্রসঙ্গটি বের করা হয়, তবে তিনটি যুক্তিই হবে None

যদি কোনও ব্যতিক্রম সরবরাহ করা হয়, এবং পদ্ধতিটি ব্যতিক্রমটিকে দমন করতে চায় (যেমন, এটি প্রচার হতে বাধা দেয়), এটি একটি সত্য মানের প্রত্যাবর্তন করবে। অন্যথায়, ব্যতিক্রমটি এই পদ্ধতি থেকে প্রস্থান করার পরে সাধারণত প্রক্রিয়া করা হবে।

নোট করুন যে __exit__()পদ্ধতিগুলি পাস-ইন ব্যতিক্রমকে পুনরায় সাজানো উচিত নয়; এটি কলারের দায়িত্ব।

আমি __exit__পদ্ধতি আর্গুমেন্টের একটি পরিষ্কার বিবরণ আশা করছি । এটির অভাব রয়েছে তবে আমরা সেগুলি হ্রাস করতে পারি ...

সম্ভবত exc_typeব্যতিক্রম শ্রেণি।

এটি বলেছে যে আপনাকে পাস-ইন ব্যতিক্রম পুনরায় বাড়াতে হবে না। এটি আমাদের কাছে পরামর্শ দেয় যে আর্গুমেন্টগুলির মধ্যে একটি সত্যিকারের ব্যতিক্রম উদাহরণ হতে পারে ... বা সম্ভবত আপনি এটি নিজেকে টাইপ এবং মান থেকে ইনস্ট্যান্ট করার কথা?

আমরা এই নিবন্ধটি দেখে উত্তর দিতে পারি:
http://effbot.org/zone/python-with-statement.htm

উদাহরণস্বরূপ, নিম্নলিখিত __exit__পদ্ধতিটি যে কোনও টাইপ-এরর গ্রাস করে, তবে এর মাধ্যমে অন্যান্য সমস্ত ব্যতিক্রম ঘটায়:

def __exit__(self, type, value, traceback):
    return isinstance(value, TypeError)

... তাই স্পষ্টভাবে valueএকটি ব্যতিক্রম উদাহরণ।

এবং সম্ভবত tracebackএকটি পাইথন ট্রেসব্যাক অবজেক্ট।


2
একমত। এই ইউআরএলটি খুঁজে পাওয়া এত কঠিন।
শিহাও জু


43

অনুরোধ আদেশটি উদাহরণের জন্য উপরের উত্তরগুলি ছাড়াও, একটি সরল রানের উদাহরণ

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, ভেরিয়েবল এমসি __enter__()উপরের ক্ষেত্রে, মানটি ফেরত দেয় None! এই ধরনের ব্যবহারের জন্য, রিটার্ন মান নির্ধারণ করা দরকার যেমন:

def __enter__(self): 
    print('__enter__')
    return self

3
এমনকি সংজ্ঞাগুলির ক্রমটি যদি স্যুইচ করা হয় তবে এক্সিকিউটিভ অর্ডারটি একই থাকে!
শান

1
এটি খুব সহায়ক ছিল। ধন্যবাদ.
রিজ0

5

আমার উত্তরগুলি যুক্ত করার চেষ্টা করুন (আমার শেখার চিন্তাভাবনা):

__enter__এবং [__exit__]উভয়ই এমন পদ্ধতি যা " দ্য উইথ স্টেটমেন্ট " ( পিইপি 343 ) এর বডি থেকে প্রবেশ এবং প্রস্থানের জন্য অনুরোধ করা হয় এবং উভয়ের প্রয়োগকে কনটেক্সট ম্যানেজার বলা হয়।

বিবৃতি সহ অবশেষে ধারাটির প্রবাহ নিয়ন্ত্রণ লুকিয়ে রাখার এবং কোডটি অনির্বচনীয় করার উদ্দেশ্যে।

বিবৃতি সহ বাক্যটির বাক্য গঠনটি হ'ল:

with EXPR as VAR:
    BLOCK

যা অনুবাদ করে (পিইপি 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

সার্ভারের ফলাফলটি আগের মতোই রয়েছে

আমার খারাপ ইংরেজি এবং আমার অস্পষ্ট ব্যাখ্যার জন্য দুঃখিত, ধন্যবাদ ....


1

একে কনটেক্সট ম্যানেজার বলা হয় এবং আমি কেবল যুক্ত করতে চাই যে অন্যান্য প্রোগ্রামিং ভাষার জন্যও একই ধরণের পন্থা বিদ্যমান। তাদের তুলনা করা পাইথনের প্রসঙ্গ পরিচালককে বুঝতে সহায়তা করতে পারে understanding মূলত, যখন আমরা কিছু সংস্থান (ফাইল, নেটওয়ার্ক, ডাটাবেস) ব্যবহার করি যা প্রারম্ভিক হওয়া দরকার এবং কোনও সময়ে টিয়ার ডাউন (নিষ্পত্তি) করা হয় তখন একটি প্রসঙ্গ পরিচালক ব্যবহার করা হয়। ইন জাভা 7 এবং উপরোক্ত আমরা স্বয়ংক্রিয় সম্পদ ব্যবস্থাপনা যে এর আকারে আছে:

//Java code
try (Session session = new Session())
{
  // do stuff
}

নোট করুন যে সেশনটির প্রয়োগ করতে হবে AutoClosableবা এর (বহু) উপ-ইন্টারফেসগুলির একটি।

ইন সি # , আমরা সেই সমস্ত সম্পদের এর আকারে পরিচালনার জন্য বিবৃতি ব্যবহার করেছেন:

//C# code
using(Session session = new Session())
{
  ... do stuff.
}

যা Sessionবাস্তবায়ন করা উচিত IDisposable

ইন পাইথন , বর্গ যে আমরা ব্যবহার বাস্তবায়ন করা উচিত __enter__এবং __exit__। সুতরাং এটি রূপ নেয়:

#Python code
with Session() as session:
    #do stuff

এবং অন্যরা যেমন নির্দেশ করেছে, আপনি সর্বদা একই ভাষা প্রয়োগের জন্য সমস্ত ভাষায় চেষ্টা / অবশেষে বিবৃতি ব্যবহার করতে পারেন। এটি কেবল সিনট্যাকটিক চিনি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.