Небольшие приложения, которые не имеют UI, особенно когда Вы пытаетесь учиться.
Редактирование: После размышления немного больше на этом, я добавил бы следующее: если Вы уже знаете высокоуровневый язык, и Вы пытаетесь узнать больше о C, хороший маршрут может быть, чтобы не создать совершенно новое приложение C, но вместо этого создать DLL C и добавить функции к нему, что можно звонить с более высокого языка. Таким образом можно заменить простые функции, что высокий язык уже должен гарантировать, что Вы, функция C делает то, что это должно (дает Вам предварительно созданное тестирование), позволяете Вам кодировать главным образом, в каком Вы знакомы с, использует язык в проблеме, с которой Вы уже знакомы, и учит Вас interop.
Просто используйте try-finally.
На самом деле, это может быть приятным умственным упражнением, но если вы на самом деле сделаете это в коде, который вам небезразличен, вы получите уродливый, сложный в поддержке код .
Как насчет этого?
def improvize_context_manager(*args, **kwargs):
assert (len(args) + len(kwargs)) == 1
if args:
context_manager = args[0]
as_ = None
else: # It's in kwargs
(as_, context_manager) = kwargs.items()[0]
def decorator(f):
exit_ = context_manager.__exit__ # Not calling it yet
enter_ = context_manager.__enter__()
exc = True
try:
try:
if as_:
f(*{as_: enter_})
else:
f()
except:
exc = False
if not exit_(*sys.exc_info()):
raise
finally:
if exc:
exit_(None, None, None)
return None
return decorator
Использование:
@improvize_context_manager(lock)
def null():
do(stuff)
Что соответствует ключевому слову с ключевым словом
без как
.
Или:
@improvize_context_manager(my_lock=lock)
def null(my_lock):
do(stuff_with, my_lock)
Что соответствует ключевому слову с
с как
.
Я думаю, вы могли бы (ab) использовать для этого декораторы. Следующие работы, например:
def execute_with_context_manager(man):
def decorator(f):
target = man.__enter__()
exc = True
try:
try:
f(target)
except:
exc = False
if not man.__exit__(*sys.exc_info()):
raise
finally:
if exc:
man.__exit__(None, None, None)
return None
return decorator
@execute_with_context_manager(open("/etc/motd"))
def inside(motd_file):
for line in motd_file:
print line,
(Ну, в Python 2.4 файловые объекты не имеют методов __enter__ и __exit__, но в остальном это работает)
Идея состоит в том, что вы заменяете строку with в:
with bar() as foo:
do_something_with(foo)
do_something_else_with(foo)
# etc...
на декорированное «объявление» функции в:
@execute_with_context_manager( bar() )
def dummyname( foo ):
do_something_with(foo)
do_something_else_with(foo)
# etc...
, но с таким же поведением (выполняется код do_something _...). Обратите внимание, что декоратор изменяет объявление функции на немедленный вызов , что является большим злом.
Поскольку вам нужно выходить из диспетчера контекста как во время ошибок, так и во время ошибок, я не думаю, что можно использовать общий вариант использования с метаклассами, или вообще. Для этого вам понадобятся блоки try / finally.
Но, возможно, в вашем случае можно сделать что-нибудь еще. Это зависит от того, для чего вы используете диспетчер контекста.
Использование __ del __
может помочь в некоторых случаях, например, при освобождении ресурса, но поскольку вы не можете быть уверены, что он будет вызван, его можно использовать только в том случае, если вам нужно освободить ресурсы, которые будут освобождены, когда программа выходит. Это также не сработает, если вы обрабатываете исключения в методе __ exit __
.
Думаю, самый чистый метод - обернуть все управление контекстом в своего рода вызов управления контекстом и извлечь блок кода в метод. Примерно так (непроверенный код, но в основном украденный из PEP 343):
def call_as_context_manager(mgr, function):
exit = mgr.__exit__
value = mgr.__enter__()
exc = True
try:
try:
function(value)
except:
exc = False
if not exit(*sys.exc_info()):
raise
finally:
if exc:
exit(None, None, None)
Если вы не против использования def только для получения блока, и декораторов, которые немедленно выполняются, вы можете использовать сигнатуру функции, чтобы получить что-то более естественное для именованного случая.
import sys def with(func): def decorated(body = func): contexts = body.func_defaults try: exc = None, None, None try: for context in contexts: context.__enter__() body() except: exc = sys.exc_info() raise finally: for context in reversed(contexts): context.__exit__(*exc) decorated() class Context(object): def __enter__(self): print "Enter %s" % self def __exit__(self, *args): print "Exit %s(%s)" % (self, args) x = Context() @with def _(it = x): print "Body %s" % it @with def _(it = x): print "Body before %s" % it raise "Nothing" print "Body after %s" % it