1

In Python 3 you can create classes like this:

class foo:
    def __init__(self, x):
        self.x=x

    def __call__(self, y):
        self.x = self.x + 1
        return (self.x, y)

And then one can use it as a functor with a state like this:

functor = foo(5)
x = 44354234
print('(1.1) ', functor(7))
print('(1.2) ', functor(8))
print('(1.2) ', functor(9))

In practice I've created a function that returns a function. However, this first function actually is a constructor that returns a callable object. IMHO this opens up a can of worms by allowing developers to extend the class, add methods, etc etc. Moreover, the code in __init__ somehow naturally precedes that of the code in __call__ as it needs to be executed, and that's not clear within the class-construct. Finally, the Python 3 'way' suggests to use functions over classes.

For this reason I created a similar function-version of the class, which has less boilerplate code and IMHO reads more natural:

def bar(x):
    def f(y):
        nonlocal x
        x = x + 1
        return (x,y)
    return f

functor2 = bar(5)
x = 345234234
print('(2.1) ', functor2(7))
print('(2.2) ', functor2(8))
print('(2.3) ', functor2(9))

However, it uses nonlocal and might not be intuitive for reasons I have not thought of. Is the second approach good practice, or are there dangerous pit-culls? Which should be preferred in Python 3? Especially since I have little experience with the use of nonlocal.

Herbert
  • 5,279
  • 5
  • 44
  • 69
  • 1
    *“IMHO this opens up a can of worms by allowing developers to extend the class”* – that is a bad thing why? Also, I’m not sure what the question is. Which would be preffered? Use what makes more sense. – poke Jan 19 '16 at 10:56
  • 2
    "Moreover, the code in __init__ somehow naturally precedes that of the code in __call__ as it needs to be executed, and that's not clear within the class-construct." => it **is** perfectly clear that the initializer __will__ be executed before it's even possible to call `__call__`. – bruno desthuilliers Jan 19 '16 at 11:39
  • 2
    "Finally, the Python 3 'way' suggests to use functions over classes" : chapter and verse please ? The "Python way" - whatever the version FWIW - is to use the construct that makes sense for the task at hand. In this case both make sense, but the first one allows for subclassing and easy inspection. – bruno desthuilliers Jan 19 '16 at 11:44
  • @brunodesthuilliers I was referring to this: https://github.com/amontalenti/elements-of-python-style/blob/master/README.md#functions-vs-classes - My point about classes was that they (1) risk becoming god-classes as they get extended with properties and methods and (2) don't describe a natural input-output flow as it is not clear which properties are read or written in which methods. – Herbert Jan 19 '16 at 15:36
  • @brunodesthuilliers Yes, __init__ clearly goes before __call__, but I think class-code does not necessarily emphasize this, especially when there are more methods than just call. Granted, this is very open for debate. – Herbert Jan 19 '16 at 15:39
  • @poke A better formulation is: Why would the nested function not be preferred? I am biased towards using functions instead of classes, and in this particular case I wanted to know if there is a reason to still use classes. – Herbert Jan 19 '16 at 15:40
  • One part that I might not have explained clearly is that I'm not very familiar with `nonlocal`. It seems to me that `nonlocal x` tells one that `x` is declared somewhere up in the 'code nesting', but not really where it is. If one initially declares `x` two nestings up and then accidentally creates a new `x` one nesting up, will this easily introduce bugs? Moreover, are the nested functions unit testable? I am not experienced in using nested functions and am indeed looking for opinions, but I do think these opinions could be based on arguments. – Herbert Jan 19 '16 at 15:51

1 Answers1

3

In some recent years Python development policy looks like to be "let's incorporate in Python every feature from other languages" and this leads to ability to accomplish single task in various ways.

So there's really no "preferred way" to do some things and it all depends on what a developer wants to do. So using Class to create a stateful function and allowing to extend it might be needed in some situations. Using closure with nonlocal is more common IMO, and there's nothing non-intuitive in it. Another question is i.e. when using this approach for method decorators, then with functions you'll have to write less code, and with classes you'll have to add more 'magic', because of self.

P.S. In Python, functions can have attributes, so one more way to code the same is using x as attribute of f inner function instead of nonlocal, though it's less common approach then those described by you.

def bar(x):
    def f(y):
        f.x=f.x+1
        return (f.x, y)
    f.x=x
    return f

EDIT: added extra indent to return statement

Herbert
  • 5,279
  • 5
  • 44
  • 69
Nikita
  • 6,101
  • 2
  • 26
  • 44
  • Your solution is equal to a global variable though, as the value of `x` is bound to the function, and not to an actual function object. – poke Jan 19 '16 at 12:14
  • Indeed. Improved it, though the previous version would still work. – Nikita Jan 19 '16 at 14:01