Python Forum
Need some advice when to use self
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Need some advice when to use self
#1
Hello,
I need some advice on how to use "self" correctly.

I want to write an app that consists of a main window "MainWindow" and a few additional windows - I've also added "AdjustmentsWindow" and "ExportPdfWindow" next to "MainWindow" as an example.

I've read that self plays a role in the process of object creation (instantiation) so that it can be assigned which object it is.

For example, I create only one object from the "MainWindow" class (w = MainWindow()).

Do I always have to use self in "def __init__(self): " of "MainWindow"?

Unfortunately, I'm still a bit unsure where to use self...

It would be great if someone could give me some hints on how to use self...

Thank you very much!!

import sys
from pathlib import Path
from PyQt6.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QHBoxLayout,
QVBoxLayout,
QWidget,
QGroupBox,
QListWidget,
QCheckBox,
QRadioButton,
)

class ExportPdfWindow(QWidget):
    def __init__(self):
        super().__init__()
        label = QLabel("export pdf(s)")
        label2 = QLabel("what would you like to export from the pdf?")
        label3 = QLabel("which pages would you like to receive?")
        radiobutton = QRadioButton("specific page(s)")
        radiobutton2 = QRadioButton("specific page range(s)")
        radiobutton3 = QRadioButton("all pages individually")
        button = QPushButton("apply selection")
        layout = QVBoxLayout()
        for t in [label, label2, label3, radiobutton, radiobutton2, radiobutton3, button]:
            layout.addWidget(t)
        self.setLayout(layout)


class AdjustmentsWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("abc")
        self.setGeometry(300, 300, 300, 300)
        label = QLabel("adjustments")
        listbox1 = QListWidget()
        button_converted_files = QPushButton("converted files")
        listbox2 = QListWidget()
        button_created_files = QPushButton("created files")
        button_donate = QPushButton("donate")
        layout = QVBoxLayout()
        for k in [label, listbox1, button_converted_files, listbox2, button_created_files, button_donate]:
            layout.addWidget(k)
        self.setLayout(layout)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        qr = self.frameGeometry()
        cp = self.screen().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

        self.w = QWidget()
        self.setCentralWidget(QWidget())
        self.setWindowTitle("abc")

        self.groupbox_have = QGroupBox("what do you have?")
        groupbox_have_layout = QVBoxLayout()
        self.groupbox_have.font().setBold(True)
        self.listbox_medium = QListWidget()
        self.listbox_medium2 = QListWidget()
        self.checkbox = QCheckBox("stack contains patchTpages")
        for x in [self.listbox_medium, self.listbox_medium2, self.checkbox]:
            groupbox_have_layout.addWidget(x)
        self.groupbox_have.setLayout(groupbox_have_layout)

        self.groupbox_receive = QGroupBox("what would you like to receive?")
        groupbox_receive_layout = QVBoxLayout()
        self.groupbox_receive.font().setBold(True)
        self.listbox_target = QListWidget()
        self.groupbox_move = QGroupBox("move file(s) to")
        self.groupbox_move.font().setBold(True)
        checkbox_move_to = QCheckBox("move file(s) to desired folder(s)")
        groupbox_move_layout = QVBoxLayout()
        groupbox_move_layout.addWidget(checkbox_move_to)
        self.groupbox_move.setLayout(groupbox_move_layout)

        groupbox_receive_layout = QVBoxLayout()
        for y in [self.listbox_target, self.groupbox_move]:
            groupbox_receive_layout.addWidget(y)
        self.groupbox_receive.setLayout(groupbox_receive_layout)

        self.groupbox_profile = QGroupBox("which profile should be used?")
        self.groupbox_profile.font().setBold(True)
        self.listbox_profile = QListWidget()
        self.button_add_profile = QPushButton("add profile")
        self.button_clear_profile = QPushButton("clear profile")

        groupbox_profile_intern_layout = QHBoxLayout()
        for x in [self.button_add_profile, self.button_clear_profile]:
            groupbox_profile_intern_layout.addWidget(x)

        groupbox_profile_layout = QVBoxLayout()
        groupbox_profile_layout.addWidget(self.listbox_profile)
        groupbox_profile_layout.addLayout(groupbox_profile_intern_layout)
        self.groupbox_profile.setLayout(groupbox_profile_layout)

        self.button_apply_selection = QPushButton("apply selection")
        self.button_adjustments = QPushButton("adjustments")
        self.label = QLabel("abc")

        layoutBase = QVBoxLayout()
        for c in [self.label, self.groupbox_have, self.groupbox_receive, self.groupbox_profile, self.button_apply_selection, self.button_adjustments]:
            layoutBase.addWidget(c)
        self.w.setLayout(layoutBase)
        self.setCentralWidget(self.w)

        # fill listbox
        self.listbox_medium.insertItem(0, "paper")
        self.listbox_medium.insertItem(1, "file(s)")

        self.button_add_profile.clicked.connect(self.button_add_profile_clicked)
        self.button_clear_profile.clicked.connect(self.button_clear_profile_clicked)
        self.button_apply_selection.clicked.connect(self.button_apply_selection_clicked)
        self.button_adjustments.clicked.connect(self.button_adjustments_clicked)

    def button_add_profile_clicked(self):
        print("add_profile")

    def button_clear_profile_clicked(self):
        print("clear_profile")

    def button_adjustments_clicked(self):
        self.w = AdjustmentsWindow()
        self.w.show()

    def button_apply_selection_clicked(self):
        print("apply_selection")


if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyleSheet(Path("stylesheet.qss").read_text())
    w = MainWindow()
    w.show()
    app.exec()
Reply
#2
There is nothing magical about self. This would work fine:
class MainWindow(QMainWindow):
    def __init__(whoopee):
        super().__init__()
        qr = whoopee.frameGeometry()
Using self is just a naming convention for the first argument sent to an instance method of a class.

Maybe your questions should be "When is an instance passed as the first argument to a method?"

The answer to that is simple. If you call a method using an instance of the class, the method is an "instance method", and the first argument will be the instance used to call the method.

__int__() is always an instance method. It always has self as the first argument.

So when should a method be an instance method? A method is an instance method if it uses an instance attribute. For example, this is an instance method because it uses "w", an instance variable of MainWindow.
    def button_adjustments_clicked(self):
        self.w = AdjustmentsWindow()
        self.w.show()
This method does not use any instance variables. It could be a class method or a static method.
    def button_add_profile_clicked(self):
        print("add_profile")
I assume this method will eventually do something that changes MainWindow, and then will have to use instance variables (like a list widget or something), and then it will have to be an imstance method.

In your currrent code, all methods are instance methods, so all of them are passed an instance as the first argument to any of their methods.
Reply
#3
In another of your posts I posed something called AutoLayout. I meant it as a joke, demonstrating that you really can do almost anything you want with Python, even the absurd. But maybe it wasn't so absurd. It is a great fit for the code you are writing.
import sys
from PySide6 import QtWidgets
 
class AutoLayout:
    """Mixin class that adds automatic layout management."""
 
    def __init__(self, *args, layout=QtWidgets.QVBoxLayout, **kwargs):
        super().__init__(*args, **kwargs)
        layout(self)
 
    def __setattr__(self, name, object):
        """Add QT widget objects to the layout."""
        super().__setattr__(name, object)
        if issubclass(type(object), QtWidgets.QWidget):
            self.layout().addWidget(object)

class ExportPdfWindow(AutoLayout, QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.label1 = QtWidgets.QLabel("export pdf(s)")
        self.label2 = QtWidgets.QLabel("what would you like to export from the pdf?")
        self.label3 = QtWidgets.QLabel("which pages would you like to receive?")
        self.radio1 = QtWidgets.QRadioButton("specific page(s)")
        self.radio2 = QtWidgets.QRadioButton("specific page range(s)")
        self.radio3 = QtWidgets.QRadioButton("all pages individually")
        self.button = QtWidgets.QPushButton("apply selection")

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = ExportPdfWindow()
    w.show()
    app.exec()
If you really want to use style sheets, you'll need handles to the widgets, so you can reference them in the sheet. AutoLayout forces you to save every widget as an instance variable, making all widgets available for individual styling.
Reply
#4
Dear deanhystad,

I appreciate the detailed answers you gave and really appreciate the effort you put into it!

Your answers help me a lot to keep getting a little bit better in python.

Thank you very much...

I will need some time to understand the information...

I wish you a nice, relaxing weekend...

Best regards,
flash77
Reply
#5
One of the main reasons for using classes is how nicely they combine data and functions. The functions are called methods, and the data are called instance variables.

Each instance of a class has their own instance variables. If you wrote a class named Cat you might give it instance variables name, breed, birthdate. You could then make thousands of cat instances, and each instance would have it's own name, breed and birthdate. The instance variables let you store the information that is unique to each instance.
from datetime import date

class Cat:
    def __init__(self, name, breed="house cat", dob=date.today().isoformat()):
        """Get self if I like it or not.  Always self in __init__()"""
        self.name = name
        self.breed = breed
        self.dob = date.fromisoformat(dob)

    def age(self):
        """Need self because I use dob"""
        return (date.today() - self.dob).days / 365.25

maggie = Cat("Maggie", "tortoiseshell", "2009-06-05")
print(maggie.age())
That can be your test for when to use "self". When you are writing a class, if the class needs to know something that is tied to a particular instance of the class, that something should be an instance variable. If the class needs to get the value of the instance variable, that is when you need to use self.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020