I was reading some Python code in a private repository on GitHub and found a class resembling the one below:
class Point(object):
'''Models a point in 2D space. '''
def __init__(self, x, y):
super(Point, self).__init__()
self.x = x
self.y = y
# some methods
def __repr__(self):
return 'Point({}, {})'.format(self.x, self.y)
I do understand the importance and advantages of using the keyword super while initialising classes. Personally, I find the first statement in the __init__ to be redundant as all the Python classes inherit from object. So, I want to know what are the advantages(if any) of initializing a Point object using super when inheriting from the base object class in Python ?
There is none in this particular case as object.__init__() is an empty method. However, if you were to inherit from something else, or if you were to use multiple inheritance, call to the super.__init__() would ensure that your classes get properly initialized (assuming of course they depend on initialization from their parent classes). Without that Python's MRO cannot do its magic, for example.
Related
Imagine you have a Vector2() class and you want to prepare some ready-made instances such as Vector2.NORTH = Vector2(0, -1). Now setting them directly as class attributes is, unfortunately, not possible (python throws NameError since the class is not defined yet). Example below:
class Vector2:
# throws NameError: cannot do it directly
NORTH = Vector2(0, -1)
What are best practices to obtain a class equivalent to the above?
(i.e. supporting the syntax Vector2.NORTH)
What I discovered so far:
built-in #classmethod decorator returning the instance (requires the ugly Vector2.NORTH())
custom #classproperty decorator (arguably the best solution? but... additional boiler-plate and a bit too verbose (e.g. cannot exploit local namespace shorthands, especially relevant if you have a lot of nested definitions, copies of constants on demand?))
overloading __getattr__ (this seems messy, since we would have to somehow store these constants inside the method although we could maybe store only the init args outside and retrieve them just before the init)
inherit from the __metaclass__ type?? (not sure about this one... wouldn't we need to define these constants (i.e. NORTH) using the metaclass __init__ and not using the __init__ of the class we are defining?)
dynamically alter the class in-place after the definition (downside: not robust against from ... import Vector2 since the config is not executed, although we could overcome this with some kind of classinit() classmethod and a flag to only run it the first time __init__ gets called.)
I apologize for the overkill. I am aware this is mostly perfectionism nonsense with fancy OOP sauce, but as you can tell I became a bit too obsessed with it now. Why isn't there a more straight-forward and elegant way to achieve this? What's the standard way to do it?
The canonical way is to use metaclasses, for example:
class Vector2Meta(type):
def __init__(cls, *args):
cls.NORTH = cls(0, -1)
class Vector2(metaclass=Vector2Meta):
x = None
y = None
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector2({self.x}, {self.y})"
print(Vector2.NORTH)
output:
Vector2(0, -1)
I have a class design where the Children classes inheriting from a certain Parent class just differ in some parameters, but the Parent class contains all methods, which are using the parameters provided as class variables on the Children. So, in other words, each of my Child classes is fully described by the list of parameters and the inheritance of the Parent class.
So, let's say, I have the following classes:
class Parent():
def __init__(self, **kwargs):
for param in self.__class__.parameters:
self.setattr(param, kwargs.get(param))
def compare(self, other):
for param in self.__class__.parameters:
if self.getattr(param) != other.getattr(param):
return False
return True
class ChildA(Parent):
parameters = ["length", "height", "width"]
def __init__(self, **kwargs):
super().__init__(**kwargs)
class ChildB(Parent):
parameters = ["color", "taste"]
def __init__(self, **kwargs):
super().__init__(**kwargs)
My actual classes are a bit different - I have more and more complex methods on the Parent class and also different kinds of parameters - , but this is sort of a minimum example of the design principle.
Since Parent class is relying on its Children to have the class variable parameters, I thought, I might want to enforce the existence of the class variable on each Child class. I have read that I achieve this by using a metaclass. But I have also read that most developers do not need to use metaclasses, and if in doubt, you probably don't need them. I have never worked with metaclasses before, and so I am in doubt whether I should use them, and so by that rule mentioned, I probably do not need a metaclass. But on the other hand, the term "metaclass" just sounds like a good match to my structure, since Parent really looks like something which could well be called "metaclass" in some sense (technically, not in terms of the way the terminus technicus metaclass is used in OOP, but in terms of: it is fully describing the behaviour of the children classes).
So, I wonder: Is there a different (better) design of classes to reflect my structure? Should I use a metaclass to enforce the existence of the parameters, or is there a better way to do so? Or should I just resign to enforce the existence of the parameters class variable on the Children classes in the first place?
If using python3.6 or above, you can accomplish this using __init_subclass__ which I personally reason better with than a metaclass.
An example of __init_subclass__ based on the usecase described:
class Parent:
def __init_subclass__(cls):
if not hasattr(cls, 'parameters'):
raise TypeError(f'Subclass of {cls} does not have a parameters class attribute')
def __init__(self, **kwargs):
for param in self.__class__.parameters:
self.setattr(param, kwargs.get(param))
def compare(self, other):
for param in self.__class__.parameters:
if self.getattr(param) != other.getattr(param):
return False
return True
class GoodChild(Parent):
parameters = ['length', 'height', 'width']
class BadChild(Parent):
pass
Which results in raising a TypeError exception when the BadChild class is created (not when it is instantiated):
TypeError: Subclass of <class '__main__.BadChild'> does not have a parameters class attribute
I dont understand why the childs method set_state() is called here, when i call it from the __init__() method of the base class:
class base():
def __init__(self, x):
self.set_state(x)
def set_state(self, x):
self.x = x
print("base")
class child(base):
def __init__(self, x, y):
super().__init__(x)
self.set_state(y)
def set_state(self, y):
self.y = y
print("child")
test = child(1, 2)
Output is:
child
child
This is common to all polymorphic languages. The definition of polymorphism is that the actual (most derived) type of the object determines which version of a method is called, even if all you know at the calling point is that it is an instance of some superclass.
If you need to override this and absolutely only ever call the superclass method from the superclass init, name it with two leading underscores as in __set_state. This invokes pythons name mangling rules so that a subclass can't (easily) override the method - however, it also makes it uncallable (or again not easily callable) from outside code. But the polymorphic behaviour is usually what you want, which is why it is the default in Python (as opposed to, say, C++ where methods are not polymorphic unless you expressly declare them as virtual).
I have a simple mixin structure in Python. The code should be pretty self-explaining:
class Base:
def __init__(self):
pass
class MixinA:
def __init__(self):
self.x = 0
self.y = 1
def a(self):
print('A: x = ' + str(self.x) + ', y = ' + str(self.y))
class MixinB:
def __init__(self):
self.x = 2
self.z = 3
def b(self):
print('B: x = ' + str(self.x) + ', z = ' + str(self.z))
class MyFirstMix(MixinA, MixinB, Base):
def __init__(self):
Base.__init__(self)
MixinB.__init__(self)
MixinA.__init__(self)
class MySecondMix(MixinA, Base):
def __init__(self):
Base.__init__(self)
MixinA.__init__(self)
I'd like to improve this a bit, so this leads to 3 questions/problems:
MixinA and MixinB both have a member x. Is there a way to make sure, each of the class sees only its own x? As far as I know: No, there isn't.
It's slightly cumbersome to call the constructor for each mixin in the mixed class. Is there a way to automatically call all constructors or to do something with the same effect?
Is there a way to dynamically mixin something in-line, without explicitly creating a class? I'm looking for a syntax like: mix = Base() with MixinA
If my proposed structure is completely wrong, I'm also open for other recommendations on how to handle mixins.
For python class inherent, I believe there are some tricks you need to know:
Class in python2 and python3 are quite different.
Python2 support old-style class, but python3 support new-style class only. Simply speaking: in python3, classes always inherent from a base class object, even though you do not explicitly use it. Check Difference-between-Old-New-Class.
Method Resolution Order (MRO). This determines how derived class search inherent members and functions. See MRO
super function. Combined with MRO, you can easily call parent member or function, without explicitly know the name of parent class. See Super
Now comes to you questions:
MixinA and MixinB both have a member x. Is there a way to make sure, each of the class sees only its own x?
I don't quit understand your meaning. When you refer a class member, you must refer it through its instance or class. So instance_of_MixinA.x and instance_of_MixinB.x are separated. If you are talking about class MyFirstMix(MixinA, MixinB, Base), it depends on how __init__ function is called. In your code, you first populate x by MixinB and then reset its value by MixinA.
It's slightly cumbersome to call the constructor for each mixin in the mixed class. Is there a way to automatically call all constructors or to do something with the same effect.
Your designation make it impossible. You have to call all constructors.
Is there a way to dynamically mixin something in-line, without explicitly creating a class?
I am not sure. But I can give you some suggestions: try outside __init__ members when def class (python3, if you used python2 take care of super):
class Base:
def __init__(self):
pass
class MixinA:
x = 0
y = 1
class MixinB:
x = 2
z = 3
def b(self):
print('B: x = ' + str(self.x) + ', z = ' + str(self.z))
class MyFirstMix(MixinA, MixinB, Base):
def __init__(self):
super().__init__()
class MySecondMix(MixinA, Base):
def __init__(self):
super().__init__()
The variables outside __init__ behaves quit different from inside variables: outside variables belongs to class and will be populated for all instances of this class, while inside variables belongs only to instance (referred by self when you define class), and will be populated only if __init__ is called. That's why you cannot use super to call all the constructors---super only call the priority parent's __init__. See variables-outsite-inside-init
This is a good solution to Mixin class. In above code, MyFirstMix inherents both MixinA and MixinB whose members are all class members (outside __init__). So instances of MyFirstMix will inherent all class members of MixinA and MixinB without call __init__. Here MixinA and MixinB own same class member x, but the MRO determines that when instances of MyFirstMix refer x, x from MixinA should be returned.
Hope this will be helpful. Thanks!
When your inheritance schemes start to suffer from these sorts of issues it's time to consider using a technique called composition instead. A good readable introduction to the topic here. The Wikipedia example is a bit less accessible, but also useful if you can handle the other programming languages. This StackExchange question also offers useful discussion.
At its simplest, rather than a class inheriting from SomeParent and mixing in the Mixin class, you instead have the SomeParent instances each create an instance of Mixin and use that to access the mixin class's functionality.
I have a base class that is inherited by multiple child classes. This base class has a method, calc_func(self), which uses uniformly named methods, func(self), in the child classes. This works but this 'architecture' would be very hard to follow if the code ever grew more complex.
# Base class
class base():
x = 12
def calc_func(self):
for i in range(1,4):
self.y += self.func()
# neither y nor func() are defined here so
# it is hard to know where they came from
# Child class 1
class child1(base):
y = 10
def __init__(self):
pass
def func(self): # method used in base class
self.x += self.y
print self.x
return self.x
# x was not defined here so it is
# hard to know where it came from
# Child class 2
class child2(base):
y = 15
def __init__(self):
pass
def func(self): # method used in base class
self.x *= self.y
print self.x
return self.x
# x was not defined here so it is
# hard to know where it came from
test1 = child1() # Create object
test1.calc_func() # Run method inherited from base class
test2 = child2() # Create another object
test2.calc_func() # Run method inherited from base class
The idea was to abstract out common code to the base class but this doesn't seem to be the right way of doing it. Maybe this could be made more understandable by using a naming convention for methods and attributes which reference their particular class of origin? Maybe a different architecture altogether? Any advise will be greatly appreciated.
This base class has a method, calc_func(self), which uses uniformly named methods, func(self), in the child classes. This works but this 'architecture' would be very hard to follow if the code ever grew more complex.
No, that's exactly how object-oriented polymorphism is supposed to work. You're already doing it right!
You say that this seems difficult to understand, but it's not clear why you think it's difficult. Probably the only thing you could do is (a) mark the base class as abstract (b) have all methods that child classes are supposed to supply exist on the base class, but only have them raise NotImplementedError.