I'm facing a standstill here while trying to figure out how to have member classes access data from their parent when they are part of an external module.
Basically, this works (the B class can access is parent's methods like so: A.say_hi(A) ):
class A:
def __init__(self):
print("Initializing parent object...")
self.child = self.B()
class B:
def __init__(self):
print("Initializing child...")
A.say_hi(A)
def say_hi(self):
print("A class says hi")
However, this can get pretty messy if classes start getting extra large, so I have been placing my additional classes in files and importing them inline. The problem with that is I can no longer get the member class to access its parent's members and functions if I try to use 'import B.py' when class B is defined within.
Is there any way to get the original behavior without leaving the member class inside the same file as the parent?
Actually in your example you couldn't access instance of A in your class B. And the code A.say_hi(A) does work however is wrong. This has been said in comments to your question.
Here is how you do that if you want to be able to access parent instance:
Module b:
class B(object):
def __init__(self, parent):
self.parent = parent
def say_hi(self):
print 'Child says hi to his parent %s' % (
self.parent.__class__.__name__
)
self.parent.say_hi()
Module a:
from b import B
class A(object):
def __init__(self):
self.b = B(self)
def say_hi(self):
print 'Parent says hi!'
If you pass the object (a) to the class (b), you can call it directly.
class a():
def __init__(self):
print"Made A"
def test(self):
print ">>A Test"
class b():
def __init__(self,parent):
print"Made B"
self.parent = parent
def test(self):
print ">>B Test"
self.parent.test()
a = a()
a.test()
b = b(a)
b.test()
Related
I am puzzled with the following error in python 2.7.12
Suppose we have a class definition within a class, something similar to this:
class C(object):
def __init__(self):
print "class C"
class D(object):
def __init__(self):
print "class D"
class A(D):
class B(C):
def __init__(self):
# Strangely here B is "not defined", why?
super(B, self).__init__()
print "class B"
def __init__(self):
super(D, self).__init__()
print "class A"
def do_something(self):
b_class = self.B()
print "b_class within A : {}".format(b_class)
a_class = A()
a_class.do_something()
but if we we extract the definition of class B outside the scope of class A,
everything works well.
Do we need to use "super" differently when called within a nested class? I fail to understand why its usage would be different within or outside the nested class. Any pointers?
The problem is not the subclass or superclass, but the nesting. B itself is not defined, only A.B is.
Note that in Python there is almost never a good reason to nest classes, though.
You need to address B by its full name, A.B:
class C(object):
def __init__(self):
print "class C"
class D(object):
def __init__(self):
print "class D"
class A(D):
class B(C):
def __init__(self):
super(A.B, self).__init__()
print "class B"
def __init__(self):
super(D, self).__init__()
print "class A"
def do_something(self):
b_class = self.B()
print "b_class within A : {}".format(b_class)
>>> a_class = A()
>>> a_class.do_something()
class A
class C
class B
b_class within A : <__main__.B object at 0x7f0cac98cbd0>
I'm working for the first time with OOP in a python project. I have 3 classes: PRA, GDB and XLS.
PRA = Main Class
GDB = Responsible for control databases
XLS = Responsible for control xls(x)
UserInput = Responsible for validate user input
How i'm doing:
PRA:
class PRA(GDB, XLS, UserInput):
__init__():
self.gdb_file, self.xls_file = self.ask_questions() # <--- ask_questions is inside the UserInput class.
self.do_something()
XLS:
class XLS:
do_something():
print(self.xls_file)
__init__(self, xls_file):
self.xls_file = xls_file
GDB:
class GDB:
__init__(self, gdb_file):
self.gdb_file = gdb_file
I would like to know if is a bad practice to initialize the gdb_file and xls_file inside the PRA.init, and if not, how can i run the initialization of self.xls_file and self.xls_gdb only in the PRA?
This is not really an answer, but more of an example of code reuse. I'm not sure if this is super Pythonic, though. Anyhow, take a look at this example:
import inspect
class A:
def __init__(self):
self.a = 1
class B:
def __init__(self):
self.b = 2
class C(A, B):
def __init__(self):
for super_class in inspect.getmro(type(self))[1:]:
super_class.__init__(self)
c = C()
print(c.a, c.b)
A bit OT but you may want to think twice about your class names... They are really terrible.
Now wrt/ your question... Technically, the way to handle proper initialisation of a parent class is to call it's initialiser from the child class, ie:
class Parent(object):
def __init__(self, name):
self.name = name
class Child(Parent):
def __init__(self, name, age):
super(Child, self).__init__(name)
self.age = age
You can also explicitly name the parent class, ie:
class Child(Parent):
def __init__(self, name, age):
Parent.__init__(self, name)
self.age = age
but it has a couple drawbacks, like harcoding the parent class in the call (so you have two or more places to edit if you change the parent class), and, more important, not taking care of proper resolution of the "diamond" problem in multiple inheritance (ie D child of B & C, B child of A, C child of A).
Actually, the only reason to not use super() would be when parent classes constructor are not compatible, but this is a huge design smell - if you have two or more parent classes that are not compatible, then you're certainly not using inheritance the right way. And that's actually the case in your example: your "main" class "is" not a "Database controller", it uses a Database controller instead, so you want to use composition, not inheritance
class ServiceA(object):
# code here
class ServiceB(object):
# code here
class Main(object):
def __init__(self, arg1, arg2, arg3):
self.arg1 = arg1
self.service_a = ServiceA(arg2)
self.service_b = ServiceB(arg3)
def run(self):
something = self.service_a.ask(question)
self.service_b.do_something_with(something)
Also you may want to avoid user interactions and costly resource acquisitions in constructors... Better use an entry point method for the first case (like app = MyApp(params); app.run()`) and lazy initialization for the second case (wait until you need the resource to acquire it, use a private attribute as cache an a public property that will take care of acquisition on first access).
[edit]
Someone suggested a dirty hack based on introspection, ie:
import inspect
class A:
def __init__(self):
self.a = 1
class B:
def __init__(self):
self.b = 2
class C(A, B):
def __init__(self):
for super_class in inspect.getmro(type(self))[1:]:
super_class.__init__(self)
c = C()
print(c.a, c.b)
This is definitly not something to do.
If all your parent classes have compatible constructors and properly use super calls, then all you have to do is using super instead:
class A(object):
def __init__(self):
super(A, self).__init__()
self.a = "a"
class B(object):
def __init__(self):
super(B, self).__init__()
self.b = "b"
class C(A, B):
def __init__(self):
super(C, self).__init__()
self.c = "c"
c = C()
print c.a, c.b, c.c
This also takes care of the "diamond inheritance" problem by calling parent classes in the right order:
class D(C, A):
def __init__(self):
super(D, self).__init__()
self.d = "d"
d = D()
print "d : ", d.a, d.b, d.c, d.d
Note that unless only one of the parent classes is a "proper" class (with state) and all other are mixin classes (stateless classes that only add functionalities), multiple inheritance is more often than not a design smell (as well as a maintainance hell). Since Python doesn't use static typing, inheritance is mostly used for implementation inheritance, and for a lot of cases composition/delegation (or just plain composition as in the OP case) is a better solution than implementation inheritance.
Suppose I have the following class in Python 3:
class CoolCar:
#classmethod
def myWheels(cls):
cls.Wheels().out()
class Wheels:
def __init__(self):
self.s = "I'm round!"
def out(self):
print(self.s)
All well and good. Now I want a derived class:
class TerribleTank(CoolCar):
class Wheels(CoolCar.Wheels):
def __init__(self):
self.s = "I'm square!!"
This works as I would expect:
CoolCar.myWheels()
TerribleTank.myWheels()
But what's bothering me is that I have to write CoolCar twice in the definition of TerribleTank. So I tried this:
class TerribleTank(CoolCar):
class Wheels(super().Wheels):
def __init__(self):
self.s = "I'm square!!"
Which does not work. Now, I know it doesn't work because super() is looking for a first-argument self/cls to begin its search.
So finally my question: Is there something like this that works, so that I don't need to explicitly write that second CoolCar?
What about:
class CoolCar:
#classmethod
def myWheels(cls):
cls.Wheels().out()
class Wheels:
def __init__(self):
self.s = "I'm round!"
def out(self):
print(self.s)
class TerribleTank(CoolCar):
class Wheels(TerribleTank.Wheels):
def __init__(self):
self.s = "I'm square!!"
>>> TerribleTank.myWheels()
I'm square!!
basically when you inherit CoolCar in TerribleTank, you set up TerribleTank.Wheels as a reference to CoolCar.Wheels, until you shadow it with your own new definition of it within the TerribleTank definition. So I believe that matches your expectations of not having CoolCar twice in TerribleBank definition ☺
HTH
Let say I have the following script in modul1:
class IN(object):
def __init__(self):
pass
class C(object):
def __init__(self, x):
pass
def func(self):
cl = IN()
Then I want to use C class inside another script:
from modul1 import C
class IN(object):
def __init__(self):
pass
class C2(C):
def __init__(self, x):
C.__init__(self, x)
I can override C class's func method by creating a method with the same name in C2 class.
But how can I override any call of modul1's IN class inside of imported C class with IN class in the caller modul2?
I want to change some functionality of original IN class. I want C class to call in the row
cl = IN()
my own IN() class with the altered functionality.
module1.py:
class IN(object):
def __init__(self):
print "i am the original IN"
class C(object):
def __init__(self, x):
pass
def func(self):
print "going to create IN from C's func"
cl = IN()
module2.py:
import module1
class IN(object):
def __init__(self):
print "I am the new IN"
class C2(module1.C):
def __init__(self, x):
super(C2, self).__init__(x)
print "\n===Before monkey patching==="
C2(1).func()
#monkey patching old In with new In
module1.IN = IN
print "\n===After monkey patching==="
C2(1).func()
Output while running the script module2.py:
===Before monkey patching===
going to create IN from C's func
i am the original IN
===After monkey patching===
going to create IN from C's func
I am the new IN
You can see how the module2's In constructor is being called.
Is it possible to leave a parent class unspecified until an instance is created?
e.g. something like this:
class SomeParentClass:
# something
class Child(unspecifiedParentClass):
# something
instance = Child(SomeParentClass)
This obviously does not work. But is it possible to do this somehow?
You can change the class of an instance in the class' __init__() method:
class Child(object):
def __init__(self, baseclass):
self.__class__ = type(self.__class__.__name__,
(baseclass, object),
dict(self.__class__.__dict__))
super(self.__class__, self).__init__()
print 'initializing Child instance'
# continue with Child class' initialization...
class SomeParentClass(object):
def __init__(self):
print 'initializing SomeParentClass instance'
def hello(self):
print 'in SomeParentClass.hello()'
c = Child(SomeParentClass)
c.hello()
Output:
initializing SomeParentClass instance
initializing Child instance
in SomeParentClass.hello()
Have you tried something like this?
class SomeParentClass(object):
# ...
pass
def Child(parent):
class Child(parent):
# ...
pass
return Child()
instance = Child(SomeParentClass)
In Python 2.x, also be sure to include object as the parent class's superclass, to use new-style classes.
You can dynamically change base classes at runtime. Such as:
class SomeParentClass:
# something
class Child():
# something
def change_base_clase(base_class):
return type('Child', (base_class, object), dict(Child.__dict__))()
instance = change_base_clase(SomeParentClass)
For example:
class Base_1:
def hello(self):
print('hello_1')
class Base_2:
def hello(self):
print('hello_2')
class Child:pass
def add_base(base):
return type('Child', (base, object), dict(Child.__dict__))()
# if you want change the Child class, just:
def change_base(base):
global Child
Child = type('Child', (base, object), dict(Child.__dict__))
def main():
c1 = add_base(Base_1)
c2 = add_base(Base_2)
c1.hello()
c2.hello()
main()
Result:
hello_1
hello_2
Works well in both python 2 and 3.
For more information, see the related question How to dynamically change base class of instances at runtime?