[Tutor] How (not!) lengthy should functions be?

Peter Otten __peter__ at web.de
Thu Apr 16 20:43:47 CEST 2015


boB Stepp wrote:

> As I go through my current coding project(s) I find myself breaking
> functions down into other functions, especially when I see see
> (unnecessarily) duplicated code fragments. I understand this to be
> regarded as good practice. However, I am wondering if I am carrying
> things too far? For instance I have a collection of functions that do
> simple units conversions such as:
> 
> def percent2Gy(dose_percent, target_dose_cGy):
>    """
>    Convert a dose given as a percent of target dose into Gy (Gray).
>    """
>    dose_Gy = cGy2Gy((dose_percent / 100.0) * target_dose_cGy)
>    return dose_Gy
> 
> This function calls another units conversion function, cGy2Gy(), in
> doing its work. Generally speaking, I have units conversions functions
> for every conversion I currently need to do plus some that I am not
> using yet because I can easily see the need for them in the future.
> 
> My current understanding of function length best practice is that: 1)
> Each function should have preferably ONE clearly defined purpose. 2) I
> have seen varying recommendations as to number of lines of code per
> function, but I have seem multiple recommendations that a function
> generally should fit into one screen on one's monitor. Of course, some
> people have HUGE monitors! And I assume that any guidance applies
> equally well to methods.
> 
> Am I on-track or am I getting carried away?

Normally I just stress that functions cannot get too short as both beginners 
and smart people tend to make them too long. As far as I'm concerned a 
function with a single line is fine while a function with more than 10 lines 
needs justification.

However, there's more to it. You are working in an environment where people 
may be harmed if you get your numbers wrong, and nothing hinders you to swap 
the arguments in your percent2Gy() function or even pass it a length and an 
amount of dollars. You need measures to make this unlikely.

Unambiguous function names and keyword-only parameters (not available in 
Python 2) and of course tests help, but you might also consider custom types 
that are restricted to a well-defined set of operations. A sketch:

# For illustration purpose only!
class Percent:
    def __init__(self, value):
        if value < 1 or value > 100: # XXX allow 0%?
            raise ValueError
        self.value = value
    def factor(self):
        return self.value / 100.0
    def __repr__(self):
        return "{} %".format(self.value)

class DoseInGray:
    def __init__(self, value, **comment):
        self.value = value
        self.comment = comment.pop("comment", "<no comment>")
        if comment:
            raise TypeEror
    def __repr__(self):
        return "{} Gy # {}".format(self.value, self.comment)
    def __str__(self):
        return  "{} Gy".format(self.value)

class TargetDoseInGray:
    def __init__(self, value):
        self.value = value
    def partial_dose(self, percent):
        if not isinstance(percent, Percent):
            raise TypeError
        return DoseInGray(
            self.value * percent.factor(),
            comment="{} of the target dose".format(percent))
    def __str__(self):
        return "{} Gy".format(self.value)


if __name__ == "__main__":
    target_dose = TargetDoseInGray(20)
    print target_dose
    
    partial_dose = target_dose.partial_dose(Percent(10))
    print partial_dose
    print repr(partial_dose)

    target_dose.partial_dose(0.1) # raises TypeError

Output:

$ python gray.py 
20 Gy
2.0 Gy
2.0 Gy # 10 % of the target dose
Traceback (most recent call last):
  File "gray.py", line 43, in <module>
    target_dose.partial_dose(0.1) # raises TypeError
  File "gray.py", line 27, in partial_dose
    raise TypeError
TypeError

OK, I got carried away a bit with my example, but you might get an idea 
where I'm aiming at. The way I wrote it it is pretty clear that Percent(10) 
denote 10 rather than 1000 %.

I can't spare you a last remark: Python may not be the right language to 
make this bulletproof.



More information about the Tutor mailing list