Parent class init is executing during inheritence - python

One basic question in OOP.
test.py file content:
class test(object):
def __init__(self):
print 'INIT of test class'
obj = test()
Then I opened another file.
I just inherited from the above test class:
from test import test
class test1(test):
def __init__(self):
pass
So when I run this second file, the __init__() from the parent class is executed (the INIT got printed).
I read that I can avoid it by using
if __name__ == '__main__':
# ...
I can overcome this, but my question is why the parent class's init is executing as I am just importing this class only in my second file. Why is the object creation code executed?

Importing a module executes all module-level statements, including obj=test().
To avoid this, make an instance only when run as the main program, not when imported:
class test(object):
def __init__(self):
print 'INIT of test class'
if __name__ == '__main__':
obj=test()
The problem is not the inheritance but the import. In your case you execute obj=test() when importing:
from test import test
When you import test, its name __name__ is test.
But when you run your program on the command line as main program with python test.py, its name is __main__. So, in the import case, you skip obj=test()if you use:
if __name__ == '__main__':
obj=test()

Related

Print function prints twice a field from a class

I am using the print function to print a field from a class from another python module and it prints the field twice.
I have two modules:
main.py:
from statics import RiskyCars
class Car:
def __init__(self, name):
self.name = name
# init
RiskyCars()
print(RiskyCars.risky_cars[0].name)
statics.py:
class RiskyCars:
#staticmethod
def __init__():
from main import Car
RiskyCars.risky_cars = []
RiskyCars.risky_cars.append(Car("car1"))
When I run main.py it print twice:
C:\Python27\python.exe C:/Users/myuser/PycharmProjects/Project1/main.py
car1
car1
But if I put breakpoint before the print function:
# main.py
# init
RiskyCars() <--- break point
and then run manually from the terminal:
print(RiskyCars.risky_cars[0].name)
it prints only one time.
Why it happens ?
Python renames the primary script you run main for you as __main__. What happens is that you run main (called __main__) which runs RiskyCars.__init__ which in turn imports main (called main). Hence the script main runs twice.
The solution is to rewrite main.py to be
from statics import RiskyCars
if __name__ == '__main__': # only execute if run as main script
# init
risky_car_1 = RiskyCars() # lets at least pretend this is sensible
print(RiskyCars.risky_cars[0].name)
statics.py to
from cars import Car
class RiskyCars:
risky_cars = []
def __init__(self):
RiskyCars.risky_cars.append(Car("car1"))
and make a new file called cars.py
class Car:
def __init__(self, name):
self.name = name

Constructor gets called twice when dynamically instantiating class

I am using importlib & getattr to dynamically create an instance of a class. But, when i run Proxy.py that is provided below, the constructor gets called twice and i get duplicate results. Thanks in advance. (Python 3.6.1)
Result
inside Cproxy contructor
inside Cproxy read()
inside Cproxy contructor
inside Cproxy read()
Runner.py
import importlib
class Crunner:
def __init__(self, nameofmodule, nameofclass):
self.run(nameofmodule, nameofclass)
def run(self, nameofmodule, nameofclass):
module = importlib.import_module(nameofmodule)
class_ = getattr(module, nameofclass)
instance = class_()
instance.read()
Proxy.py
from Runner import Crunner
class Cproxy:
def __init__(self):
print("inside Cproxy contructor")
def read():
print("inside Cproxy read()")
Crunner("Proxy", "Cproxy")
Your proxy module is imported twice - once as __main__ (when you run python Proxy.py) and once as Proxy (when it's imported by Crunner).
The solution is simple: guard the call to Crunner() so it's only executed when Proxy is used as script:
if __name__ == "__main__":
Crunner("Proxy", "Cproxy")

Is it possible to invoke the main method of a test class through pytest?

I have a test class test_enrollment.py that defines a set of tests, and has a main method which uses a generator to generate a new custom test class. In a simpler form, it looks like:
import json
import unittest
import front_end_tests.generator
class EnrollmentTests(unittest.TestCase):
def test_new_student_registration(self):
# test definition here
if __name__ == '__main__':
front_end_tests.generator.generate_and_run_tests(EnrollmentTests)
The way I normally run this test class is by calling python test_enrollment.py. If I wanted to run this same test file with pytest instead, is there a way to call the file in a way where the main method still gets called?
I thought you can`t.
To solve this problem, you just need to move
front_end_tests.generator.generate_and_run_tests(EnrollmentTests)
To
def setUpModule():
front_end_tests.generator.generate_and_run_tests(EnrollmentTests)
test_enrollment.py look like this:
import json
import unittest
import front_end_tests.generator
def setUpModule():
front_end_tests.generator.generate_and_run_tests(EnrollmentTests)
class EnrollmentTests(unittest.TestCase):
def test_new_student_registration(self):
# test definition here
pass
if __name__ == '__main__':
unittest.main()
and just type:
pytest

How do I execute a module's code from another?

I know it's a greenhorn question. But. I have a very simple module that contains a class, and I want to call the module to run from another. Like so:
#module a, to be imported
import statements
if __name__ == '__main__':
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
do stuff involving 'a1' when called from another module
#Module that I'll run, that imports and uses 'a':
if __name__ == '__main__':
import a
a.run_proc()
However, for reasons that are likely obvious to others, I get the error Attribute Error: 'Module' object has no attribute 'run_proc' Do I need a static method for this class, or to have my run_proc() method within a class, that I initialize an instance of?
Move the
if __name__ == '__main__':
in module a to the end of the file and add pass or some test code.
Your problems are that:
Any thing in the scope of if __name__ == '__main__': is only considered in the top level file.
You are defining a class but not creating a class instance.
module a, to be imported
import statements
class a1:
def __init__(self, stuff):
do stuff
def run_proc():
#do stuff involving 'a1' when called from another module
if __name__ == '__main__':
pass # Replace with test code!
Module that I'll run, that imports and uses 'a':
import a
def do_a():
A = a.a1() # Create an instance
A.run_proc() # Use it
if __name__ == '__main__':
do_a()

How does name resolution work when classes are derived across modules?

Classes B and C both derive from base class A, and neither override A's method test(). B is defined in the same module as A; C is defined in a separate module. How is it that calling B.test() prints "hello", but calling C.test() fails? Shouldn't either invocation end up executing A.test() and therefore be able to resolve the symbol "message" in mod1's namespace?
I'd also gratefully receive hints on where this behaviour is documented as I've been unable to turn up anything. How are names resolved when C.test() is called, and can "message" be injected into one of the namespaces somehow?
FWIW, the reason I haven't used an instance variable (e.g. set A.message = "hello") is because I'm wanting to access a "global" singleton object and don't want to have an explicit referent to it in every other object.
mod1.py:
import mod2
class A(object):
def test(self):
print message
class B(A):
pass
if __name__ == "__main__":
message = "hello"
A().test()
B().test()
mod2.C().test()
mod2.py:
import mod1
class C(mod1.A):
pass
output is:
$ python mod1.py
hello
hello
Traceback (most recent call last):
File "mod1.py", line 14, in <module>
mod2.C().test()
File "mod1.py", line 5, in test
print message
NameError: global name 'message' is not defined
Many thanks!
EOL is correct, moving the "main" part of the program into a new file mod3.py does indeed make things work.
http://bytebaker.com/2008/07/30/python-namespaces/ further clarifies the issue.
In my original question, it turns out that the variable message ist stored in the __main__ module namespace because mod1.py is being run as a script. mod2 imports mod1, but it gets a separate mod1 namespace, where the variable message does not exist. The following code snippet demonstrates more clearly as it writes message into mod1's namespace (not that I'd recommend this be done in real life), causing the expected behaviour.
import sys
class A(object):
def test(self):
print message
class B(A):
pass
if __name__ == "__main__":
import mod2
message = "hello"
sys.modules["mod1"].message = message
A().test()
B().test()
mod2.C().test()
I think the best real-world fix is to move the "main" part of the program into a separate module, as EOL implies, or do:
class A(object):
def test(self):
print message
class B(A):
pass
def main():
global message
message = "hello"
A().test()
B().test()
# resolve circular import by importing in local scope
import mod2
mod2.C().test()
if __name__ == "__main__":
# break into mod1 namespace from __main__ namespace
import mod1
mod1.main()
Could you use a class attribute instead of a global? The following works
import mod2
class A(object):
message = "Hello" # Class attribute (not duplicated in instances)
def test(self):
print self.message # Class A attribute can be overridden by subclasses
class B(A):
pass
if __name__ == "__main__":
A().test()
B().test()
mod2.C().test()
Not using globals is cleaner: in the code above, message is explicitly attached to the class it is used in.
That said, I am also very curious as to why the global message is not found by mod2.C().test().
Things work as expected, though, if the cross-importing is removed (no main program in mod1.py, and no import mod2): importing mod1 and mod2 from mod3.py, doing mod1.message = "Hello" there and mod2.C().test() works. I am therefore wondering if the problem is not related to cross-importing…

Categories