1

I'm learning how to develop some simple GUI applications with PyQt5. I'm also learning Python because of it. There are some things about classes that I don't understand.

For example, here I have a simple GUI code:

from PyQt5 import QtWidgets, QtCore
import sys

class Ui_MainWindow:
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setWindowTitle("Simple GUI")
        MainWindow.resize(800,600)

        self.button = QtWidgets.QPushButton(MainWindow)
        self.button.setGeometry(QtCore.QRect(10, 10, 91, 91))
        self.button.setObjectName("button1")
        self.button.setText("Button")

        self.new_dialog = QtWidgets.QDialog()

        self.button.clicked.connect(lambda: New_Dialog.setupDialog(self.new_dialog, "Simple Dialog"))

class New_Dialog:
    def setupDialog(window, window_name):
        window.setObjectName(window_name)
        window.setWindowTitle(window_name)
        window.resize(600,400)

        window.exec()

app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

The code generates a simple Main window with a button. When I press the button, a new dialog window pops up (depicted in picture).

enter image description here

This is working as I wanted to, but it produces 5 errors:

  1. Method should have "self" as first argument

  2. Instance of 'New_Dialog' has no 'setObjectName' member

  3. Instance of 'New_Dialog' has no 'setWindowTitle' member

  4. Instance of 'New_Dialog' has no 'resize' member

  5. Instance of 'New_Dialog' has no 'exec' member

Analyzing the errors, I wonder: Why I have always to have a self as an argument in a method of a class if there is no self.variable inside the method?

When I add self as argument it show the following error when I press the button:

self.button.clicked.connect(lambda: New_Dialog.setupDialog(self.new_dialog, "Simple Dialog"))
TypeError: setupDialog() missing 1 required positional argument: 'window_name'

What I'm doing wrong?

M--
  • 25,431
  • 8
  • 61
  • 93
Luguecos
  • 131
  • 1
  • 1
  • 9
  • Related (at least): https://stackoverflow.com/q/4445405/10077 – Fred Larson Jan 07 '20 at 15:58
  • 1
    "This is working as I wanted to, but it produces 5 errors" unless you wanted errors, that seems like a self-contradictory statement. Are these *warnings* generated by a static code analyzer or actual errors? – John Coleman Jan 07 '20 at 15:59
  • It is generated by VS Code. The Code runs and produces the window with a button that generates a dialog window when pressed. – Luguecos Jan 07 '20 at 16:05
  • 2
    The `self` argument is needed because Python *always* passes the object to any method in the first argument, so if you don't put `self` there to accept it, you get the object put into the variable with name `window`. Which might be what you want, but it's likely to confuse other readers, since by convention that parameter should always have the name `self`. By contrast, if you don't want to accept that argument at all, make something a static method (with the `@staticmethod` decorator), not an instance method. – Charles Duffy Jan 07 '20 at 16:07
  • 3
    @Luguecos delete this question: https://stackoverflow.com/questions/59618789/missing-self-argument-in-method – eyllanesc Jan 07 '20 at 19:55

1 Answers1

3

As Charles Duffy mentioned, you are going to get self whether you want it (or use it) or not. Doesn't matter what you call it. When you create an instance method inside of a python class, self is part and parcel with that method-- it will always be the first argument when the method is called. If you decide to leave out self in the method definition, then the first thing you list in the arguments list will be self with a different name:

class foo:
  def bar(baz):
    print("self is having an identity crisis, he thinks his name is baz")

in this example, baz is the same object as self would otherwise be. There is no requirement that it be called self, but it is nearly universal convention to use that name. Regardless of what it's called, it will always be the first argument that gets passed to an instance method.

By default, all methods are instance methods, unless explicitly declared otherwise. If you really don't want self and will never use it, then declare the method as a @staticmethod:

@staticmethod
def my_method():
  # can't use self here...

static methods are always a little questionable though: If it doesn't interact with the state of the object, does it really belong as part of that class definition at all? Or should it be moved to a stand-alone function inside the same module?

Now, if you do this:

New_Dialog.setupDialog(new_dialog, "Simple Dialog")

it is actually calling the setupDialog method on the class, and not on instance of the class (an object). In that case, there is no self for Python to pass automatically, because no object instance has been created. And very often, calling it like that is a mistake, when what was really intended is:

New_Dialog().setupDialog(new_dialog, "Simple Dialog")

The only difference between these two calls is the empty parens, (), after New_Dialog. The parens cause Python to invoke the class constructor for New_Dialog and then call setupDialog on the resulting object. Without the parens, you are basically reaching into the class definition itself and running the setupDialog method as if it were a standalone function declared outside of the class.

There are some good explanations of this here: What is the purpose of the word 'self'?

Z4-tier
  • 7,287
  • 3
  • 26
  • 42
  • Yeah, I can see how it makes sense. I added `self` as an argument in my method and called it in `Ui_MainWindow` as `New_Dialog.setupDialog(self.new_dialog, "Simple Dialog")`. Then the following error occured: `setupDialog() missing 1 required positional argument: 'window_name'`. How do I have to call it? Because it seems that it is using the first argument as `self`and not as `window` as it should. – Luguecos Jan 07 '20 at 16:34
  • I was not very clear in the last comment. Actually I declared as `setupDialog(self, window, window_name)`and called as `New_Dialog.setupDialog(self.new_dialog, "Simple Dialog")`. This produces the error: `setupDialog() missing 1 required positional argument: 'window_name'`. Then I called as `New_Dialog.setupDialog(self, self.new_dialog, "Simple Dialog")` and it worked nicelly. However I don't understand why in this case I needed to explicit the `self` when calling the method, and sometimes I can write only `method(variable1, variable2`. – Luguecos Jan 07 '20 at 16:47
  • 1
    When you call it as `New_Dialog.setupDialog`, you are actually calling the `setupDialog` **on the class* and not an instance of the class. Try `New_Dialog().setupDialog(self.new_dialog, "Simple Dialog")` – Z4-tier Jan 07 '20 at 16:52
  • I think I understand. So, to call `New_Dialog.setupDialog(...)` I have to be inside the class. When outside the class, it has to be `New_Dialog().setupDialog(...)`? – Luguecos Jan 07 '20 at 17:12
  • You probably don't ever need to call `New_Dialog.setupDialog()` like that, what you probably want is `New_Dialog().setupDialog()`. Notice the extra set of `()` in there. That makes a huge difference: it's the difference between calling the method on the class versus on an instance of the class. Until this stuff is second nature, you almost certainly do not want to call the method on the class itself. – Z4-tier Jan 07 '20 at 17:20
  • @Luguecos Delete this question: https://stackoverflow.com/questions/59618789/missing-self-argument-in-method – eyllanesc Jan 07 '20 at 19:55