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.
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.
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.
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.
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”.
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
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.
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
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.
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.
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.
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.
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”.
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
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.
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