Object orientation in python

Asked

Viewed 602 times

0

I’m a beginner in Python, I took some courses and I’m trying to learn Tkinter, I found a playlist on youtube with a guy who made a BTC trading app with Tkinter and he created a class to open more than one window, type, when I select a window this can open another and so on, there is A LOT I didn’t understand, I looked for some tutorials about classes on the internet but did not get very well in my head yet.

class SeaofBTCapp(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        container = tk.Frame(self)

        container.pack(side="top", fill="both", expand= True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        frame = StartPage(container, self)

        self.frames[StartPage] = frame

        frame.grid(row=0, column = 0, sitcky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

My doubts are about the lines

container = tk.Frame(self)
frame = StartPage(container, self)

I did not understand how the question of the self in these lines, these parameters will be passed when the class is called? I have big doubts about classes, if someone has a source can be in Portuguese or English I would really appreciate it.

2 answers

1

Yes, these lines are called when the class SeaofBTCapp is instantiated. self refers to the instance. As is traditional in OOP, instances have different values for the same attributes, so it is necessary to refer to the instance sometimes.

The official source for classes is https://docs.python.org/3/tutorial/classes.html

  • I guess that answer doesn’t clear up much, does it? Mine may be exaggerated, but I do not know if for someone who is with the degree of confusion that the OP is about to get a very large application, this will clarify something.

1


This has very little to do with object orientation, and much more to do with Tkinter.

I myself find very bad the inherited design of the classes of the application of Tkinter classes. Since the early 90s, in C++ programming for Windows, and unfortunately, all the documentation of Tkinter does as in this example: inherits the main part of the application from the window component of the framework (in this case, the Seaofbtcapp class inheriting from Tkinter.Tk).

You don’t get almost anything out of it, unless someone thought it was cute back there in Windows programming. But your program doesn’t have much to do with a window to BE a window, which that heritage implies. It’s much simpler if it has a window. Then it does the network and file accounts and transactions it has to do, and when interacting with the user, then yes, it uses the window methods.

In the "real world" someone woke up to this about 10 years ago, and wrote some good articles - a "composition vs heritage" debate. That is: your program can be a class that has several attributes, among them a window (composition) or a window (inheritance). Unfortunately, although it is almost consensual that composition is better in terms of maintenance of the program, this clarification was not given in the existing documentation and examples.

Specifically entering your question: in Tkinter, the first parameter of each component is always your "parent" - in the case of a single window, in general that window. Now, because of the design choice, the main window of the program is the program itself. That is, the "self". So the class that could only worry about the logic of inputs and outputs and currency exchange transactions, which is already complicated enough, has to also worry about accommodating all methods and attributes to manage a Tkinter application - which are of the order of 250 items.

You can have a program working exactly the same way if you don’t inherit anything from your class, and create an attribute self.window = tkinter.Tk() - ready, the 262 attributes needed to manage the window application are isolated in self.window - and you are free to have attributes such as self.wallet_number, self.balance, self.last_quotation for your application logic.

Object orientation is really cool, but when it’s understood organically. The wrong use of this style of window inheritance applications, just forces an unnatural use that complicates and mixes concepts, It’s got to be so confusing for you.

OOP until permtie you create a class that doesn’t worry nothingness with the interface - only with the logic of the application itself - and then a subclass that inherits everything it does, and brood additional attributes to be the window, text entries, and buttons of your program.

Let’s think of an application two orders of magnitude simpler - instead of wanting to start from a bitcoin wallet, without understanding right how a wallet works, without understanding right how Tkinter works, and without understanding right how it works object orientation (it’s - it looks like you were in a bush without a dog) - a simple schedule that only has phone, email and people’s names.

In Python, we can use a Person class to have the name, address and phone data. Hence each person who is in the memory of the program will be an "instance" of the class, or an "object":

class Pessoa:
   def __init__(self, nome="", email="", telefone=""):
        self.nome = nome
        self.email = email
        self.telefone = telefone

Done. In Python, we have the lists. Our simple application can keep the data of several people in a list. And have a Tkinter application class. The application can have: a space for the name, an email, a button for the phone, a button for "next" a button for "previous" and a button for "new". We won’t have multiple instances of the application, even creating a class for it - the advantage here is that several methods linked to the class can share data: for example, everyone can access the list of names.

import Tkinter

class person: def init(self, name="", email="", phone=""): self name = name self.email = email self.phone = phone

def create_entry(root, label): frame = Tkinter. Frame(root) label = Tkinter. Label(frame, text=label + ":") variable = Tkinter. Variable() entry = Tkinter. Entry(frame, textvariable=variable) label.pack() entry.pack() frame.pack() Return variable

class App:
    def __init__(self):
        self.window = tkinter.Tk()
        self.name_var = create_entry(self.window, "Nome")
        self.email_var = create_entry(self.window, "Email")
        self.phone_var = create_entry(self.window, "Telefone")
        self.data = [Person()]

        button_frame = tkinter.Frame(self.window)
        button_frame.pack()
        button_prev = tkinter.Button(self.window, text="<", command=self.previous)
        button_new = tkinter.Button(self.window, text="+", command=self.new)
        button_next = tkinter.Button(self.window, text=">", command=self.next)

        button_prev.pack(side="left"); button_new.pack(side="left"); button_next.pack(side="left")
        self.index = 0

    def save_person_data(self):
        person = self.data[self.index]
        person.name = self.name_var.get()
        person.email = self.email_var.get()
        person.phone = self.phone_var.get()

    def display_person_data(self):
        person = self.data[self.index]
        self.name_var.set(person.name)
        self.email_var.set(person.email)
        self.phone_var.set(person.phone)

    def next(self):
        self.save_person_data()
        self.index += 1
        if self.index >= len(self.data):
            self.index = 0
        self.display_person_data()

    def previous(self):
        self.save_person_data()
        self.index -= 1
        if self.index < 0:
            self.index = len(self.data) - 1
        self.display_person_data()

    def new(self):
        self.save_person_data()
        self.data.append(Person())
        self.index = len(self.data) - 1
        self.display_person_data()


app = App()
tkinter.mainloop()

Ready - this is a minimal application that should be more understandable. The application class has a window, and has variables to set and read the content of text entries. If we put two more methods and the respective buttons - to save and load the data from the disk, it could already function as a mini notebook. And it’s easy to see that in all the methods of a class, the "self" is always the object itself, and "self.something" is the corresponding attribute - with the small class we have control over all the methods and attributes of the same and this is more noticeable.

  • His answer was fantastic but I’m still "dying" to understand all this, I came across a code, class Window(Frame): def init(self, master = None): Frame.init(self, master) self.master = master .init at all

  • Of course, this answer is not enough to "understand object orientation" as a whole. But it should have been clear that any code that has classes inherited from Tkinter is bad code - and even worse to try to be used as an example.

  • I understand, it’s because I usually understand most classes but those of Tkinter I completely bugo, you find it more advantage to learn pyqt instead of Tkinter?

  • Pyqt and more sofisitcado, modern and will let you do more things - but I don’t think most examples will be free of the same problem of these. That should be very clear in my answer: inheriting from Toolkit classes is bad practice. Bad. But everybody does it, because everyone has done it since 1991. Pyqt will be harder to understand a little, because abstraction over C++ methods at some points is very fine, and it gets complicated.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.