这里的初学者Python编码器来自Java背景。我仍然对此感到困惑:
with open(...) as f:
do_something(f)甚至在谷歌和阅读了这里的一些答案之后(我只是无法理解这些答案)。
我的理解是,有一个叫做上下文管理器的东西,它是某种包装器,包含对创建的文件的引用。关于
as f:上面的“as”就像下面的“as”
import numpy as np只是个化名。'f‘不是指文件,而是指上下文管理器。上下文管理器使用修饰器模式实现所打开的文件所执行的所有方法,这样我就可以把它当作文件对象来对待(并通过调用适当的方法来获取文件对象,这些方法将在上下文管理器中的文件中调用)。当然,当块完成时,文件将被关闭(这是整个过程的要点)。
这就引出了一个问题: open()通常是返回文件(或对文件的引用)还是上下文管理器?它一般会返回上下文管理器吗?这就是我们一直在不知道的情况下使用的内容吗?或者它是否返回文件类型,除非在此特殊上下文中返回与上下文管理器不同的内容。
这附近有吗?有人想澄清吗?
发布于 2016-08-15 16:41:47
文件对象本身就是上下文管理器,因为它们有__enter__和__exit__方法。当输入和退出上下文时,with会通知file对象(分别调用__enter__和__exit__ ),这就是文件对象“知道”关闭文件的方式。这里不涉及包装对象;文件对象提供了这两种方法(用Java术语来说,您可以说文件对象实现了上下文管理器接口)。
注意,as不是像import module as altname那样的别名;相反,contextmanager.__enter__()的返回值是分配给目标的。fileobject.__enter__()方法返回self (因此文件对象本身),以便更容易地使用语法:
with open(...) as fileobj:如果fileobject.__enter__()没有这样做,但返回了None或其他对象,则无法内联open()调用;要保持对返回的文件对象的引用,必须先将open()的结果赋值给变量,然后再将其用作上下文管理器:
fileobj = open(...)
with fileobj as something_enter_returned:
fileobj.write()或
fileobj = open(...)
with fileobj: # no as, ignore whatever fileobj.__enter__() produced
fileobj.write()请注意,没有什么可以阻止您在自己的代码中使用后一种模式;如果您已经有了对文件对象的另一个引用,或者根本不需要进一步访问该文件对象,您就不必在这里使用as target部件。
但是,其他上下文管理器可能返回一些不同的内容。一些数据库连接器返回数据库游标:
conn = database.connect(....)
with conn as cursor:
cursor.execute(...)退出上下文会导致事务被提交或回滚(取决于是否存在异常)。
发布于 2016-08-15 17:04:59
这是您可以创建的最基本的上下文管理器:
class UselessContextManager(object):
def __enter__(self):
pass
def __exit__(self, type, value, traceback):
pass
with UselessContextManager() as nothing:
print(nothing is None)如果您想要对实际流程流程的外观有一点了解,请尝试以下一个:
class PrintingContextManager(object):
def __init__(self, *args, **kwargs):
print('Initializing with args: {} and kwargs: {}'.format(args, kwargs))
def __enter__(self):
print('I am entering the context')
print('I am returning 42')
return 42
def __exit__(self, type, value, traceback):
print('And now I am exiting')
print('Creating manager')
manager = PrintingContextManager()
print('Entering with block')
with manager as fnord:
print('Fnord is {}'.format(fnord))
print('End of context')
print('Out of context') 输出:
Creating manager
Initializing with args: () and kwargs: {}
Entering with block
I am entering the context
I am returning 42
Fnord is 42
End of context
And now I am exiting
Out of context您应该尝试修改代码以打印出type, value, traceback,然后在with块中引发异常。
如您所见,with语法几乎只是以下的缩写:
thing = ContextManager()
try:
stuff = thing.__enter__()
except Exception as e:
stuff.__exit__(type(e), e.args[0], e.__traceback__)可以看到,文件始终是上下文管理器:
>>> f = open('/tmp/spanish_inquisition.txt', 'w')
>>> f.__enter__
<function TextIOWrapper.__enter__>
>>> f.__exit__
<function TextIOWrapper.__exit__>我不知道一个文件可以是一个ContextManager,只需实现两个方法,而不继承超类或显式实现接口。再说一次,我对这门语言很陌生。
在Python中,它显式地实现了接口。在Java中,您必须指定要遵守的接口。在Python中,你只需这样做。需要一个类似文件的对象?添加一个.read()方法。可能是.seek()、.open()和.close(),这取决于他们的期望。但在Python里..。
it = DecoyDuck()
if it.walks_like_a_duck() and it.talks_like_a_duck() and it.quacks_like_a_duck():
print('It must be a duck')https://stackoverflow.com/questions/38959182
复制相似问题