zeycus
zeycus

Reputation: 890

Subtle unexpected behaviour with a function used as class-attribute

I have a piece of code that was broken when I changed an attribute and made it class-attribute, I would love to understand why.

So, I started with

def linInterp(x1, x2, y1, y2, x):
    return y1 + (x - x1) * (y2 - y1) / (x2 - x1)

class Inter1DLineal(object):
    def __init__(self):
        self.interpSegment = linInterp

if __name__ == "__main__":
    inter = Inter1DLineal()
    print(inter.interpSegment(0.2, 0.6, 0, 1, 0.4))

which works alright. I know I could implement interpSegment as a proper method in Inter1DLineal, for instance as

@classmethod
def interpSegment(cls, *args, **kwargs):
    return linInterp(*args, **kwargs)

but I thought I was fine with an attribute of type function.

What surprised me was what happened next. I decided that, because interpSegment is common to all instances, I should make it a class attribute.

def linInterp(x1, x2, y1, y2, x):
    return y1 + (x - x1) * (y2 - y1) / (x2 - x1)

class Inter1DLineal(object):
    interpSegment = linInterp
    def __init__(self):
        pass

if __name__ == "__main__":
    inter = Inter1DLineal()
    print(inter.interpSegment(0.2, 0.6, 0, 1, 0.4))

But this broke the code. It seems the call to interpSegment is passing now passing 6 attributes, not 5. Can someone explain why this happens? What would the most Pythonistic way of doing this?

Upvotes: 0

Views: 77

Answers (1)

sshashank124
sshashank124

Reputation: 32199

well you are passing the inter as the first parameter which is the self parameter. So essentially, in the "__main__" code, you are passing something as follows:

interpSegment(inter, 0.2, 0.6, 0, 1, 0.4)

You should instead call it as:

Inter1DLineal.interpSegment(0.2, 0.6, 0, 1, 0.4)

However, let me also state that what you were doing first where interpSegment was in __init__ or as a method on its own is a better way of doing it.

Upvotes: 1

Related Questions