Implementazione di utilizzo di 'con l'oggetto () come f' in classe personalizzata in Python
-
04-10-2019 - |
Domanda
Devo aprire un file-come oggetto in python (si tratta di una connessione seriale tramite / dev /) e quindi chiuderlo. Questo viene fatto più volte in diversi metodi di mia classe. Come stavo facendo stava aprendo il file nel costruttore, e chiudendo nel distruttore. Ricevo strani errori e anche se penso che abbia a che fare con il garbage collector e tale, sto ancora non abituato a non sapere esattamente quando i miei oggetti vengono eliminati = \
La ragione per cui stavo facendo questo è perché devo usare tcsetattr
con un gruppo di parametri ogni volta che l'apro e diventa fastidioso fare tutto ciò che tutto il luogo. Quindi voglio implementare una classe interna per gestire tutto ciò che così posso usarlo facendo
with Meter('/dev/ttyS2') as m:
che cercavo in linea e non sono riuscito a trovare una buona risposta su come è implementata la sintassi with
. Ho visto che utilizza i metodi __enter__(self)
e __exit(self)__
. Ma è tutto quello che hanno a che fare applicare tali metodi e posso utilizzare la sintassi? O c'è di più ad esso?
C'è sia un esempio di come fare questo o qualche documentazione su come viene implementato su file di oggetti già che posso guardare?
Soluzione
Tali metodi sono praticamente tutto il necessario per rendere il lavoro oggetto con dichiarazione with
.
In __enter__
si deve restituire l'oggetto del file dopo l'apertura e la sua creazione.
In __exit__
si deve chiudere l'oggetto file. Il codice per la scrittura sarà nel corpo dichiarazione with
.
class Meter():
def __init__(self, dev):
self.dev = dev
def __enter__(self):
#ttysetattr etc goes here before opening and returning the file object
self.fd = open(self.dev, MODE)
return self.fd
def __exit__(self, type, value, traceback):
#Exception handling here
close(self.fd)
meter = Meter('dev/tty0')
with meter as m:
#here you work with the file object.
m.read()
Altri suggerimenti
più semplice potrebbe essere quella di utilizzare libreria standard di Python modulo contextlib :
import contextlib
@contextlib.contextmanager
def themeter(name):
theobj = Meter(name)
yield theobj
theobj.close() # or whatever you need to do at exit
Questo non fa Meter
per sé un gestore di contesto (e quindi non è invasivo per quella classe), ma piuttosto "decora" esso (non nel senso di "sintassi decoratore" di Python, ma quasi, ma non del tutto , nel senso del design pattern decorator ;-) con una funzione di fabbrica themeter
che è un gestore di contesto (che il decoratore contextlib.contextmanager
costruisce dalla funzione generatore di "single-yield
" si scrive) - questo rende così molto più facile da separare l'ingresso e la condizione di uscire, evita nidificazione, ecc.
Il primo Google ha colpito (per me) spiega abbastanza semplicemente:
http://effbot.org/zone/python-with-statement.htm
e il PEP lo spiega più precisamente (ma anche più verboso):