Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parent constructor called by default?

I have the following example from python page_object docs:

 from page_objects import PageObject, PageElement
 from selenium import webdriver

 class LoginPage(PageObject):
        username = PageElement(id_='username')
        password = PageElement(name='password')
        login = PageElement(css='input[type="submit"]')

 driver = webdriver.PhantomJS()
 driver.get("http://example.com")
 page = LoginPage(driver)
 page.username = 'secret'
 page.password = 'squirrel'
 assert page.username.text == 'secret'
 page.login.click()

What bothers me is that we create a LoginPage with providing a driver to it's constructor, but we haven't define a __init__ method in LoginPage class.

Does that mean that the parent class PageObject's constructor is called with driver parameter? I thought that python doesn't implicitly call parent's constructors?

like image 744
CuriousGuy Avatar asked Oct 22 '25 21:10

CuriousGuy


1 Answers

The __init__ method is just a method and as such python performs the same kind of lookup for it as other methods. If class B does not define a method/attribute x then python looks up it's base class A and so on, until it either finds the attribute/method or fails.

A simple example:

>>> class A:
...     def method(self):
...         print('A')
... 
>>> class B(A): pass
... 
>>> class C(B):
...     def method(self):
...         print('C')
... 
>>> a = A()
>>> b = B()
>>> c = C()
>>> a.method()
A
>>> b.method()  # doesn't find B.method, and so uses A.method
A
>>> c.method()
C

The same is with __init__: since LoginPage does not define __init__ python looks up the PageObject class and finds its definition there.

What is meant when we say that "python doesn't implicitly call parent class constructors" is that if you define an __init__ method the interpreter will just call that method and not call all the parent class __init__s, and as such if you want to call the parent class constructor you have to do so explicitly.

Note the difference among these classes:

>>> class A:
...     def __init__(self):
...         print('A')
... 
>>> class B(A):
...     pass
... 
>>> class B2(A):
...     def __init__(self):
...         print('B')
... 
>>> class B3(A):
...     def __init__(self):
...         print('B3')
...         super().__init__()
... 
>>> A()
A
<__main__.A object at 0x7f5193267eb8>
>>> B()  # B.__init__ does not exists, uses A.__init__
A
<__main__.B object at 0x7f5193267ef0>
>>> B2()  # B2.__init__ exists, no call to A.__init__
B
<__main__.B2 object at 0x7f5193267eb8>
>>> B3()  # B3.__init__exists, and calls to A.__init__ too
B3
A
<__main__.B3 object at 0x7f5193267ef0>
like image 137
Bakuriu Avatar answered Oct 25 '25 12:10

Bakuriu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!