Python:无论输出是否已分配,我都可以更改函数行为吗?

时间:2014-10-14 11:01:48

标签: python

在Matlab中,nargout是一个变量,它告诉你输出是否已分配,所以

x = f(2);

f(2);

行为可能不同。

是否有可能在Python中做类似的事情?

我有一个绘制屏幕并返回matplotlib图形对象的函数。我希望如果将输出分配给变量,则不要绘制到屏幕。

2 个答案:

答案 0 :(得分:4)

这是你可以做的一种方式(不是我建议它),但它有很多情况下它不起作用 - 使它工作你基本上需要解析该行中的python代码,看看它在做什么,这可能会达到某种程度,但总有可能总是有办法绕过它。

import inspect, re


def func(x, noCheck=False):
  if not noCheck:
      #Get the line the function was called on.
      _, _, _, _, lines, _ = inspect.getouterframes(inspect.currentframe())[1]

      #Now we need to search through `line` to see how the function is called.

      line = lines[0].split("#")[0] #Get rid of any comments at the end of the line.

      match = re.search(r"[a-zA-Z0-9]+ *= *func\(.*\)", line) #Search for instances of `func` being called after an equals sign

      try:
        variable, functioncall = match.group(0).split("=")
        print variable, "=", functioncall, "=", eval(functioncall.strip()[:-1] + ", noCheck=True)")

      except:
        pass #print "not assigned to a variable"

  #Actually make the function do something
  return 3*x**2 + 2*x + 1

func(1) # x = func(1)
x = func(1)

另一种方法是在调用代码时检查所有设置的局部变量,并检查是否有任何设置为函数的结果,然后使用该信息来帮助解析python。

或者您可以查看对象ID,并尝试以这种方式执行操作,但这不是直截了当的,因为并非所有对象都以相同的方式工作(即执行a=10c=10并且然后查看每个对象的ID,尽管ac是分开的,但它们是相同的。对于短字符串也是如此。

如果你能想出一个可以普遍运作的方法,我会有兴趣知道你是怎么做的,我应该通过挖掘检查来完成,而不是通过解析实际代码。

答案 1 :(得分:1)

其他人提到这很复杂,但可以通过检查来完成。您可能需要一个简单的方法,通过单独的函数来绘制它,或者传递一个额外的变量来表示绘图。

def create_plot(x):
    return plot

def display(plot):
    # show the plot

x = create_plot(2)
display(x)

绘制变量

def plot(x, show=False)
    # create the plot
    if show:
        # show the plot

plot(2, True)
x = plot(2)

可能不值得花时间而且更容易创建这两个函数。

就个人而言,我认为这很丑陋,令人讨厌,我不相信功能应该基于捕获返回值的东西。但是,我很好奇,我找到了办法。如果你想在将来使用它,你可能会把它变成一个装饰器,但我仍然建议你使用两个单独的方法而不是检查输出。

import inspect

def f(val):
    has_output = False
    frame = inspect.currentframe()
    name = frame.f_code.co_name
    outer = inspect.getouterframes(frame)[1] # may want to loop through available frames.
    for i in range(len(outer)):
        item = str(outer[i]).replace(" ", "")
        check = "="+name+"("
        if check in item and "="+check not in item: # also check assignment vs equality
            # Your method has an output
            has_output = True
            break

    if has_output:
        print("Something catches the output")
    return val*val
# end f

在许多情况下,这也不起作用。如果你总是想让它起作用,你必须为支票制作非常好的正则表达式。

import my_lib

x = my_lib.f(2)