在Python中是否有方法检查函数输出是否分配给变量?

在Python中是否有方法检查函数输出是否分配给变量?,python,functional-programming,bytecode,Python,Functional Programming,Bytecode,在Python中,我想编写一个函数,如果自己调用,它会将结果打印到控制台上(主要用于交互或调试)。对于这个问题,假设它检查某个事物的状态。如果我打电话 check_status() 我想看看这样的东西: Pretty printer status check 0.02v NOTE: This is so totally not written for giant robots ================================= System operational: ... o

在Python中,我想编写一个函数,如果自己调用,它会将结果打印到控制台上(主要用于交互或调试)。对于这个问题,假设它检查某个事物的状态。如果我打电话

check_status()
我想看看这样的东西:

Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
=================================
System operational: ... ok
Time to ion canon charge is 9m 21s
Booster rocket in AFTERBURNER state
Range check is optimal
Rocket fuel is 10h 19m 40s to depletion
Beer served is type WICKSE LAGER, chill optimal
Suggested catchphrase is 01_FIGHTING_SPIRIT_GOGOGO
Virtual ... on
但是,如果我在变量赋值的上下文中调用它,我也希望它以列表的形式传递输出:

not_robot_stat = check_status()
print not_robot_stat
>>> {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'}

所以。。。是否有一种方法可以在函数中动态地知道其输出是否被分配?我希望能够做到这一点,而无需求助于param传递,或编写另一个专用于此的函数。我在谷歌上搜索了一段时间,从我所能知道的一点来看,我似乎不得不求助于使用字节码。这真的有必要吗?

函数无法知道其返回值是如何使用的


好吧,正如你所提到的,令人震惊的字节码黑客也许能够做到这一点,但这将是非常复杂的,而且可能是脆弱的。使用更简单的显式方法。

没有办法做到这一点,至少在正常语法过程中是这样,因为函数调用和赋值是完全独立的操作,它们彼此都不知道

我能看到的最简单的解决方法是将一个标志作为arg传递给
check\u status
函数,并相应地处理它

def check_status(return_dict=False) :
    if return_dict :
        # Return stuff here.
    # Pretty Print stuff here.
然后

check_status() # Pretty print
not_robot_stat = check_status(True) # Get the dict.

编辑:我以为你打印的次数比你指定的要多。如果情况并非如此,请交换默认值和传入的值。

要做您想要做的事情,唯一的方法就是“使用字节码”——没有其他方法可以恢复该信息。当然,更好的方法是提供两个单独的函数:一个获取dict状态,另一个调用第一个函数并格式化它

或者(但不是一个优秀的体系结构)您可以有一个函数,它采用一个可选参数以这两种完全不同的方式运行——这不是很好,因为一个函数应该有一个函数,即基本上只做一件事,而不是像这样的两个不同的函数

但是,我也希望它以列表的形式传递输出

您的意思是“将输出作为字典返回”-小心;-)

您可以做的一件事是使用Python解释器的功能将任何表达式的结果自动转换为字符串。为此,创建一个自定义的
dict
子类,当要求将其自身转换为字符串时,该子类将执行您想要的任何漂亮的格式设置。比如说,

class PrettyDict(dict):
    def __str__(self):
        return '''Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
=================================
System operational: ... %s
Time to ion canon charge is %dm %ds
Booster rocket in %s state
 (other stuff)
''' % (self.conf_op and 'ok' or 'OMGPANIC!!!',
       self.t_canoncharge / 60, self.t_canoncharge % 60, 
       BOOSTER_STATES[self.booster_charge],
       ... )
当然,您可能会想出一种更漂亮的方法来编写代码,但基本思想是
\uuuu str\uuu
方法创建一个漂亮的打印字符串,该字符串表示对象的状态并返回它。然后,如果键入时从
check_status()
函数返回
PrettyDict

>>> check_status()
你会看到

Pretty printer status check 0.02v NOTE: This is so totally not written for giant robots ================================= System operational: ... ok Time to ion canon charge is 9m 21s Booster rocket in AFTERBURNER state Range check is optimal Rocket fuel is 10h 19m 40s to depletion Beer served is type WICKSE LAGER, chill optimal Suggested catchphrase is 01_FIGHTING_SPIRIT_GOGOGO Virtual ... on 将给您相同的东西,因为相同的字符串转换是作为
print
函数的一部分进行的。但在一些实际应用中使用它,我怀疑这是否重要。如果您真的想将返回值看作一个纯dict,您可以这样做

>>> print repr(not_robot_stat)
相反,它应该告诉你

{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'} {'cond_op':1,'t_canoncharge':1342,'stage_booster':5,'range_est_sigma':0.023,'fuel_est':32557154,'beer_type':31007,'beer_temp':2,'Catchphase_suggestion':1023,'virtual__on':'Held yes')
关键是,正如其他海报所说,Python中的函数无法知道如何处理它的返回值(编辑:好的,也许会有一些奇怪的字节码攻击方式,但不要这样做),但在重要的情况下,您可以解决它。

新解决方案

这是一个新的解决方案,它通过检查自己的字节码来检测函数的结果何时用于赋值。没有字节码编写,它甚至应该与Python的未来版本兼容,因为它使用操作码模块进行定义

import inspect, dis, opcode

def check_status():

    try:
        frame = inspect.currentframe().f_back
        next_opcode = opcode.opname[ord(frame.f_code.co_code[frame.f_lasti+3])]
        if next_opcode == "POP_TOP": 
            # or next_opcode == "RETURN_VALUE":
            # include the above line in the if statement if you consider "return check_status()" to be assignment
            print "I was not assigned"
            print "Pretty printer status check 0.02v"
            print "NOTE: This is so totally not written for giant robots"
            return
    finally:
        del frame    

    # do normal routine

    info = {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

    return info

# no assignment    
def test1():
    check_status()

# assignment
def test2():
    a = check_status()

# could be assignment (check above for options)
def test3():
    return check_status()

# assignment
def test4():
    a = []
    a.append(check_status())
    return a
解决方案1

这是一个旧的解决方案,它在python-i或PDB下调试时检测何时调用函数

import inspect

def check_status():
    frame = inspect.currentframe()
    try:
        if frame.f_back.f_code.co_name == "<module>" and frame.f_back.f_code.co_filename == "<stdin>":
            print "Pretty printer status check 0.02v"
            print "NOTE: This is so totally not written for giant robots"
    finally:
        del frame

    # do regular stuff   
    return {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

def test():
    check_status()


>>> check_status()
Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

>>> a=check_status()
Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots

>>> a
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

test()
>>>
导入检查
def检查_状态():
frame=inspect.currentframe()
尝试:
如果frame.f_back.f_code.co_name==“”和frame.f_back.f_code.co_filename==“”:
打印“漂亮打印机状态检查0.02v”
打印“注意:这完全不是为巨型机器人写的”
最后:
三角架
#做常规的事情
返回{'cond_op':1,'t_canoncharge':1342,'stage_booster':5}
def test():
检查_状态()
>>>检查_状态()
漂亮的打印机状态检查0.02v
注意:这完全不是为巨型机器人编写的
{'cond_op':1,'t_canoncharge':1342,'stage_booster':5}
>>>a=检查状态()
漂亮的打印机状态检查0.02v
注意:这完全不是为巨型机器人编写的
>>>a
{'cond_op':1,'t_canoncharge':1342,'stage_booster':5}
测试()
>>>

这方面没有使用案例。Python将所有交互结果分配给一个名为
\uu
的特殊变量

您可以交互地执行以下操作。效果很好。没有有趣的事

>>> check_status()
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'}

>>> pprint.pprint( _ )
{'beer_temp': 2,
 'beer_type': 31007,
 'catchphrase_suggestion': 1023,
 'cond_op': 1,
 'fuel_est': 32557154,
 'range_est_sigma': 0.023,
 'stage_booster': 5,
 't_canoncharge': 1342,
 'virtual_on': 'hell yes'}

即使有办法做到这一点,这也是个坏主意。想象一下,尝试调试某个行为因调用它的上下文而异的对象。现在试着想象一下,六个月后,这些东西就埋在某个系统的某个部分里,这个系统太大了,你无法一下子将其保存在脑海中


保持简单。显式比隐式好。只需创建一个漂亮的print函数(或者使用pprint模块)并在结果中调用它。在交互式Pythn会话中,您可以使用u获取最后一个表达式的值。

我不一定同意让函数根据传递给它的值返回/打印是不好的架构
>>> check_status()
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'}

>>> pprint.pprint( _ )
{'beer_temp': 2,
 'beer_type': 31007,
 'catchphrase_suggestion': 1023,
 'cond_op': 1,
 'fuel_est': 32557154,
 'range_est_sigma': 0.023,
 'stage_booster': 5,
 't_canoncharge': 1342,
 'virtual_on': 'hell yes'}