Reputation: 2615
I have a python class , which inherits multiple classes, and have test_func() with same name
parent.py
class parent:
def __init__(self, **kwargs):
self.ip = kwargs.get('ip')
self.name = kwargs.get('name')
self.local = kwargs.get('local')
class child1(parent):
def __init__(self,**kwargs):
parent.__init__(self,**kwargs)
def test_func(self):
print 'When local =true'
return self.name
class child2(parent):
def __init__(self,**kwargs):
parent.__init__(self,**kwargs)
def test_func(self):
print ("When local =False")
return self.ip
class child3(parent,child1,child2):
def __init__(self, **kwargs):
parent.__init__(self, **kwargs)
There is an environment file , where i am initializing the class
from parent import parent
from child2 import child2
from child1 import child1
from parent import child3
server=child3(
ip = '10.20.11.10',
name ='pankaj',
local = False
)
I have a robotfile (Test.robot) which calls the method test_func
*** Settings ***
Library parent.child3 WITH NAME wireshark_test
*** Variables ***
*** Test Cases ***
This is first
Invoking methods
*** Keywords ***
Invoking methods
log to console wireshark_test.test_func
i am executing this via command
pybot -V envSI.py Test.robot
I am always getting test_func of child1 class
Expectation:
When local=True test_func of child1 class Else test_func of child2 class
Could anyone please guide me how can i do this?
Upvotes: 3
Views: 187
Reputation: 6971
Building on the above answer by @todor. What I observed was that there was no logic determine how to instantiate the right class. Normally this logic would reside in some factory class but assuming there is a simple logic for determining the class then the following example will allow you to do what you want using dynamic class names.
robot_suite.robot
*** Test Cases ***
TC - false
Import Library child3
... ip=10.20.11.10
... name=pankaj
... local=false
... WITH NAME i_false
${result} i_false.Test Func
Should Be Equal As Strings ${result} 10.20.11.10
TC - true
Import Library child3
... ip=10.20.11.10
... name=pankaj
... local=true
... WITH NAME i_true
${result} i_true.Test Func
Should Be Equal As Strings ${result} pankaj
As the instantiation of a library can only be done once, I'm using the WITH NAME
construct to load the same lib twice.
child3.py
class child3(object):
def __init__(self, **kwargs):
self.child = globals()["child_" + kwargs.get('local', 'true')](**kwargs)
def get_keyword_names(self):
return ['test func']
def run_keyword(self, name, args):
return getattr(self.child, name.lower().replace(' ', '_'))()
class parent:
def __init__(self, **kwargs):
self.ip = kwargs.get('ip', 'Default')
self.name = kwargs.get('name', 'Default')
self.local = kwargs.get('local', 'Default')
class child_true(parent):
def __init__(self,**kwargs):
parent.__init__(self,**kwargs)
def test_func(self):
return self.name
class child_false(parent):
def __init__(self,**kwargs):
parent.__init__(self,**kwargs)
def test_func(self):
return self.ip
Upvotes: 2
Reputation: 20067
I am always getting test_func of child1 class
That is so because of the Method Resolution Order in multiple inheritance in python; another read is https://www.python.org/download/releases/2.3/mro/ (don't mind the old version in the url).
In short, when there's a multiple inheritance - like in your example, class child3(parent,child1,child2)
, when there's an access to an attribute python will look in the parent classes from left to right, until a match is found (and raise an exception, if there isn't such).
When you called test_func()
, the resolution started from "parent" - not found, then went to "child1" - and as it has this method, it got picked and executed. And thus for objects created from "child3", it's always going to be the implementation in "child1".
Can you change the MRO? Hardly (and, you really don't want to do that, if you are not 101% certain what you're doing). You can change the inheritance patterns of the class; or you can have different classes objects - "child1" and "child2", and call the corresponding one depending on your condition.
Upvotes: 3