natter1
natter1

Reputation: 394

Pythonic way to combine simillar methods called from classmethod and instance method

I have a class with methods and classmethods to create Figures. The class has also an attribute auto_show on class and on instance level. That's used to decide whether the created figures should be shown automatically or not. Right now I need two different methods to achieve this:

class MyClass:
    auto_show = True
    ...
    def __init__(self, ...):
        self.auto_show = MyClass.auto_show
        ...

    @classmethod
    def _class_auto_show_figure(cls, fig):
        """Should be used only for class methods"""
        if cls.auto_show:
            fig.show()

    def _auto_show_figure(self, fig):
        if self.auto_show:
            fig.show()

Right now the first one is called inside all classmethods and the second is called inside all instance methods. I would like to combine them in a single method, but couldn't find a satisfactory way to do this. Is there a good solution for this, or should I stick with two separate methods doing basically the same thing? (Btw. it's important that an instance could have a different value for auto_show compared to the class-attribute.)

Upvotes: 1

Views: 382

Answers (2)

quantummind
quantummind

Reputation: 2136

You can do that with one function in the following way:

class MyClass: 
     auto_show = True 
     
     def __init__(self): 
         self.auto_show = MyClass.auto_show  # can be changed to (obj.__class__).auto_show 



     def fun(self=None): 
         if self==None: 
              print("class auto_show:", MyClass.auto_show) 
         else: 
              print("instance auto_show:", self.auto_show) 
                                                                                                                                                                                              

obj=MyClass()                                                                                                                                                                             

MyClass.fun()                                                                                                                                                                             
out: class auto_show: True

obj.fun()                                                                                                                                                                                 
out: instance auto_show: True

obj.auto_show = False                                                                                                                                                                     

MyClass.fun()                                                                                                                                                                             
out: class auto_show: True

obj.fun()                                                                                                                                                                                 
instance auto_show: False

Check whether this method meets your requirements.

Upvotes: 3

kaya3
kaya3

Reputation: 51034

Here's a solution using the descriptor protocol:

from functools import partial

class ClassOrInstanceMethod:
    def __init__(self, f):
        self.f = f
    def __get__(self, instance, cls=None):
        return partial(self.f, cls, instance)

class Foo:
    data = 'Foo class data'
    def __init__(self, data):
        self.data = data
    
    @ClassOrInstanceMethod
    def test(cls, instance):
        if instance is None:
            print(cls.data)
        else:
            print(instance.data)

class Bar(Foo):
    data = 'Bar class data'

Foo.test() # prints 'Foo class data'
Bar.test() # prints 'Bar class data'
Foo('Foo instance data').test() # prints 'Foo instance data'
Bar('Bar instance data').test() # prints 'Bar instance data'

Upvotes: 1

Related Questions