__enter__ 方法从不提供任何参数,因此在 self 之外,您的签名不应该有任何其他参数。
您应该将这些参数移至 __init__ 方法:
class FooBar(object):
def __init__(self, param1, param2):
# do something here ...
def __enter__(self):
# something else, perhaps return self
创建FooBar() 的实例是一个单独的步骤。 with 在mymod.FooBar("hello", 123) 表达式的结果上调用__enter__,表达式本身不会转换为__enter__ 调用。
如果是这样,你也不能这样使用它,但你可以:
cm = mymod.FooBar("hello", 123)
with cm as x:
# do something here with x, which is the return value of cm.__enter__()
请注意,x 被分配了任何 cm.__enter__() 返回的值;你可以从__enter__返回self,或者你可以返回完全不同的东西。
预期的方法 __enter__ 和 __exit__ 记录在 Python 数据模型文档的 With Statement Context Managers section 中:
object.__enter__(self)
输入与该对象相关的运行时上下文。 with 语句会将此方法的返回值绑定到该语句的 as 子句中指定的目标(如果有)。
以及内置类型文档的Content Manager Types section:
contextmanager.__enter__()
进入运行时上下文并返回此对象或与运行时上下文相关的另一个对象。此方法返回的值绑定到使用此上下文管理器的with 语句的as 子句中的标识符。
返回自身的上下文管理器的一个示例是文件对象。文件对象从__enter__() 返回自身,以允许open() 用作with 语句中的上下文表达式。
如果您对确切的交互感兴趣,请参阅原始提案:PEP 343 -- The "with" Statement;从规范部分你可以看到 with EXPR as VAR: BLOCK 语句在幕后做了什么:
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)
注意mgr = (EXPR) 部分;在你的情况下,mymod.FooBar("hello", 123) 就是那个部分。另请注意,(EXPR)、__enter__ 和 __exit__ 在此处不受 try..except 的“保护”,表达式中或进入或退出时引发的异常不由上下文管理器处理!