tags:

views:

39

answers:

5

Which of the following code snippets is the most "pythonic"? The calculation is trivial in this example but could be assumed to be complex in real life.

class A(object):
    """Freely mix state and calcs - no good I presume"""
    def __init__(self, state):
        self.state = state

    def calc_with_state(self, x):
        return (self.state + x)**2

or

class B(object):
    """Separate state from calc by a static method"""
    @staticmethod
    def inner_calc(u, v):
        return (u + v)**2

    def __init__(self, state):
        self.state = state

    def calc_with_state(self, x):
        return B.inner_calc(self.state, x)

or

class C(object):
    """Break out the calculation in a free function"""
    def __init__(self, state):
        self.state = state

    def calc_with_state(self, x):
        return outer_calc(self.state, x)

def outer_calc(u, v):
    return (u + v)**2
+1  A: 

I think it depends on your particular project. Is cal_with_state only applicable to this particular class or is the method needs to be shared among many different objects? Do different classes share it?

There is nothing more or less pythonic about any of this approaches, use the one that will satisfy your project. DRY is beyond pythonicity.

SilentGhost
It seems we said roughly the same thing at the same time.
Singletoned
A: 

Personally I would say it depends on resusability. If the calculation is one that might be used with other objects (as it does look to be) then the third example is the most reusable. If the calculation is completely tied to the object or would never be reused then the first example. I'd say the second example is wrong in most cases.

Singletoned
A: 

Factoring out the calculation, whether in a static or global method doesn't offer any benefit with regards to the state awareness. The only slight advantage is that the code explicitly shows which of the object's stateful properties are taken into account in the calculation (show at the level of the function call, rather than having to be read within the logic of the method in the class A)

There may be other advantages to introducing stateless (static, global) or instance methods:

  • reusability
  • code readability and management at large

but as said, these constructs do not help with regards to state management per-se. The A approach seems quite legitimate (and pythonic) to me. Indeed David Berger beat us to it, in reminding us that...

Flat is better than nested!

.

mjv
A: 

What is wrong with A? It does the calculation in one place only and does not modify the state so calc_with_state is a method that does not change state so is a 'simple' behaviour. If the state was complex it stops a large number of parameters being passed into the calculation function.

However if the calculation can be written taking the state as a parameter (as in C) then you can separate out the calculation. benefits here include being able to rues this calculation on data not in the class C and also you can use the function as data passed to C so calc_with_state can be made to call different calculation functions

I can't see B having any benefits as inner_calc does not make use of the class and so could just as well be a free function.

So I would probably write it as A first and then if wanting to reuse the calculation, make the class use different calculations or just if the code of the calculation got too big you could refactor into class C

Mark
+4  A: 

As written, A, by a longshot. The issue, quite simply, is

Flat is better than nested.

Look: separating state from calculations is a good design principle, but it doesn't mean what you think, at least not what I can infer you think from this example. We want to make sure that state doesn't change in order to complete calculations if that state isn't going to be reinitialized on the next calculation. If state is read-only with respect to some particular calculation, there's no stylistic compulsion to redirect around it so that you don't directly read it. That is, unless the calculation and the state are sufficiently complex to need separate unit testing. Then, by all means, B or C will be preferred, but only if it is really that much easier to create values for u than to instantiate fresh instances of A.

David Berger
Most of us here said the same thing. You did beat us with with the quote from PEP20. +1!
mjv
Yes, but I'm starting to question whether this is the best application of that point, since I kind of imagine that it is usually understood to apply to data structure rather than code structure. I could have gone with "Simple is better than complex," and made a similar but more vague point.
David Berger
Actually the flat vs. nested also speaks to code (as opposed to just data structures). I've seen discussions/opinions on this topic, for example in the [distinct but related] area of object modeling whereby it is generally considered poor pythonic practice to have "too many dots" (as in "myObj1.myContainedObj2.PropertyX.DoThis()". Anyway... I hope citing "verses" from the Zen of Python doesn't flag Pythons programmers as dogmatic drones ;-) Let's edge our bets: _Everything thing else being equal_, Flat is better than nested.
mjv