Импровизация общедоступной замены для “с” оператором для Python 2.4

Небольшие приложения, которые не имеют UI, особенно когда Вы пытаетесь учиться.

Редактирование: После размышления немного больше на этом, я добавил бы следующее: если Вы уже знаете высокоуровневый язык, и Вы пытаетесь узнать больше о C, хороший маршрут может быть, чтобы не создать совершенно новое приложение C, но вместо этого создать DLL C и добавить функции к нему, что можно звонить с более высокого языка. Таким образом можно заменить простые функции, что высокий язык уже должен гарантировать, что Вы, функция C делает то, что это должно (дает Вам предварительно созданное тестирование), позволяете Вам кодировать главным образом, в каком Вы знакомы с, использует язык в проблеме, с которой Вы уже знакомы, и учит Вас interop.

6
задан Ram Rachum 10 September 2013 в 20:02
поделиться

5 ответов

Просто используйте try-finally.

На самом деле, это может быть приятным умственным упражнением, но если вы на самом деле сделаете это в коде, который вам небезразличен, вы получите уродливый, сложный в поддержке код .

6
ответ дан 8 December 2019 в 18:38
поделиться

Как насчет этого?

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)

Что соответствует ключевому слову с с как .

1
ответ дан 8 December 2019 в 18:38
поделиться

Я думаю, вы могли бы (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 _...). Обратите внимание, что декоратор изменяет объявление функции на немедленный вызов , что является большим злом.

4
ответ дан 8 December 2019 в 18:38
поделиться

Поскольку вам нужно выходить из диспетчера контекста как во время ошибок, так и во время ошибок, я не думаю, что можно использовать общий вариант использования с метаклассами, или вообще. Для этого вам понадобятся блоки 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)
1
ответ дан 8 December 2019 в 18:38
поделиться

Если вы не против использования 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

1
ответ дан 8 December 2019 в 18:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: