tl; dr使用上下文管理器。請參閱此答案的底部以瞭解關於它們的重要注意事項。
雖然有可能在普通用戶類使用一些方法,這些方法不會隨內置類的工作文件已經在Python 3更復雜。一種方法是instanciating之前混合,在所需的類,但這需要知道什麼是混合類應該是第一:
class MyFileType(???):
def __init__(...)
# stuff here
def close(self):
# more stuff here
因爲有這麼多種類,多的可能可能在被加入未來(不太可能,但可能),並且我們不確定哪些將被退回到之後呼叫open
,此方法不起作用。
另一種方法是改變了我們的自定義類型有返回的文件的___bases__
和修改返回實例的__class__
屬性爲我們自定義類型:
class MyFileType:
def close(self):
# stuff here
some_file = open(path_to_file, '...') # ... = desired options
MyFileType.__bases__ = (some_file.__class__,) + MyFile.__bases__
,但是這會產生
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __bases__ assignment: '_io.TextIOWrapper' deallocator differs from 'object'
然而,另一種可以使用純用戶類的方法是直接從返回的實例類中創建自定義文件類型,然後更新返回的實例類:
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
卻又:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __class__ assignment: only for heap types
因此,它看起來好像是會在所有的工作在Python 3,幸運的是也將在Python 2工作的最佳方法(有用的,如果你想在同一代碼基地上兩個版本的工作)是有一個自定義的上下文管理器:
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
,並使用它:
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
重要的一點要記住:在__init__
或__enter__
任何未處理的異常將防止__exit__
運行,所以在這兩個位置,你仍然需要使用try
/except
和/或try
/finally
成語,以確保你不不會泄漏資源。
也許不是擴展文件對象,而是使用'with'語句來使用自定義對象? –
爲什麼封裝'open'返回值的類太糟糕了?您可以重寫'__getattr__'來批量轉發方法。 –
@BenjaminHodgson它已經足夠長,我不記得我到底在想什麼,但它可能是沿着這樣的路線:「做90%的工作很容易,而且每個角落案例都很痛苦明確了。」我沒有在Python中使用對象自省做過很多事情,當我嘗試過時,它會以令人困惑的方式絆倒我。 – zwol