Inherit instance variable from parent class - python-3.x

main.py
...
person = cPerson("xyz", "ozp")
...
person.set_name("somename")
...
csystem = cSystem()
...
cperson.py
class cPerson:
def __init__(self, addr, client):
self.addr = addr
self.client = client
self.name = None
def set_name(self, name):
self.name = name
csystem.py
from cperson import cPerson
class cSystem(cPerson):
def __init__(self):
print(self.name)
Can i access self.name from the parent class in this way? I get the error message:
AttributeError: 'cSystem' object has no attribute 'name'
I do not want to initialize from the csystem class, i want the current value from the instance variable set as shown in the main program.

I am not entirely sure what you want the end result to be.
In any case is this what you are looking for?
class cPerson:
name = None
def __init__(self, addr, client):
self.addr = addr
self.client = client
#classmethod
def set_name(cls, value):
cls.name = value
class cSystem(cPerson):
def __init__(self, addr, client):
super().__init__(addr, client)
print(self.name)
person = cPerson("xyz", "ozp")
person.set_name('Jake')
csystem = cSystem("xyz", "ozp")
The above code returns 'Jake'.
A class method is a method which is bound to the class and not the object of the class. They have the access to the state of the class as it takes a class parameter that points to the class and not the object instance.
Is this what you were looking for? If not can you explain the problem in a bit more detail?

Related

Multiple inheritance, super() and their correct use with arguments in Python

I'm trying to understand multiple inheritance in python. I think that "kinda" got it, but I'm missing a few pieces. I know that if I have two clases I can do something like:
class A():
def __init__(self,name):
self.name = name
class B(A):
def __init__(self,name):
A.__init__(self,name)
self.mm = False
self.name = name
b = B("Peter")
My problem is when I have more classes and each class has their own init arguments. At first glance, it makes like no sense to have something like this:
class A():
def __init__(self,name,arg_a1,arg_a2):
self.name = name
class B(A):
def __init__(self,name,arg_b1,arg_b2,arg_a1,arg_a2...):
A.__init__(self,name,arg_a1,arg_a2...)
self.mm = False
self.name = name
class C(B):
def __init__(self,name,arg_c1,arg_c2,arg_b1,arg_b2,arg_a1,arg_a2.........):
B.__init__(self,name,arg_b1,arg_b2,arg_a1,arg_a2...)
self.name = name
So I started to look how to do it in an efficient way and not just hardcode it. Thats when I came across with multiple inheritance and thats when my doubts started to arraise.
If I have 3 classes:
class A():
def __init__(self,name):
self.name = name
class B(A):
def __init__(self,name,*args,**kwargs):
super().__init__(*args,**kwargs)
self.mm = False
self.name = name
class C(B):
def __init__(self,a,j,*args,**kwargs):
super().__init__(*args,**kwargs)
self.a = a
self.j = j
c = C("p",1,5,name="p")
Why this give an error but adding name as an init argument does not?
In this other example, if I add another argument to A init's function the I get TypeError: __init__() got multiple values for argument 'name'.
class A():
def __init__(self,name,lastname):
self.name = name
self.lastname = lastname
class B(A):
def __init__(self,name,*args,**kwargs):
super().__init__(name,*args,**kwargs)
self.mm = False
self.name = name
class C(B):
def __init__(self,a,j,*args,**kwargs):
super().__init__(*args,**kwargs)
self.a = a
self.j = j
c = C("p",1,5,name="p")
So, after all this, several questions comes to my mind.
Why this TypeError is generated?
How can I make inheritance "smart"?
Do I always need to use *args and **kwargs with multiple inheritance?
And all this gets me to the point to the libraries I use daily. Probably some of them use this concetps (I don't know, I'm assuming). What happes when the user puts a kwarg that is not present in any class? How do python "knows" that name goes in class A and not class B or viceversa?

How to share the parent class variables to third class through the child class in python?

I have the following code:
class Parent():
def __init__(self):
self.variable1 = self.method1()
self.variable2 = self.method2()
self.variable3 = self.method3()
self.variable4 = self.method4()
#.........(for example I have 100 variables here)
def method1(self):
return 100
def method2(self):
return 200
def method3(self):
return 300
def method4(self):
return 400
class Third():
def __init__(self):
a = 1
def call(self):
value = self.variable3 + 1
return value
class Child(Parent):
def __init__(self):
super().__init__()
self.getanswer = self.method11()
def method11(self):
value_count = Third().call()
return value_count
obj = Child()
It throwed the following Error:
AttributeError: 'Third' object has no attribute 'variable3'
Here I wanted to send all the values of parent to Third Class through Child class. How can I achieve it? I know that I can pass Parent class variables seperately in directly as a parameter in the class Third as following:
value_count = Third(self.variable3).call()
and change the Third Class constructor accordingly. But I don't want to do it as my Parent class has some time taking operations to do.
Also I don't want to make class Third as child to the class Parent.
So How can I recognize the Parent class variables(variable1, variable2, variable3, variable4, ....) in Third Class through Child Class ?

How to extend base class to child class in python and printing child class value?

when i try to extend base class to child class it doesn't work properly
it shows error
b1 = B("adnan", 25, "male")
TypeError: object() takes no parameters
here is my code :
class A:
def letter(self,name,age):
self.name=name
self.age=age
class B(A):
def farhan(self,gender):
self.gender=gender
b1=B("adnan",25,"male")
print(b1.name,b1.age,b1.gender)
None of your classes have an __init__ method, which is used to initialise the class. When you do: B("adnan",25,"male"), it's translated to a call to B.__init__:
B.__init__(<object of type B>, "adnan", 25, "male")
The default implementation of __init__ supplied by the class object takes no parameters, which is exactly what the error is saying. A inherits from object (issubclass(B, object) == True), so its default __init__ method is the same as that of object.
You can try this:
class A:
def __init__(self, name, age):
self.name=name
self.age=age
class B(A):
def __init__(self, name, age, gender):
super().__init__(name, age) # initialise parent
self.gender = gender
When you write something like
b1 = B("adnan", 25, "male")
You are creating a new instance of the class 'B'. When you do that, you're calling the __init__ method of that class. A possible solution would be in the lines of:
class B(A):
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
You need to brush up your Python OOP skills! A nice source is https://realpython.com/python3-object-oriented-programming/

OOP Casting class member to another class

I have parent class Ad with 2 children Direct and Adword. On the other side I have parent class Campaign with 2 children DirectCampaign and AdwordsCampaign. Campaign class contains array of corresponding Ad children instances.
class Ad:
def __init__(self, keyword, negative_keywords, url):
self.keyword = keyword
self.negative_keywords = negative_keywords
self.url = url
class Direct(Ad):
def __init__(self, keyword, negative_keywords, headline, description, url):
super().__init__(keyword, negative_keywords, url)
self.url_with_utm = url + "?"
class Adword(Ad):
def __init__(self, keyword, negative_keywords, headline1, headline2, description, url):
super().__init__(keyword, negative_keywords, url)
class Campaign():
ads = []
def __init__(self, name):
self.name = name
def add(self, ad):
self.ads.append(ad)
class DirectCampaign(Campaign):
def __init__(self, name):
super().__init__(name)
class AdwordsCampaign(Campaign):
pass
def main():
direct = DirectCampaign("adv_search")
direct.import_from_csv('direct.csv')
My primary goal is to cast DirectCampaign to AdwordsCampaign, but I cannot understand how to do it according to OOP(what class should have such method, should I call AdwordsCampaign constructor there and Adwords constructor after).
Secondary goal is DirectCampain has name attribute, how I can access it in Direct instance? Should I pass it through constructor to every Direct instance?
Any feedback for the code is welcome.

dynamic class inheritance using super

I'm trying to dynamically create a class using type() and assign an __init__ constructor which calls super().__init__(...); however, when super() gets called I receive the following error:
TypeError: super(type, obj): obj must be an instance or subtype of type
Here is my code:
class Item():
def __init__(self, name, description, cost, **kwargs):
self.name = name
self.description = description
self.cost = cost
self.kwargs = kwargs
class ItemBase(Item):
def __init__(self, name, description, cost):
super().__init__(name, description, cost)
def __constructor__(self, n, d, c):
super().__init__(name=n, description=d, cost=c)
item = type('Item1', (ItemBase,), {'__init__':__constructor__})
item_instance = item('MyName', 'MyDescription', 'MyCost')
Why is super() inside the __constructor__ method not understanding the object parameter; and how do I fix it?
Solution 1: Using cls = type('ClassName', ...)
Note the solution of sadmicrowave creates an infinite loop if the dynamically-created class gets inherited as self.__class__ will correspond to the child class.
An alternative way which do not have this issue is to assigns __init__ after creating the class, such as the class can be linked explicitly through closure. Example:
# Base class
class A():
def __init__(self):
print('A')
# Dynamically created class
B = type('B', (A,), {})
def __init__(self):
print('B')
super(B, self).__init__()
B.__init__ = __init__
# Child class
class C(B):
def __init__(self):
print('C')
super().__init__()
C() # print C, B, A
Solution 2: Using MyClass.__name__ = 'ClassName'
An alternative way to dynamically create class is to define a class inside the function, then reassign the __name__ and __qualname__ attributes:
class A:
def __init__(self):
print(A.__name__)
def make_class(name, base):
class Child(base):
def __init__(self):
print(Child.__name__)
super().__init__()
Child.__name__ = name
Child.__qualname__ = name
return Child
B = make_class('B', A)
class C(B):
def __init__(self):
print(C.__name__)
super().__init__()
C() # Display C B A
Here is how I solved the issue. I reference the type() method to dynamically instantiate a class with variable references as such:
def __constructor__(self, n, d, c, h):
# initialize super of class type
super(self.__class__, self).__init__(name=n, description=d, cost=c, hp=h)
# create the object class dynamically, utilizing __constructor__ for __init__ method
item = type(item_name, (eval("{}.{}".format(name,row[1].value)),), {'__init__':__constructor__})
# add new object to the global _objects object to be used throughout the world
self._objects[ item_name ] = item(row[0].value, row[2].value, row[3].value, row[4].value)
There may be a better way to accomplish this, but I needed a fix and this is what I came up with... use it if you can.

Resources