Purpose of super() when class does not inherit - python-3.x

I have found a code in realpython.com about python super() and I don't understand what is the purpose of the super() in Rectangle and Triangle init method if both classes have no parent (don't inherit).
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
super().__init__(**kwargs)
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length=length, width=length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class RightPyramid(Square, Triangle):
...

This way, these classes can work with multiple-inheritance, and they may get ancestors unknown at coding time - the call to super, passing any unknown parameters they may have got, ensures they will play nice when used this way.
For example, let's suppose these shapes are used to represent the creation concrete 3D printing plastic objects.
class Print3D:
def __init__(self, *, filament="PLA", **kw):
self.filament=filament
print("Print3D part initialized")
super().__init__(**kwargs)
One now can do:
class PrintedSquare(Square, Print3D):
pass
mysquare = PrintedSquare(length=20, filament="PVC")
and everything will just work.

Related

Factory design pattern using __init_subclass__ python3

I didn't find any info about the implementation of the factory design pattern using __init_subclass__ to register the product and the class. What do you think about?
https://peps.python.org/pep-0487/
class Shape:
product = None
shapes_classes = {}
def __init_subclass__(cls, **kwargs):
cls.shapes_classes[cls.product] = cls
#classmethod
def create_shape(cls, product, *args, **kwargs):
return cls.shapes_classes[product](*args, **kwargs)
def __str__(self):
return f'I am {self.__class__.__name__} shape'
def area(self):
raise NotImplemented
class Triangle(Shape):
product = 'triangle'
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return self.height * self.base / 2
class Square(Shape):
product = 'square'
def __init__(self, base, ):
self.base = base
def area(self):
return self.base ** 2
#Usage:
Shape.shapes_classes
{'triangle': __main__.Triangle, 'square': __main__.Square}
triangle = Shape.create_shape(product='triangle',base=3,height=4)
square=Shape.create_shape(product='square',base=3)
print(triangle)
I am Triangle shape
print(square)
I am Square shape
triangle.area()
6.0
square.area()
9

How to correctly position the QDockWidgets, with a size hint

How to correctly position a different Dockwidgets inside a QMainwindow based on the size hint given to each of the dockwidgets. I tried to position based on addDockWidget and setAllowedAreas, but seems I am missing up the concept. And turn off the tabified when moving the QDockwidgets (prevent them from group in tabs).
from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Dock_1(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def sizeHint(self):
return QSize(.2*self.width(), .7*self.height())
class Dock_2(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def sizeHint(self):
return QSize(.2*self.width(), .3*self.height())
class Dock_3(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def sizeHint(self):
return QSize(.6*self.width(), .7*self.height())
class Dock_4(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def sizeHint(self):
return QSize(.6*self.width(), .3*self.height())
class Dock_5(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
def sizeHint(self):
return QSize(.1*self.width(), self.height())
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 800, 800)
self.UiComponents()
self.show()
def UiComponents(self):
dock1 = QDockWidget("Dock_1", self)
dock2 = QDockWidget("Dock_2", self)
dock3 = QDockWidget("Dock_3", self)
dock4 = QDockWidget("Dock_4", self)
dock5 = QDockWidget("Dock_5", self)
dock1.setAllowedAreas(Qt.LeftDockWidgetArea)
dock2.setAllowedAreas(Qt.BottomDockWidgetArea)
dock3.setAllowedAreas(Qt.TopDockWidgetArea)
dock4.setAllowedAreas(Qt.BottomDockWidgetArea)
dock5.setAllowedAreas(Qt.RightDockWidgetArea)
w_1 = Dock_1(self)
w_2 = Dock_2(self)
w_3 = Dock_3(self)
w_4 = Dock_4(self)
w_5 = Dock_5(self)
dock1.setWidget(w_1)
dock2.setWidget(w_2)
dock3.setWidget(w_3)
dock4.setWidget(w_4)
dock5.setWidget(w_5)
self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
self.addDockWidget(Qt.LeftDockWidgetArea, dock2)
self.addDockWidget(Qt.RightDockWidgetArea, dock3)
self.addDockWidget(Qt.RightDockWidgetArea, dock4)
self.addDockWidget(Qt.RightDockWidgetArea, dock5)
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
Size hints are almost useless for dock widgets, since precedence is given to the central widget and the main window layout, but your approach is in any case wrong for two reasons:
the size hint is called before resizing, and returning a hint based on the current size wouldn't be valid since it could cause some sort of recursion (this doesn't normally happen as sizeHint() is generally called only when the layout structure is changed and then cached, but that's not the point);
when any widget is initialized it has a default size (100x30 if the parent is in the constructor, otherwise 640x480), so the results from your implementation would be invalid anyway;
Since what you want completely depends on the size of the main window, the only possibility is to resize the docks in the resizeEvent().
Also note that:
in order to have dock widgets side by side you must use splitDockWidget();
to have dock 3 and 4 vertically aligned with 1 and 2 (or 5) you can only put them in (and allow) the left or right dock area;
the allowed areas should match the area in which the dock is added;
creating the "inner" widget of a dock with the main window as a parent is pointless, since the dock will take ownership of that widget;
Considering the above, you should remove all sizeHint() overrides, set the proper allowed areas and then lay out the docks as required.
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.setGeometry(200, 200, 800, 800)
self.UiComponents()
self.show()
def UiComponents(self):
dock1 = QDockWidget("Dock_1", self)
dock2 = QDockWidget("Dock_2", self)
dock3 = QDockWidget("Dock_3", self)
dock4 = QDockWidget("Dock_4", self)
dock5 = QDockWidget("Dock_5", self)
dock1.setAllowedAreas(Qt.LeftDockWidgetArea)
dock2.setAllowedAreas(Qt.LeftDockWidgetArea)
dock3.setAllowedAreas(Qt.RightDockWidgetArea)
dock4.setAllowedAreas(Qt.RightDockWidgetArea)
dock5.setAllowedAreas(Qt.RightDockWidgetArea)
w_1 = Dock_1()
w_2 = Dock_2()
w_3 = Dock_3()
w_4 = Dock_4()
w_5 = Dock_5()
dock1.setWidget(w_1)
dock2.setWidget(w_2)
dock3.setWidget(w_3)
dock4.setWidget(w_4)
dock5.setWidget(w_5)
self.addDockWidget(Qt.LeftDockWidgetArea, dock1)
self.addDockWidget(Qt.LeftDockWidgetArea, dock2)
self.addDockWidget(Qt.RightDockWidgetArea, dock3)
self.addDockWidget(Qt.RightDockWidgetArea, dock4)
self.addDockWidget(Qt.RightDockWidgetArea, dock5)
self.splitDockWidget(dock1, dock2, Qt.Vertical)
self.splitDockWidget(dock3, dock5, Qt.Horizontal)
self.splitDockWidget(dock3, dock4, Qt.Vertical)
self.docks = dock1, dock2, dock3, dock4, dock5
def resizeEvent(self, event):
super().resizeEvent(event)
side = self.width() // 5 # 2 / 10
center = side * 3 # 6 / 10
widths = side, side, center, center, side
self.resizeDocks(self.docks, widths, Qt.Horizontal)
vUnit = self.height() // 10
top = vUnit * 7
bottom = vUnit * 3
heights = top, bottom, top, bottom, top + bottom
self.resizeDocks(self.docks, heights, Qt.Vertical)

How can I create a subclass of an existing class?

I'm creating a Space Invaders with PyGame, and I would like to create a subclass of the class Alien, to simplify my code a bit. How would I do this? This is the code i have so far:
class Alien(pygame.sprite.Sprite):
def __init__(self, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(RED)
self.image = pygame.image.load("alien1.png").convert_alpha()
self.rect = self.image.get_rect()
In fact, you've just created a subclass of Sprite. Just do the same with Alien.
class Reptilian(Alien):
def __init__(self, width, height, human_form): # you can pass some other properties
super().__init__(width, height) # you must pass required args to Alien's __init__
# your custom stuff:
self.human_form = human_form

Descriptor pattern : trouble with property and instance attribute

I have implemented the following descriptor class.
I want to follow Player instances attribute credit.
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
class SignalDescriptor(object):
subscriptions = {}
#classmethod
def warn_me(cls, obj, attr, callback):
cls.subscriptions.setdefault(obj, {}).setdefault(attr,
set()).add(callback)
def __init__(self, name, value_init=None):
self.name = name
self.value = value_init
def __get__(self, obj, objtype):
for callback in self.subscriptions.get(obj, {}).get(self.name, ()):
callback('get', obj, self.name, self.value)
return self.value
def __set__(self, obj, value):
for callback in self.subscriptions.get(obj, {}).get(self.name, ()):
callback('set', obj, self.name, self.value, value)
self.value = value
class Player(object):
credits = SignalDescriptor("credits", 0)
def monitor_credits(action, obj, attribut, current_value, new_value=None):
if action == 'set':
print("Credits have been changed:")
else:
print("Credits have been consulted:")
print(action, obj, attribut, current_value, new_value)
MY PROBLEM IS :
1-how to follow multiple instances (ie j1.credits, j2.credits,j3.credits)
I dont know how to re-write my pattern to survey instance attributes, i have here only class attribute survey.
2-How to survey property with my pattern:
Lets look another example:
I dont care about Width or Height change, only surface matters : how to syntax my descriptor pattern ,or my Shape class to accept it,in thise case ?
class Shape():
def __init__(self, Width=1, Height=1):
self.Width = Width
self.Height = Height
#property
def surface(self):
return self.Width * self.Height
rect1 = Shape(3, 4)
rect2 = Shape(4, 3)

pyqt5 and multiple inheritance

I'd like to create a new class that inherits two subclasses of QWidget. I know multi-inheritance isn't possible in pyqt, but how could I manage to have the properties of both parent classes in one subclass?
What I wish I could do is as follows:
class A(QWidget):
def __init__(self, widget, parent=None):
widget.destroyed.connect(self.destroy_handler)
#pyqtSlot()
def destroy_handler(self):
pass
class B (A, QStatusBar):
def __init__(self, widget, parent=None):
A.__init__(self, widget)
QStatusBar.__init__(self, parent)
#pyqtSlot()
def destroyed_handler(self):
print("Destroyed")
I finally found how to do it: first of all, the problems came from A and QStatusBar inheriting QWidget. We can't change QStatusBar, so we must changer A.
A shouldn't inherit QWidget: so let's create another class, AInterface, like that:
class AInterface(QObject):
def __init__(self, a, parent=None)
super().__init__(parent=parent)
self.a = a
self.connect_signal()
def connect_signal(self, widget):
widget.destroyed.connect(self.handler)
#pyqtSlot()
def handler(self):
self.a.handler()
A has now the following implementation:
class A:
def __init__(self, widget):
a.widget = widget
a.interface = AInterface(self)
def handler(self):
pass
Thus, now we can create subclasses inheriting not only A but also any QObject, like this:
class B(QStatusBar, A):
def __init__(self, widget, parent=None):
QStatusBar.__init__(self, parent=parent, wiget=widget)
A.__init__(self, widget)
def handler(self):
self.show('Destroyed', 3000)
Notice the widget=widget in the constructor of QStatusBar: if we don't specify it, a TypeError is thrown...

Resources