In Python, consider I have the following code:
class SuperClass(object):
def __init__(self, x):
self.x = x
class SubClass(SuperClass):
def __init__(self, y):
self.y = y
# how do I initialize the SuperClass __init__ here?
How do I initialize the SuperClass __init__ in the subclass? I am following the Python tutorial and it doesn't cover that. When I searched on Google, I found more than one way of doing. What is the standard way of handling this?
Python (until version 3) supports "old-style" and new-style classes. New-style classes are derived from object and are what you are using, and invoke their base class through super(), e.g.
class X(object):
def __init__(self, x):
pass
def doit(self, bar):
pass
class Y(X):
def __init__(self):
super(Y, self).__init__(123)
def doit(self, foo):
return super(Y, self).doit(foo)
Because python knows about old- and new-style classes, there are different ways to invoke a base method, which is why you've found multiple ways of doing so.
For completeness sake, old-style classes call base methods explicitly using the base class, i.e.
def doit(self, foo):
return X.doit(self, foo)
But since you shouldn't be using old-style anymore, I wouldn't care about this too much.
Python 3 only knows about new-style classes (no matter if you derive from object or not).
As of python 3.5.2, you can use:
class C(B):
def method(self, arg):
super().method(arg) # This does the same thing as:
# super(C, self).method(arg)
https://docs.python.org/3/library/functions.html#super
Both
SuperClass.__init__(self, x)
or
super(SubClass,self).__init__( x )
will work (I prefer the 2nd one, as it adheres more to the DRY principle).
See here: http://docs.python.org/reference/datamodel.html#basic-customization
How do I initialize the base (super) class?
class SuperClass(object):
def __init__(self, x):
self.x = x
class SubClass(SuperClass):
def __init__(self, y):
self.y = y
Use a super object to ensure you get the next method (as a bound method) in the method resolution order. In Python 2, you need to pass the class name and self to super to lookup the bound __init__ method:
class SubClass(SuperClass):
def __init__(self, y):
super(SubClass, self).__init__('x')
self.y = y
In Python 3, there's a little magic that makes the arguments to super unnecessary - and as a side benefit it works a little faster:
class SubClass(SuperClass):
def __init__(self, y):
super().__init__('x')
self.y = y
Hardcoding the parent like this below prevents you from using cooperative multiple inheritance:
class SubClass(SuperClass):
def __init__(self, y):
SuperClass.__init__(self, 'x') # don't do this
self.y = y
Note that __init__ may only return None - it is intended to modify the object in-place.
Something __new__
There's another way to initialize instances - and it's the only way for subclasses of immutable types in Python. So it's required if you want to subclass str or tuple or another immutable object.
You might think it's a classmethod because it gets an implicit class argument. But it's actually a staticmethod. So you need to call __new__ with cls explicitly.
We usually return the instance from __new__, so if you do, you also need to call your base's __new__ via super as well in your base class. So if you use both methods:
class SuperClass(object):
def __new__(cls, x):
return super(SuperClass, cls).__new__(cls)
def __init__(self, x):
self.x = x
class SubClass(object):
def __new__(cls, y):
return super(SubClass, cls).__new__(cls)
def __init__(self, y):
self.y = y
super(SubClass, self).__init__('x')
Python 3 sidesteps a little of the weirdness of the super calls caused by __new__ being a static method, but you still need to pass cls to the non-bound __new__ method:
class SuperClass(object):
def __new__(cls, x):
return super().__new__(cls)
def __init__(self, x):
self.x = x
class SubClass(object):
def __new__(cls, y):
return super().__new__(cls)
def __init__(self, y):
self.y = y
super().__init__('x')
Related
Was wondering if there was a way to set a class attribute to a specific instance from within the class definition. For example,
class Value:
def __init__(self, x):
self.x = x
# Something like
# half = Value(0.5)
>>> Value.half.x
0.5
>>> Value.half.half.x
0.5
I'm also aware I can easily set it outside the class that seems a bit more bulky and error prone, like this
class Value:
def __init__(self, x):
self.x = x
Value.half = Value(0.5)
>>> Value.half.x
0.5
>>> Value.half.half.x
0.5
No. At the time the body of the class is being evaluated, the class doesn't yet exist. A class statement is a declarative syntax for calling a metaclass:
class Value:
def __init__(self, x):
self.x = x
is roughly equivalent to
def init(self, x):
self.x = x
Value = type('Value', (object,), {'__init__': init})
Your class attribute would have to be a member of the dict passed as the third argument, which has to be fully defined before type is called.
not quite, but you can make a class method that return a new instance of your class in whatever way you want with the classmethod decorator
>>> class Value:
def __init__(self, x):
self.x=x
def __repr__(self):
return f"{type(self).__name__}({self.x})"
#classmethod
def half(cls):
return cls(0.5)
>>> Value(10)
Value(10)
>>> Value.half()
Value(0.5)
>>>
look like in py3.9 you can combine it with the property decorator to accomplish just that, see linked documentation above (but I don't have it at the moment)
Simply, you can't because the class hasn't yet existed. But you can use either metaclass or class decorator to achieve the same goal as the following shows:
#Metaclass
class Meta(type):
def __init__(cls, clsname, clsbases, clsdict):
cls.half = cls(0.5)
class Value(metaclass=Meta):
def __init__(self, x):
self.x = x
#Decorator
def decorator(cls):
cls.half = cls(0.5)
return cls
#decorator
class Value2:
def __init__(self, x):
self.x = x
print(Value.half.half.x)
print(Value.half.x)
print(Value2.half.half.x)
print(Value2.half.x)
Here is the format of my code:
class A(object):
def __init__(self, x, other):
self.other = other
self.x = x
class B(A):
def __init__(self):
# place code here
def something_else(self):
return self.x["foo"]
x is an object which I would like to call, with a subscript later on (in something_else.
I would like only x to be inherited from the parent class.
It is important that other is not inherited, so super().__init__ is not suitable.
I have attempted a workaround by creating a function within class A:
def x(self):
return self.x
so I could call super().x() in class B, but this doesn't work either.
I have attempted calling directly super.x["foo"], and this doesn't work.
How can I achieve what I want in my case?
Thanks!
Variables don't always have to be registered in the __init__ function, if you want x from class A, have a method in A:
def set_x(self, x):
self.x = x
# other stuff
you'll still be able to call set_x from class B as all functions are inherited, from there you can instantiate property x without calling __init__ from A.
As title described, I an confused as the example:
class Point(object):
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
#classmethod
def get_point1(cls, cor): # cor is list with x=1 and y=2
return Point(cor[0], cor[1])
#classmethod
def get_point2(cls, cor):
return cls(cor[0], cor[1])
I am confused which one(get_point1 or get_point2) should I use, and what is the difference between them?
The #classmethod decorator makes the function a class method, as opposed to instance method. To make it more robust, it is preferable to use cls rather than the actual class name where it is defined.
If you use cls, the parameter which will be passed depends on the actual class being called (for example, if you subclass Point) while using Point explicity, may cause issues if you subclass it and use the class method.
Look at this code for example
class Point(object):
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
#classmethod
def get_point1(cls, cor): # cor is list like [1,2] with x=1 and y=2
return Point(cor[0], cor[1])
#classmethod
def get_point2(cls, cor):
return cls(cor[0], cor[1])
class SubPoint(Point):
pass
sub1 = SubPoint.get_point1([0, 1])
sub2 = SubPoint.get_point2([2, 2])
print sub1.__class__
print sub2.__class__
<class '__main__.Point'>
<class '__main__.SubPoint'>
Is there any other difference? - well, if you need to do some logic inside your class method, which depends on class attributes, then yes it does.
I saw an example that is about super();
class Class1:
def __init__(self):
pass
def name(self):
return "My name is"
class Class2(Class1):
def __init__(self):
pass
def name(self):
return super(Class2, self).name() + " Tom"
#now lets call the object.
b = Class2()
print(b.name())
#Output is 'My name is Tom'
Here is another version of this one without super() that I made on the above codes;
class Class1:
def __init__(self):
pass
def name(self):
return "My name is"
a = Class1()
class Class2(Class1):
def __init__(self):
pass
def name(self):
return a.name() + " Tom"
b = Class2()
print(b.name())
Output is same. So while we can inherit the abilites from Class1, we can use that abilities already. Then why we need super() ?
Because you're using the wrong example. Try to do this without super():
class Base:
def __init__(self, x):
self.x = x
def square(self):
return self.x**2
class Derived(Base):
def __init__(self, x, y):
super().__init__(x)
self.y = y
def square(self):
return super().square() + self.y**2
class CubeMixin(Base):
def square(self):
return self.x**3
class MultiplyDerived(Derived, CubeMixin):
pass
Edited to use multiple inheritance, per chepner in the comments.
When Derived calls super().square(), it gets CubeMixin.square(), rather than Base.square(). If it hadn't used super(), there would be no way for it to know that CubeMixin.square() even existed.
What you did here is called composition, although you missed it by a little.
For large codebase it's generally considered a better approach, because it alleviates issues with debugging. Imagine you had a class that inherited a class which inherited a class... After a while it tends to get hard to keep up. Proper example of a composition would be:
class a(object):
def __init__(self, a):
self.a = a
class b(object):
def __init__(self, b):
self.b = b
class rect(object):
def __init__(self, x, y):
self.a = a(x)
self.b = b(y)
Which seems a bit silly for something stupid, but has pretty much the same uses as inheritance. Additionally, it may take a bit more code (a decorator) to make the class instances not behave like objects so you don't bother the end user.
Get a better example, and comparison composition vs inheritance Here
I have a class (named "A") with some instance variables. I want to add the dir() of this variables to the dir() of instances of class A.
For example:
class A(object):
def __init__(self, x, y):
self.x = x
self.y = y
class X(object):
def f_x(self):
pass
class Y(object):
def f_y(self):
pass
x = X(); y = Y()
a = A(x,y)
I want f_x and f_y to appear in
dir(a)
Is there a better way, or a more 'correct' one, than just iterating X.dict and Y.dict and for each element, use something like:
setattr(A, str(element), element)
Thanks.
A should really be a subclass of X and Y in this case. (Just be sure to read Michele Simionato's article on super and diamond inheritence before you get too deep into it.)
class X(object):
def f_x(self):
pass
class Y(object):
def f_y(self):
pass
class A(X, Y):
def __init__(self, *args, **kwargs): # splats optional
# do what you need to here
dir(A(X(),Y())) # Ah! Lisp!
However, if you really need things to be magic, then just override __getattr__ for X to look in self.x and self.y before throwing an error. But seriously, don't do this.
Why don't you simply inherit from both classes?
class B(A, X):
pass
a = B()
dir(a)