开发者

how to couple 'reasons' with return values, elegantly

开发者 https://www.devze.com 2023-03-15 05:17 出处:网络
What often happens in code I\'m writing is I\'ll have a function that checks a condition dependent on many other conditions, e.g.:

What often happens in code I'm writing is I'll have a function that checks a condition dependent on many other conditions, e.g.:

def is_foo(bar):
    if X: return True
    if Y: return False
    if Z: return True
    return False

Then, I'll want to debug my code or log it, so I'll change the above to:

def is_foo_reason(bar):
    if X: return True, "cause of X you fool"
    if Y: return False, "no X but Y"
    if开发者_如何学Python Z: return True, "Z Z Z Z Z Z"
    return False, "default"
#for backwards compatibility:
def is_foo(bar): return is_foo_reason(bar)[0] 

Then the code that wants the reason (so it can log it / show it to user, w/e) calls the _reason version.

My question is: is there any more elegant way to do this?


This is a perfectly good way to do it. Only thing I might change is nest is_foo_reason in is_foo (so that there's only one, simple interface) and add a default argument to is_foo(), e.g.

#for backwards compatibility:
def is_foo(bar, reason=False): 
    def is_foo_reason(bar):
        if X: return True, "cause of X you fool"
        if Y: return False, "no X but Y"
        if Z: return True, "Z Z Z Z Z Z"
        return False, "default"
    if reason:
        return is_foo_reason(bar)
    else:
        return is_foo_reason(bar)[0] 

That way, the function by default won't give a reason, but if you want one, you can ask for one.


I think you shouldn't change the semantics of your function(s) if it's just about debugging. Use e.g. a logger instead. Take a look at Python's logging module: http://docs.python.org/library/logging.html

import logging

def is_foo(bar):
    logger = logging.getLogger()
    if X:
        logger.debug("msg1")
        return True
    if Y:
        logger.debug("msg2")
        ...

Then you can define your logging handler to either log the messages to a file, or print them on the screen, etc.


For future extensibility of your return values, use a namedtuple:

from collections import namedtuple
ExplainedValue = namedtuple('ExplainedValue', 'value explanation')

def is_foo_reason(bar):
    if X: return ExplainedValue(True, "cause of X you fool")
    if Y: return ExplainedValue(False, "no X but Y")
    if Z: return ExplainedValue(True, "Z Z Z Z Z Z")
    return ExplainedValue(False, "default")

def is_foo(bar): return is_foo_reason(bar).value
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号