Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a function is pure in Python?

A pure function is a function similar to a Mathematical function, where there is no interaction with the "Real world" nor side-effects. From a more practical point of view, it means that a pure function can not:

  • Print or otherwise show a message
  • Be random
  • Depend on system time
  • Change global variables
  • And others

All this limitations make it easier to reason about pure functions than non-pure ones. The majority of the functions should then be pure so that the program can have less bugs.

In languages with a huge type-system like Haskell the reader can know right from the start if a function is or is not pure, making the successive reading easier.

In Python this information may be emulated by a @pure decorator put on top of the function. I would also like that decorator to actually do some validation work. My problem lies in the implementation of such a decorator.

Right now I simply look the source code of the function for buzzwords such as global or random or print and complains if it finds one of them.

import inspect

def pure(function):
    source = inspect.getsource(function)
    for non_pure_indicator in ('random', 'time', 'input', 'print', 'global'):
        if non_pure_indicator in source:
            raise ValueError("The function {} is not pure as it uses `{}`".format(
                function.__name__, non_pure_indicator))
    return function

However it feels like a weird hack, that may or may not work depending on your luck, could you please help me in writing a better decorator?

like image 778
Caridorc Avatar asked Jul 22 '15 16:07

Caridorc


People also ask

How do you know if a function is pure?

A function's pure if it's free from side-effects and returns the same output, given the same input. Side-effects include: mutating input, HTTP calls, writing to disk, printing to the screen.

What is a pure function in Python?

A pure function is a function whose output value follows solely from its input values, without any observable side effects. In functional programming, a program consists entirely of evaluation of pure functions. Computation proceeds by nested or composed function calls, without changes to state or mutable data.

What makes a function pure?

A Pure Function is a function (a block of code) that always returns the same result if the same arguments are passed. It does not depend on any state or data change during a program's execution. Rather, it only depends on its input arguments.

What are the characteristics of pure function in Python?

Pure functions have 2 characteristics - they have no side effects and the return value is the same for the same parameters. A functional programming language must have immutability, and python has some immutable data types such as tuples.


2 Answers

I kind of see where you are coming from but I don't think this can work. Let's take a simple example:

def add(a,b):
    return a + b

So this probably looks "pure" to you. But in Python the + here is an arbitrary function which can do anything, just depending on the bindings in force when it is called. So that a + b can have arbitrary side effects.

But it's even worse than that. Even if this is just doing standard integer + then there's more 'impure' stuff going on.

The + is creating a new object. Now if you are sure that only the caller has a reference to that new object then there is a sense in which you can think of this as a pure function. But you can't be sure that, during the creation process of that object, no reference to it leaked out.

For example:

class RegisteredNumber(int):

    numbers = []

    def __new__(cls,*args,**kwargs):
        self = int.__new__(cls,*args,**kwargs)
        self.numbers.append(self)
        return self

    def __add__(self,other):
        return RegisteredNumber(super().__add__(other))

c = RegisteredNumber(1) + 2

print(RegisteredNumber.numbers)

This will show that the supposedly pure add function has actually changed the state of the RegisteredNumber class. This is not a stupidly contrived example: in my production code base we have classes which track each created instance, for example, to allow access via key.

The notion of purity just doesn't make much sense in Python.

like image 157
strubbly Avatar answered Oct 15 '22 02:10

strubbly


(not an answer, but too long for a comment)

So if a function can return different values for the same set of arguments, it is not pure?

Remember that functions in Python are objects, so you want to check the purity of an object...

Take this example:

def foo(x):
    ret, foo.x = x*x+foo.x, foo.x+1
    return ret
foo.x=0

calling foo(3) repeatedly gives:

>>> foo(3)
9

>>> foo(3)
10

>>> foo(3)
11

...

Moreover, reading globals does not require to use the global statement, or the global() builtin inside your function. Global variables might change somewhere else, affecting the purity of your function.

All the above situation might be difficult to detect at runtime.

like image 35
fferri Avatar answered Oct 15 '22 01:10

fferri