Ram*_*amy 37 python with-statement
只需从本文中了解语句即可
问题是,我可以通过论证__enter__吗?
我有这样的代码:
class clippy_runner:
def __enter__(self):
self.engine = ExcelConnection(filename = "clippytest\Test.xlsx")
self.db = SQLConnection(param_dict = DATASOURCES[STAGE_RELATIONAL])
self.engine.connect()
self.db.connect()
return self
Run Code Online (Sandbox Code Playgroud)
我想将filename和param_dict作为参数传递给__enter__.那可能吗?
S.L*_*ott 44
不,你不能.你传递参数__init__().
class ClippyRunner:
def __init__(self, *args):
self._args = args
def __enter__(self):
# Do something with args
print(self._args)
with ClippyRunner(args) as something:
# work with "something"
pass
Run Code Online (Sandbox Code Playgroud)
小智 25
是的,您可以通过添加更多代码来获得效果.
#!/usr/bin/env python
class Clippy_Runner( dict ):
def __init__( self ):
pass
def __call__( self, **kwargs ):
self.update( kwargs )
return self
def __enter__( self ):
return self
def __exit__( self, exc_type, exc_val, exc_tb ):
self.clear()
clippy_runner = Clippy_Runner()
print clippy_runner.get('verbose') # Outputs None
with clippy_runner(verbose=True):
print clippy_runner.get('verbose') # Outputs True
print clippy_runner.get('verbose') # Outputs None
Run Code Online (Sandbox Code Playgroud)
Vin*_*ent 11
接受的答案(我认为这是不正确的)指出您不能,而应该这样做;
class Comedian:
def __init__(self, *jokes):
self.jokes = jokes
def __enter__(self):
jokes = self.jokes
#say some funny jokes
return self
Run Code Online (Sandbox Code Playgroud)
..虽然这通常是您会做的事情,但它并不总是最好的解决方案,甚至不是解决方案,而且绝对不是唯一的解决方案!..
我假设你想要的是能够做类似的事情;
funny_object = Comedian()
with funny_object('this is a joke') as humor:
humor.say_something_funny()
Run Code Online (Sandbox Code Playgroud)
如果是这种情况,并且没有比这更复杂的情况,那么您可以这样做;
class Comedian:
def __enter__(self):
jokes = self.jokes
#say some funny jokes
return self
def __call__(self, *jokes):
self.jokes = jokes
Run Code Online (Sandbox Code Playgroud)
..那样你仍然可以用你想要的任何参数初始化对象,并像往常一样对对象做任何其他的事情,但是当你去使用对象作为上下文管理器时,你首先调用它的调用函数并设置为上下文管理器提供一些参数。
这里重要的是准确理解上下文管理器在 Python 中的工作方式。
在 Python 中,上下文管理器是定义enter方法的任何对象。执行此操作时会自动调用此方法;
with object as alias:
alias.do_stuff()
..
Run Code Online (Sandbox Code Playgroud)
..注意 object 后面没有几个“()”,它是一个隐式函数调用,它不带任何参数。
你可能已经得到了传递参数给的念头进入的;
with open(filename) as file:
"do stuff with file..
Run Code Online (Sandbox Code Playgroud)
但这与覆盖enter不同,因为“open”不是一个对象,而是一个函数。
一个很好的练习是打开一个交互式 python 控制台并输入“open”+[ENTER]
>>> open
<built-in function open>
Run Code Online (Sandbox Code Playgroud)
“open”不是上下文管理器对象,而是函数。它根本没有enter方法,而是通过以下方式定义;
@contextmanager
def open(..):
...
Run Code Online (Sandbox Code Playgroud)
..你可以用同样的方式定义你自己的上下文管理器函数,你甚至可以覆盖“open”的定义。
不过,IMO,如果您需要创建一个对象,然后将其用作带参数的上下文管理器(我所做的),最好的办法是为该对象提供一个方法,该方法返回一个定义了enter方法的临时对象,像这样;
class Comedian:
def context(audience):
class Roaster:
context = audience
def __enter__(self):
audience = self.__class__.context
# a comedian needs to know his/her audience.
return Roaster(audience)
funny_thing = Comedian()
with funny_thing.context('young people') as roaster:
roaster.roast('old people')
Run Code Online (Sandbox Code Playgroud)
本例中调用链的顺序是;喜剧演员。init () -> Comedian.context(args) -> Roaster。进入()
我觉得很多人都缺少这个答案,所以我添加了它。
您可以使用 contextmanager 装饰器来传递参数:
https://docs.python.org/3/library/contextlib.html#contextlib.contextmanager
from contextlib import contextmanager
@contextmanager
def clippy_runner(*args):
yield
Run Code Online (Sandbox Code Playgroud)
恕我直言,我发现使用contextmanager你可以提供参数,但你不能将它们提供给__enter__