-1

I have following structure for class.

class foo(object):
    def __call__(self,param1):
        pass
class bar(object):
    def __call__(self,param1,param2):
        pass

I have many classes of this type. And i am using this callable class as follows.

classes = [foo(), bar()]
for C in classes:
    res = C(param1) 
 '''here i want to put condition if class takes 1 argumnet just pass 1  
 parameter otherwise pass two.'''

I have think of one pattern like this.

class abc():
    def __init__(self):
        self.param1 = 'xyz'
        self.param2 = 'pqr'

    def something(self, classes): # classes = [foo(), bar()]
        for C in classes:
            if C.__class__.__name__ in ['bar']:  
                res = C(self.param1, self.param2)
            else:
                res = C(self.param2)

but in above solution have to maintain list of class which takes two arguments and as i will add more class to file this will become messy.

I dont know whether this is correct(pythonic) way to do it.

  • On more idea i have in mind is to check how many argument that class is taking. If its 2 then pass an additional argument otherwise pass 1 argument.I have looked at this solution How can I find the number of arguments of a Python function? . But i am not confident enought that this is the best suited solution to my problem.
  • Few things about this:
    • There are only two type of classes in my usecase one with 1 argument and one with 2.
    • Both class takes first argument same so params1 in both case is same argument i am passing. in case of class with two required parameter i am passing additional argument(params2) containing some data. Ps : Any help or new idea for this problem are appretiated. UPD : Updated the code.
Poojan
  • 2,985
  • 2
  • 13
  • 31
  • 1
    I assume your `def __class__` is a typo and was supposed to be `def __call__` ? – bruno desthuilliers Jan 28 '19 at 15:13
  • @brunodesthuilliers So sorry about that. i fixed it now. – Poojan Jan 28 '19 at 15:16
  • Why are you putting the objects in a single list if they don't share the same behavior? If you know objects of `bar` take 2 parameters and objects of `foo` take one parameter, put them in separate lists and iterate over them separately. – chepner Jan 28 '19 at 16:21
  • @chepner in my case that list is coming from another class. i am taking those callable as argument of class method. I will update the code – Poojan Jan 28 '19 at 16:23

1 Answers1

0

Basically, you want to use polymorphism on your object's __call__() method, but you have an issue with your callables signature not being the same.

The plain simple answer to this is: you can only use polymorphism on compatible types, which in this case means that your callables MUST have compatible signatures.

Hopefully, there's a quick and easy way to solve this: just modify your methods signatures so they accept varargs and kwargs:

class Foo(object):
    def __call__(self,param1, *args, **kw):
        pass

class Bar(object):
    def __call__(self, param1, param2, *args, **kw):
        pass

For the case where you can't change the callable's signature, there's still a workaround: use a lambda as proxy:

def func1(y, z):
   pass

def func2(x):
   pass


callables = [func1, lambda y, z: func2(y)]
for c in callables:
    c(42, 1138)

Note that this last example is actually known as the adapter pattern

Unrelated: this:

if C.__class__.__name__ in ['bar']:

is a inefficient and convoluted way to write:

if C.__class__.__name__ == 'bar':

which is itself an inefficient, convoluted AND brittle way to write:

if type(C) is bar:

which, by itself, is a possible design smell (there are legit use cases for checking the exact type of an object, but most often this is really a design issue).

bruno desthuilliers
  • 68,994
  • 6
  • 72
  • 93
  • Thank you for answer. Yes it will be better if i dont change all class `__call__` method with `*args`. And your second suggested solution also will work. But i am looking for a way where in future i dont have to maintain it manually. In this case for each function that takes one argument i have to add lambda proxy in my callable list. Thanks for tip on better way to check type of class. – Poojan Jan 28 '19 at 15:34