将参数传递给去上下文装饰器 [英] Passing arguments to decontext decorator

查看:73
本文介绍了将参数传递给去上下文装饰器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个帮助器类 Decontext ,该类用于将上下文管理器转换为装饰器(pyton 2.6)。

I have a helper class Decontext that I am using to turn a context manager into a decorator (pyton 2.6).

class Decontext(object):
    """
    makes a context manager also act as decorator
    """

    def __init__(self, context_manager):
        self._cm = context_manager

    def __enter__(self):
        return self._cm.__enter__()

    def __exit__(self, *args, **kwds):
        return self._cm.__exit__(*args, **kwds)

    def __call__(self, func):
        def wrapper(*args, **kwds):
            with self:
                return func(*args, **kwds)

        return wrapper

我的 contextmanager 接受一个参数,而我正在尝试弄清楚使用此装饰器时如何传递该参数?

My contextmanager takes an argument and I am trying to figure out how to pass that argument when using this decorator ?

@contextmanager
def sample_t(arg1):
print "<%s>" % arg1
        yield

这是我使用失败的方式:

This is how I am using it which fails:

my_deco =  Decontext(sample_t)

@my_deco(arg1='example')
def some_func()
     print 'works'

编辑:

我希望 Decontext 类在<$ c时传递context_manager中的所有 * args $ c> __ call __ 函数执行。

I would like the Decontext class to pass all *args in the context_manager when the __call__ function executes.

示例:

decorator_example = Decontext(sample_t) // I don't want to pass in the argument here but when the decorator is created. How can I modify my class to make this enhancement

编辑2:

我期望的例子

my_deco =  Decontext(sample_t)

@my_deco(arg1='example')
def some_func()
     print 'works'

预期的输出:

'example' // running and passing argument to context_manager
'works' // after yield executing some_func 

后,

推荐答案

您遇到的问题是您在 __ init __ 方法中设置的 _cm 属性实际上并未存储上下文管理器实例,而是上下文管理器的类型(或者可能是产生上下文管理器实例的工厂函数)。您需要稍后调用类型或工厂来获取实例。

The issue you're having is that the _cm attribute you're setting up in your __init__ method isn't actually storing a context manager instance, but rather the the type of the context manager (or possibly a factory function that produces context manager instances). You need to call the type or factory later, to get an instance.

尝试一下,这对两个上下文管理器实例都适用(假定它们也不可调用)和需要参数的上下文管理器类型:

Try this, which should work for both context manager instances (assuming they're not also callable) and context manager types that require arguments:

class Decontext(object):
    """
    makes a context manager also act as decorator
    """

    def __init__(self, context_manager):
        self._cm = context_manager   # this may be a cm factory or type, but that's OK

    def __enter__(self):
        return self._cm.__enter__()

    def __exit__(self, *args, **kwds):
        return self._cm.__exit__(*args, **kwds)

    def __call__(self, *cm_args, **cm_kwargs):
        try:
            self._cm = self._cm(*cm_args, **cm_kwargs) # try calling the cm like a type
        except TypeError:
            pass
        def decorator(func):
            def wrapper(*args, **kwds):
                with self:
                    return func(*args, **kwds)

            return wrapper
        return decorator

那里有一个相当愚蠢的嵌套层次,但这正是您想要调用该事物的方式所需要的。这是一个运行中的示例:

There's a fairly silly level of nesting going on in there, but it's what you need given the way you want to call the thing. Here's an example with it in action:

from contextlib import contextmanager

@contextmanager
def foo(arg):
    print("entered foo({!r})".format(arg))
    yield
    print("exited foo({!r})".format(arg))

foo_deco_factory = Decontext(foo)

@foo_deco_factory("bar")
def baz(arg):
    print("called baz({!r})".format(arg))

baz("quux")

它将输出:

entered foo("bar")
called baz("quux")
exited foo("bar")

请注意, foo_deco_factory 作为上下文管理器将不起作用(类似于将与foo 一起使用将不起作用)。在 Decontext 实例上使用上下文管理器协议只有在使用上下文管理器实例(而不是类型或工厂)初始化或已经被调用时才有效。一个带有适当参数的装饰器。

Note that trying to use foo_deco_factory as a context manager will not work (similarly to how using with foo won't work). Using the context manager protocol on a Decontext instance will work only if it was initialized with a context manager instance (rather than a type or factory) or if it has been called already as a decorator with appropriate arguments.

如果您不需要装饰器本身就可以充当上下文管理器,则可以很容易地将整个类变成一个函数( __ call __ 成为一个额外的关闭级别,而不是一个方法):

If you didn't need the decorator to be able to act as a context manager itself, you could pretty easily turn the whole class into a function (with __call__ becoming an extra level of closure, rather than a method):

def decontext(cm_factory):
    def factory(*cm_args, **cm_kwargs):
        cm = cm_factory(*cm_args, **cm_kwargs)
        def decorator(func):
            def wrapper(*args, **kwargs):
                with cm:
                    return func(*args, **kwargs)
            return wrapper
        return decorator
    return factory

在这种情况下,为了简化代码,我总是假设您要传入一个上下文管理器工厂,而不是一个上下文管理器实例。

To simplify the code in this case, I always assume you're passing in a context manager factory, rather than a context manager instance.

这篇关于将参数传递给去上下文装饰器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆