method that can be called from a class and also from an instance

Peter Otten __peter__ at web.de
Fri Nov 23 03:52:25 EST 2012


Steven D'Aprano wrote:

> On Thu, 22 Nov 2012 16:51:27 +0100, Peter Otten wrote:
> 
>> Marc Aymerich wrote:
>> 
>>> Hi,
>>> 
>>> I want to create a method within a class that is able to accept either
>>> a class or an instance.
> [...]
>> Why would you overload a method that way?
> 
> 
> The use-case I have is that I have a number of classes with default
> state. Most instances don't override any of the state, so the instances
> don't add anything except an extra conceptual layer:
> 
> instance = MyClass()  # notice that there are no arguments passed
> instance.method(args)
> 
> Since the instances don't have any state except for that already held by
> the class, they are redundant and pointless. Just knowing the class is
> enough to specify the behaviour. If I used class methods, I could do this:
> 
> MyClass.method(args)
> 
> 
> But here's the thing -- sometimes I *do* have instances that override the
> default state:
> 
> instance = MyClass(x, y, z)
> instance.method(args)
> 
> Now if method is a class method, my per-instance state is ignored. So I
> want a method that can be called from the class, and see the default
> state, or from the instance, and see the per-instance state. Neither
> classmethod, staticmethod nor ordinary instance methods do the job, but
> my custom dualmethod does.
> 
> http://code.activestate.com/recipes/577030/

Am I reading that right that you don't invoke method() as MyClass.method()? 
Then I'd probably use class attributes to store the default state and shade 
them by instance attributes as needed.

class A:
    state = "default"
    def __init__(self, state=None):
        if state is not None:
            self.state = state
    def method(self): return self.state

assert A().method() == "default"
assert A("special").method() == "special"

The same idea might work for the OP, too (but I'm not sure it's a good 
idea):

class B:
    def inst_f(self):
        return "instance"
    @classmethod
    def f(class_):
        return "class"
    def __init__(self):
        self.f = self.inst_f

assert B.f() == "class"
assert B().f() == "instance"





More information about the Python-list mailing list