Python class inheritance __init__ - python

So, here's the problem..
if you do this:
class x(object):
def __init__(self):
pass
why would you explicitly call init in child class to access parent class attribute? (class y has class x attribute anyway.)
class y(x):
def __init__(self):
x.__init__(self)
Cheers.
Edit:
I read this article https://linuxmeerkat.wordpress.com/2015/04/28/why-you-should-use-super-in-python/, it says "In real life we tend to run the initializer for every parent class. This is simply because of how program designs tend to be. In our simple example a way to solve this is to explicitly call the initializer of A:" Could someone please explain?

The fact is that in python there is a clear distinction between class and instance attributes:
Attributes declared in the class body, outside any method, are class attributes, they are the same for each object of that class and are the ones that are inherited by the subclasses. Be aware of the fact that doing instance_obj.class_att = something doesn't change the value of the class attribute, but simply creates an instance attribute and hides the shared class attribute for that object.
Instance attributes are the ones that are declared with syntax instance_obj.att = something, they are not shared between instances and are the most similar thing to non-static attributes that you have in other programming languages and they are usually created in the init method.self is just a convention to indicate the instance object automatically passed to methods.
Here's an example:
class MyClass:
c = 1 #class attribute, the subclasses will inherit this
def __init__(self):
self.i = 1 #instance attribute
MyClass.c #access attribute c of class MyClass
MyClass.i #error! MyClass has no attribute i
x = MyClass() #calling __init__ creates instance attribute i for obj x
x.i #access instance attribute i of object x
x.c #access class attribute c of class MyClass
x.c = 2 #hide MyClass.c and create instance attribute c for obj x
x.c #access instance attribute c of obj x
So, to sum up, doing:
class y(x):
def __init__(self):
x.__init__(self)
is useful because if the base class would have been something like this
class x:
def __init__(self):
self.i=1
you would have not been able to access the attribute i from any instances of y simply because they would not have it.

Instead of calling to the init function explicitly, you should use the super() method instead.
In python 3.0+, you can jusy use:
class y(x):
def __init__(self):
super().__init__()
In python 2.7 or under, use:
class y(x):
def __init__(self):
super(self.__class__, self).__init__()
super() lets you avoid referring to the base class explicitly.

Because the child class inherits from the parent class, of course, that means everything: methods, attributes and the constructor.
So instead of rewrite all the __init__ code, you just use what is already written in the parent class.
Hope it makes sense to you.

Related

How do I access an attribute from a parent class in Python?

This doesn't work:
class parent:
a=1
class child:
b=a+1
nor does
class parent:
a=1
class child:
b=parent.a+1
nor does
class parent:
a=1
class child:
b=self.a+1
nor does
class parent:
a=1
class child:
b=super().a+1
What do I do? I've heard that Stack Overflow can be quite toxic, but I'm hoping it's not true. Please understand that I'm new here.
Your question does not reflect properly in your code. As per inheritance of classes you inherit from a parent class. But in your code you are trying to call outerclass from an inner class.
One solution might be like this (According to your question):
class Parent:
a = 1
class Child(Parent):
b = Parent.a + 1
parent = Parent()
child = Child()
print(parent.a) # output: 1
print(child.b) # output: 2
But if you really want to access outer class from inner class then you can visitHow to access outer class from an inner class? (according to your code)
class Parent():
def __init__(self):
self.a = 1
class Child(Parent):
def __init__(self):
Parent.__init__(self)
self.b = self.a +1
child_class = Child()
print(child_class.b)
Maybe something like this.
The proper way to create a child class is like this:
class parent():
a = 1
# child class inherits attributes from parent like this
class child(parent):
b = 2
# so when you instantiate an object of class child...
child_object = child()
# ... you can access its parent's attributes directly like this:
print(child_object.a + child_object.b)
If you want to access the parent's attribute inside a method, you can do like this:
class child(parent):
b = 2
def sum_with_parent(self):
# you can either use self.a to access the parent attribute,
# since 'class child(parent):' made the proper inheritance
sum1 = self.b + self.a
# or you can use the super().a, but bear in mind that 'super()'
# is actually creating a fresh instance of parent
# that is, it's calling __init__ from parent
sum2 = self.b + super().a
return sum1 == sum2 #this will return true
Welcome to Stack Overflow. It seems like you don’t quite understand what inheritance is. Here is a quick “deep” dive.
What is inheritance in OOP?
Inheritance is a fundamental concept in object oriented programming. It is when you provide a base or super class for another class. The super class usually contains functionality that will apply, or be useful, to any instance of the classes deriving from it. It prevents you from having to reimplement things.
Inheritance in Python
In Python, a class deriving from another class automatically is able to access methods and attributes defined in super class, through the super() function:
class Foo:
def bar(self):
print("bar")
class Bar(Foo):
def bar(self):
super().bar()
b = Bar()
b.bar() # bar
Even if we use the convention for showing some method or attribute is private, which is prefixing with an underscore, Python doesn’t enforce this and we can still access it:
class Foo:
def _bar(self):
print("bar")
class Bar(Foo):
def bar(self):
super()._bar()
b = Bar()
b.bar() # bar
Inheritance in Other OO Languages
In other object oriented languages like C#, there are access modifiers. Marking a method with public means it has no restrictions to what can access it. It can be accessed by:
All code in the assembly it was defined in
All code in any assemblies referencing the assembly where it was defined
But, C# gives us the option to multiple other access modifiers, including private. Marking something as prívate means it can only be accessed by the code in the same class, or struct, it was defined in:
class Foo
{
private string _x = "Foo";
}
static void Main()
{
var foo = new Foo();
Console.WriteLine(foo._x); // compile time error
}
But, restricted members can be indirectly accessed through a public API:
class Foo
{
private string _x = "Foo";
public string AccessPrivate()
{
return _x;
}
}
static void Main()
{
var foo = new Foo();
Console.WriteLine(foo.AccessPrivate());
}
Python’s super() function
mCoding on YouTube has a great video explaining how super() works
Simply, super() will give you access to methods in a superclass, from subclasses that inherit from it. Calling it actually returns a temporary object of the superclass, letting you access its methods and attributes.
The official Python documentation on super() says:
Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class.
Single inheritance with super()
super() is relatively simple with single inheritance, as shown in the Inheritance in Python section.
You commonly see it used in the __init__ method for calling the superclass’s initializer with arguments supplied by the initializer of the subclass:
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
class Square(Rectangle):
def __init__(self, length):
super().__init__(length, length)
We define a class Rectangle whose initializer takes a length and width parameter. The length and width of a rectangle will be different. Next, we define a class Square, deriving from Rectangle. This makes sense because all squares are rectangles. Rectangles are not squares though because they don’t have equal length sides, but a square’s dimensions will always be the same. We pass length to Square’s __init__. This length parameter is then passed to the constructor of the superclass as the argument for both length and width.
super() is also good for extending the functionality of an inherited method.
I hope this message helped explain a bit on what inheritance is and accessing attributes/methods from the parent class, in the subclass.

correct way of extending a class in python

I am given a designated factory of A-type objects. I would like to make a new version of A-type objects that also have the methods in a Mixin class. For reasons that are too long to explain here, I can't use class A(Mixin), I have to use the A_factory. Below I try to give a bare bones example.
I thought naively that it would be sufficient to inherit from Mixin to endow A-type objects with the mixin methods, but the attempts below don't work:
class A: pass
class A_factory:
def __new__(self):
return A()
class Mixin:
def method(self):
print('aha!')
class A_v2(Mixin): # attempt 1
def __new__(cls):
return A_factory()
class A_v3(Mixin): # attempt 2
def __new__(cls):
self = A_factory()
super().__init__(self)
return self
In fact A_v2().method() and A_v3().method() raises AttributeError: 'A' object has no attribute 'method'.
What is the correct way of using A_factory within class A_vn(Mixin) so that A-type objects created by the factory inherit the mixin methods?
There's no obvious reason why you should need __new__ for what you're showing here. There's a nice discussion here on the subject: Why is __init__() always called after __new__()?
If you try the below it should work:
class Mixin:
def method(self):
print('aha!')
class A(Mixin):
def __init__(self):
super().__init__()
test = A()
test.method()
If you need to use a factory method, it should be a function rather than a class. There's a very good discussion of how to use factory methods here: https://realpython.com/factory-method-python/

Use class instance as parent class in python

I'm trying to get a better understanding of python class system. This question is intended only to satisfy my curiosity.
Is it possible to use somehow a class instance as a parent class for another class. So far what I tried to do is
class A:
pass
a = A()
class B(a):
pass
and it gives following error: TypeError: object() takes no parameters
class Meta(type):
pass
class A:
pass
a = A()
class B(a, metaclass=Meta):
pass
and it gives this error TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I'm wondering, is it possible to somehow proxy all of the class instance methods to metaclass, so my instance would behave as a class
Is it possible to use somehow a class instance as a parent class for another class
Well, actually that's always the case since classes ARE instances (of their metaclass). But then the class of the instance you want to use as a parent class (yeah, re-read it thrice...) must behave as if it was a genuine metaclass - which can rapidily become impractical.
I'm wondering, is it possible to somehow proxy all of the class instance methods to metaclass, so my instance would behave as a class
There might be a way indeed (overriding __getattr__() or __getattribute__()), but devil is in the details and chances are that by the time you make this rube goldberg contraption "kind-of-work-with-severe-limitations-and-corner-cases", you will wonder if that was really worth the pain.
Note that OTHO both composition/delegation and dynamic (runtime) creation / modification of classes is absurdly easy in Python so I can hardly think of a problem that would be better solved by (ab)using an instance as a parent class.
Every instance has a __class__ attribute that refers to the underlying class structure.
Knowing this, you can actually do the following:
class A(object):
def foo(self):
return 'hello'
a = A()
class B(a.__class__):
pass
b = B()
print(b.foo()) # Prints 'hello'
Alternatively, you can also use type:
class B(type(a)):
pass
b = B()
print(b.foo()) # Prints 'hello'
Your instance needs to be a type in order to be used in inheritance chains. For example:
class A(type):
pass
a = A(str) # you need to pass the type's `type` to the construcor
class B(a):
pass
That being said, there's little, if no practical application for this that I can think of - or rather whatever you achieve this way will be easier and more Pythonic to achieve through normal inheritance and metaclasses.
EDIT:
OK, so it is possible to hack if you have control over the base class (either using metaclasses or __init_subclass__ (python 3.6 or later))
class A:
x = 1
def __init_subclass__(cls, inst, **kwargs):
super().__init_subclass__(**kwargs)
for k, v in vars(inst).items():
if k not in dir(cls): # i.e. don't override but remove if you want to
setattr(cls, k, v)
a = A()
a.y = 2
class B(A, inst=a):
pass
B.x # --> 1
B.y # --> 2
You're sort of on the right tracks with your second example. Yes it is possible.
class Meta(type): pass
class A(metaclass=Meta): pass
class B(A): pass
issubclass(B, A) # --> True
isinstance(B, Meta) # --> True
Thats because A is an instance of Meta (thats what a metaclass means, a class whose instance is also a class). Hence B is a subclass of an instance of Meta.
So yes, you could set for example
class Meta(type):
def __init__(cls, *args, **kwargs):
cls.x = 1
super().__init__(cls, *args, **kwargs)
class A(Meta):
def __init__(self):
self.y = 2
A.x # 1 (acts as an instance of Meta)
a = A()
a.y # 2 (acts as an instance of A)
a.x # AttributeError (does not act as an instance of Meta)

Class variable access in all class method

I want to have a class variable, so that the value can be access in all instances, but I also want to access the variable in methods inside the class. Is that possible? I have tried this, but it didn't work at all.
class myClass:
myvariable = 1
def add():
myvariable+= 1
def print1():
print myvariable
I want to make two instances, one only do add method, the other only do print1 method
Yes, just access the variable on the class object:
class myClass(object):
myvariable = 1
def add(self):
myClass.myvariable += 1
def print1(self):
print myClass.myvariable
or if you want to set it per sub-class, use type(self):
class myClass(object):
myvariable = 1
def add(self):
type(self).myvariable += 1
def print1(self):
print type(self).myvariable
The difference is that the latter will create a separate attribute on any subclass when set, masking the base class attribute. This is just like setting an attribute on an instance would mask the class attribute.
Although you can get the class attribute via self as well (print self.myvariable), explicit is better than implicit here, and avoids accidentally being masked by an instance attribute of the same name. Setting class attributes always has to be done on the class; setting it on self would create or update an instance attribute instead (not shared).
Do inherit your classes from object though; using new-style classes has many advantages, not in the least that type(self) will then actually return the class. In old-style classes (not inheriting from object) you'd have to use self.__class__ instead.
Using object as a base also gives you a third option, class methods with the #classmethod decorator; use these when you only need to access the class object, not the instance. These methods are bound to the current (sub)class, so their effect on class attributes is the same as using type(self):
class myClass(object):
myvariable = 1
#classmethod
def add(cls):
cls.myvariable += 1
#classmethod
def print1(cls):
print cls.myvariable

Python: inheritance of class data (if superclass object has been already initialized)

I faced with an inability of the inheritance of superclass attribute values. I have already called superclass constructor and now trying to check out the inherited values.
class base:
def __init__(self, x):
self.x = x
print(self.x)
class derive(base):
def __init__(self):
print(self.x + 1)
print("base class: ")
b = base(1) <-- Creating superclass instance
print("derive class: ")
d = derived() <-- Inheriting. Failure.
Why can't I do this? Should I pass the underlying object to the inheriting object explicitly in order to get x attribute?
b and d are not related; b is entirely a separate instance of the base class.
If you want to invoke the overridden initializer (__init__), then use the super() proxy object to access it:
class derive(base):
def __init__(self):
super().__init__(1)
print(self.x + 1)
Note that you still need to pass in an argument to the initializer of the parent class. In the above example, I pass in a constant value 1 for the x parameter of the parent initializer.
Note that I used Python 3 specific syntax here; super() without arguments won't work in Python 2, where you also need to use object as a parent for the base class to make it a new-style class.

Categories