Python装饰器访问范围变量

时间:2017-05-11 07:23:04

标签: python scope decorator

Python装饰器可以访问装饰函数范围内的所有变量吗? e.g。

@decme
def call_me():
    ...

def caller_function():
    context = context_creator()
    call_me()

在这种情况下,decme装饰者可以访问context变量吗?

我们知道如果我们将call_me作为参数传递,context将能够访问context,是否有办法将decme传递给@decme(context)函数?< / p>

请注意,call_me函数可以在单独的模块中定义,这意味着在我们调用call_me函数时public class Second extends Activity{ TextView txtsrno,txtflower,txtstatus,txttimeleft; ListView listView; ArrayList<Model> flowerlist; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); txtsrno = (TextView) findViewById(R.id.srno); txtflower = (TextView) findViewById(R.id.name); txtstatus = (TextView) findViewById(R.id.buy); txttimeleft=(TextView)findViewById(R.id.remtime); listView = (ListView) findViewById(R.id.list); flowerlist = new ArrayList<>(); flowerlist.add(new Model(1, "Rose",System.currentTimeMillis() + 1800000)); flowerlist.add(new Model(2, "Sunflower",System.currentTimeMillis() + 10000)); flowerlist.add(new Model(3, "Lotus",System.currentTimeMillis() + 30000)); flowerlist.add(new Model(4, "Jasmine",System.currentTimeMillis() + 600000)); SecondCustom sc = new SecondCustom(this, flowerlist); listView.setAdapter(sc); } } 可能不正常

3 个答案:

答案 0 :(得分:2)

@Alfe提供了一些特殊的解决方案。

你可能已经了解了跑步和跑步之间的时间安排。装饰器。

但是,由于您的目的不明确,根据您当前的代码,您可以尝试将代码重构为此样式:

def decme(context):
    def real_decme(function):
        def wrapper(*args, **kwargs):
            function(*args, **kwargs)
        return wrapper
    return real_decme

def call_me():
    pass

def caller_function():
    context = context_creator()
    decme(context)(call_me)()

在这种情况下,decme可以处理上下文。但它不会在装饰器生成时间内运行。

答案 1 :(得分:0)

您可以访问调用者堆栈并查看其框架中的所有局部变量。我使用这种技术来实现我的Stack Environment in Python,它或多或少地使用了这种技术,顺便说一下,它可以更整齐地解决你的整体问题。

但是,除非你把它放到一个漂亮的图书馆,它隐藏了所有丑陋的细节,我称之为丑陋的黑客。

如何将此上下文传递到call_me()?那么它的装饰师当然会收到它。

如果您选择使用StackEnv,这将是制定它的方法:

from stackEnv import stackEnv

def decme(function):
    def wrapper(*args, **kwargs):
        if stackEnv.context.someValue > someOtherValue:
            doSomething()
        return function(*args, **kwargs)
    return wrapper

@decme
def call_me():
    ...

def caller_function():
    stackEnv.context = context_creator()
    call_me()

答案 2 :(得分:0)

函数是一个对象,可以有属性。您可以直接将上下文作为包装器的属性传递:

def decme(f):
    def wrapped(*args, **kwargs):
        # here we can access the context passed as wrapped.context
        print("Before context:", wrapped.context) 
        cr = f(*args, **kwargs)
        print("After")
        return cr
    wrapped.context = None
    return wrapped

def caller_function():
    # just pass the context
    call_me.context = context_creator()
    call_me()

此处原始call_me没有context属性的概念,但已修饰的函数具有。唯一的缺点是它是函数的一个属性,并且会在调用中持续存在。特别是它会在多线程环境中导致意外结果......

或者,您可以使用装饰器向可在运行时传递的函数添加一个附加参数。这种方式是线程安全的:

def decme(f):
    def wrapped(context, *args, **kwargs):
        # here we can access the context
        print("Before context:", context) 
        cr = f(*args, **kwargs)    # call the underlying function
        print("After")
        return cr
    return wrapped

@decme
def call_me():
    ...


def caller_function():
    # just pass the context
    context = context_creator()
    call_me(context)