I'm wondering if it's possible to make a method which behaves differently when called as a class method than when called as an instance method.
For example, as a skills-improvement project, I'm writing a Matrix
class (yes, I know there are perfectly good matrix classes already out there). I've created a class method for it called identity
which returns an identity matrix of a specified size.
Now, when called on an instance of Matrix
, it seems logical that the size shouldn't need to be specified; it should return an identity matrix of the same size as the Matrix
it's called on.
In other words, I'd like to define a method which can determine whether it was called via an instance and, if so, access that instance's attributes. Unfortunately, even after digging through the documentation and a few Google searches, I haven't found anything which suggests this is possible. Does anyone know differently?
Edit:
Wow! Clearly, I'm still not quite used to first-class functions. Here's what I ended up with — thanks to Unknown for providing the key!
class Foo(object):
def __init__(self, bar):
self.baz = bar
self.bar = MethodType(lambda self: self.__class__.bar(self.baz), self, self.__class__)
@classmethod
def bar(cls, baz):
return 5 * baz
Foo.bar(3) # returns 15
foo = Foo(7)
foo.bar() # returns 35
Edit 2:
Just a quick note — this technique (and most of those presented below) won't work on classes which define __slots__
, as you cannot reassign the method.
[edited: use attribute to be a more direct answer; see the helpful comment by John Fouhy]
You can use a descriptor to do what you want:
Using the above:
I think the larger problem is that you are overloading the name 'bar' on class 'Foo', something python doesn't allow. The second definition of 'bar' clobbers the first definition of 'bar'.
Try to think of unique names for your classmethod and instance method. i.e.
Questionably useful Python hacks are my forte.
@Unknown What's the difference between your's and this:
You can reassign your identity method in init with short lambda function:
If you're not familiar with lambda, it creates an anonymous function. It's rarely necessary, but it can make your code more concise. The lambda line above could be rewritten: