HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Scala inspired classes in Python

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
pythonscalainspiredclasses

Problem

I have to define a lot of values for a Python library, each of which will represent a statistical distribution (like the Normal distribution or Uniform distribution). They will contain describing features of the distribution (like the mean, variance, etc). After a distribution is created it doesn't really make sense to change it.

I also expect other users to make their own distributions, simplicity is an extra virtue here.

Scala has really nice syntax for classes in cases like this. Python seems less elegant, and I'd like to do better.

Scala:

class Uniform(min : Double, max : Double) {
    def logp(x : Double) : Double = 
        1/(max - min) * between(x, min, max)

    def mean = (max + min)/2
}


Python:

class Uniform(object):
    def __init__(self, min, max):
        self.min = min
        self.max = max
        self.expectation = (max + min)/2

    def logp(self, x):
        return 1/(self.max - self.min) * between(x, self.min, self.max)


It's not terrible, but it's not great. There are a lot of extra selfs in there and the constructor part seems pretty boilerplate.

One possibility is the following nonstandard idiom, a function which returns a dictionary of locals:

def Uniform(min, max):
    def logp(x): 
        return 1/(max - min) * between(x, min, max)

    mean = (max + min)/2
    return locals()


I like this quite a bit, but does it have serious drawbacks that aren't obvious?

It returns a dict instead of an object, but that's good enough for my purposes and would be easy to fix with a that made it return an object.

Is there anything better than this? Are there serious problems with this?

Solution

You might prefer to use namedtuple for the attributes, and the property decorator for mean. Note that mean is now computed every time it's accessed - maybe you don't want this, or maybe it makes sense since max and min are mutable.

from collections import namedtuple

class Uniform(namedtuple('Uniform', ('min', 'max'))):

    def logp(self, x):
        return 1/(self.max - self.min) * between(x, self.min, self.max)

    @property
    def mean(self):
        return 0.5*(self.min + self.max)

Code Snippets

from collections import namedtuple

class Uniform(namedtuple('Uniform', ('min', 'max'))):

    def logp(self, x):
        return 1/(self.max - self.min) * between(x, self.min, self.max)

    @property
    def mean(self):
        return 0.5*(self.min + self.max)

Context

StackExchange Code Review Q#21666, answer score: 9

Revisions (0)

No revisions yet.