tl; drUżyj menedżera kontekstu. Zobacz na dole tej odpowiedzi ważne uwagi na ich temat.
Pliki dostał bardziej skomplikowana w Pythonie 3. Chociaż istnieje kilka metod, które mogą być stosowane w normalnych klasach użytkownika, te metody nie działają z wbudowanych klas. Jednym ze sposobów jest mieszanie w żądanej klasie przed instanciating, ale to wymaga wiedząc, co powinno być najpierw wymieszać w klasie:
class MyFileType(???):
def __init__(...)
# stuff here
def close(self):
# more stuff here
Ponieważ istnieje tak wiele rodzajów, a mógłby być dodany w przyszłości (mało prawdopodobne, ale możliwe), i nie wiemy na pewno, która zostanie zwrócona do po połączenie z open
, ta metoda nie działa.
Inną metodą jest zmiana zarówno nasz typ niestandardowy mieć zwrócony File ___bases__
i modyfikując atrybut Zwracany instancji __class__
do naszego typu niestandardowe:
class MyFileType:
def close(self):
# stuff here
some_file = open(path_to_file, '...') # ... = desired options
MyFileType.__bases__ = (some_file.__class__,) + MyFile.__bases__
ale to daje
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __bases__ assignment: '_io.TextIOWrapper' deallocator differs from 'object'
Jeszcze inną metodą, która może działać z czystymi klasami użytkowników, jest tworzenie niestandardowego typu pliku w locie, bezpośrednio z klasy zwróconej instancji, a następnie aktualizacja klasy zwróconego egzemplarza:
some_file = open(path_to_file, '...') # ... = desired options
class MyFile(some_file.__class__):
def close(self):
super().close()
print("that's all, folks!")
some_file.__class__ = MyFile
ale znowu:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
Tak, wygląda na to najlepszym sposobem, który będzie działał w ogóle w Pythonie 3, a szczęście będzie również pracować w Pythonie 2 (przydatne, jeśli chcesz tego samego kodu baza do pracy w obu wersjach) ma mieć menedżera kontekstowe niestandardowe:
class Open(object):
def __init__(self, *args, **kwds):
# do custom stuff here
self.args = args
self.kwds = kwds
def __enter__(self):
# or do custom stuff here :)
self.file_obj = open(*self.args, **self.kwds)
# return actual file object so we don't have to worry
# about proxying
return self.file_obj
def __exit__(self, *args):
# and still more custom stuff here
self.file_obj.close()
# or here
i go używać:
with Open('some_file') as data:
# custom stuff just happened
for line in data:
print(line)
# data is now closed, and more custom stuff
# just happened
Ważnym punktem, aby pamiętać: każdy nieobsługiwany wyjątek w __init__
lub __enter__
uniemożliwi __exit__
z systemem, więc w tych dwóch miejscach nadal trzeba używać try
/except
i/lub try
/finally
idiomów, aby upewnić się, że don Przeciek zasobów.
Być może zamiast rozszerzania obiektu pliku można utworzyć niestandardowy obiekt do użycia z instrukcją 'with'? –
Dlaczego klasa, która zawija wartość zwracaną 'otwartego', jest tak zła? Możesz przesłonić '__getattr__', aby przekazywać metody hurtowo. –
@BenjaminHodgson To było wystarczająco długie, że nie pamiętam dokładnie, co myślałem, ale prawdopodobnie było to zgodne z następującymi argumentami: "łatwo byłoby wykonać 90% pracy i ogromny ból, aby zdobyć każdą ostatnią narożną skrzynkę przybity. " Nie zrobiłem zbyt wiele z introspekcji obiektów w Pythonie, a kiedy spróbowałem, potknęło mnie to w mylący sposób. – zwol