referencing class methods in class lists in Python

Question:

I am writing a class in Python 2.6.2 that contains a lookup table. Most cases are simple enough that the table contains data. Some of the cases are more complex and I want to be able call a function. However, I’m running into some trouble referencing the function.

Here’s some sample code:

class a:
    lut = [1,
           3,
           17,
           [12,34],
           5]

Where lut is static, and is expected to be constant as well.

and now I wan to do the following:

class a:
    def spam0(self):
        return (some_calculation_based_on_self)

    def spam1(self):
        return (a_different_calculation_based_on_self)

    lut = [1,
           3,
           17,
           [12,34],
           5,
           self.spam0
           self.spam1]

This doesn’t compile because self.spam0 and self.spam1 are undefined. I tried using a.spam but that is also undefined. How can I set lut[5] to return a reference to self.spam?

Edit: This is what I plan to do:

(continuing the definition of class a):

import inspect

# continue to somewhere in the definition of class a

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

def eggs(self):
    tmp = lut[param]
    if (insect.isfunction(tmp)): # if tmp is self.spam()
        return tmp()             # should call it here
    return tmp

So I want to either return a simple value or run some extra code, depending on the parameter.

Edit: lut doesn’t have to be a class property, but the methods spam0 and spam1 do need to access the class members, so they have to belong to the class.

I’m not sure that this is the best way to do this. I’m still in the process of working this out.

Asked By: Nathan Fellman

||

Answers:

You’re going to need to move the definition of a.lut outside of the definition of a.

class a():
    def spam():pass

a.lut = [1,2,3,a.spam]

If you think about it, this makes perfect sense. Using self wouldn’t work because self is actually only defined for class methods for which you use the parameter “self“. self has no special meaning in Python and is not a reserved word; it is simply the conventional argument passed to bound class methods, but could also be this, or foo, or whatever you want.

Referring to a.lut doesn’t work because the definition of a isn’t complete yet. How should Python know, at that point in the code, what a is? In the scope of a‘s class definition, a itself is still undefined.

Answered By: Kenan Banks

In the clas body, you’re creating the class; there is no self, so you obviously cannot yet refer to self.anything. But also within that body there is as yet no a: name a gets bound AFTER the class body is done. So, although that’s a tad less obvious, in the body of class a you cannot refer to a.anything either, yet.

What you CAN refer to are bare names of class attributes that have already been bound: for example, you could simply use 5, spam] at the end of your list lut. spam will be there as a function, as you say at one point that you want; not as a method, and most definitely NOT as a class method (I don’t see classmethod ANYWHERE in your code, why do you think a class method would magically spring into existence unless you explicitly wrap a function in the classmethod builtin, directly or by decorator?) — I suspect your use of “class method” does not actually refer to the class-method type (though it’s certainly confusing;-).

So, if you later need to call that function on some instance x of a, you’ll be calling e.g. a.lut[-1](x), with the argument explicitly there.

If you need to do something subtler it may be possible to get a bound or unbound method of some sort at various points during processing (after the class creation is done, or, if you want a bound instance method, only after a specific instance is instantiated). But you don’t explain clearly and completely enough what exactly it is that you want to do, for us to offer very detailed help on this later-stage alternatives.

Answered By: Alex Martelli

While you are in the scope of the class, you can just write

class A:
    def spam(self):
        pass

    lut = [1, 2, 3, spam]

a = A()
print a.lut

gives

[1, 2, 3, <function spam at 0xb7bb764c>]

Don’t forget that this is a function in your lookup table, not a number as you probably intended. You probably want to solve another problem.

Answered By: Otto Allmendinger

I’m not sure I understand the question. Is this what you mean?

class a:
    lut = [1,
           3,
           17,
           [12,34],
           5]

    def __init__(self):
        self.lut.append(self.spam)

    def spam(self, a):
        print "this is %s" % a

b = a()
b.lut[-1](4)

this will output: “this is 4”.

Answered By: giorgian

Trivial:

class a:
    @classmethod
    def spam(cls):
        # not really pass, but you get the idea
        pass

    lut = [1,
           3,
           17,
           [12,34],
           5,
           spam]


assert a().lut[-1] == a.spam
assert a.spam() is None
Answered By: ilya n.

You want the function to be bound to the class. None of the answers seem to address this.

This won’t be done automatically; when you do this:

class a:
    def spam(self): print self
    lut = [1, spam]

lut[1] is spam itself, not a bound method to an object, so you can’t simply call lut[1](); you’d have to call lut[1](self).

If you specifically want to be able to include functions in the list that can be called directly, you need to arrange for the functions to be bound, which means referencing them from an instance and not the class. To do this, you’d probably want to initialize this list from __init__:

class a:
    def spam(self): print self
    def __init__(self):
        self.lut = [1, self.spam]

and now self.lut[1]() is correct, since it’s a bound method.

This all has the advantage that other functions can be placed in the list for other purposes, possibly bound to other objects or otherwise not expecting a parameter.

It has the disadvantage that you aren’t reusing the list between instances; this may or may not matter to you.

Answered By: Glenn Maynard

Remember that there’s no such thing as static, or constant, in Python. Just make it easy to read. Here’s an example which generates a cached version of lut per object:

class A(object):
    def __init__(self):
        self.__cached_lut = None

    def spam0(self):
        return (some_calculation_based_on_self)

    def spam1(self):
        return (a_different_calculation_based_on_self)

    @property
    def lut(self):
         if self.__cached_lut is None:
             self.__cached_lut = [1,
               3,
               17,
               [12,34],
               5,
               self.spam0()
               self.spam1()]
         return self.__cached_lut

a = A()
print a.lut
Answered By: John Millikin
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.