Python Forum
What is positional argument self?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What is positional argument self?
#11
I dont mean it as a complaint but i like it when you guys comes with sopheticated answers like this.

Its clearly meant to teach me the proper way to implement class and attributes and i tha nk you for that. But its not solving the main issue.

from tkinter import *


class Temperature:

    def __init__(self, valeur):

        self.valeur = valeur


def conversionF(self):
    if choix.get() == 'Celcius à Fahrenheit':
        resultat = float((9 * self.valeur) / 5 + 32)
        return resultat.configure(text=str(fahrenheit))

    else:
        return self.conversionC(self)            ///////// <------i still want to know if it is logical and possible to that. 

def conversionC(self):
    resultat = float((self.valeur - 32) * 5 / 9)
    return resultat.configure(text=str(celcius))


def changement(event):
    if choix.get() == 'Celcius à Fahrenheit':
        txt1.configure(text='Température en Celcius')
        txt2.configure(text='Température en Fahrenheit')
    else:
        txt2.configure(text='Température en Celcius')
        txt1.configure(text='Température en Fahrenheit')

valeur = Temperature(valeur = str(entree.get()))           ///<----instead of a number i want to fit my method to input the temperature.
                                                                                   ///How do i do that.


fen1 = Tk()
fen1.title('Conversion')

txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)

entree = Entry(fen1)
entree.grid(row=0, column=1)

txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)

resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)

bouton = Button(fen1, text='Conversion', command=conversionF)
bouton.grid(row=2, column=0)

choix = StringVar(fen1)
choix.set('Celcius à Fahrenheit')
liste = OptionMenu(fen1, choix, 'Celcius à Fahrenheit', 'Fahrenheit à Celcius', command=changement)

liste.grid(row=2, column=1)

fen1.mainloop()
There must be an easy way to fix that code without reformating the whole thing. I get the bid picture, its the small details that slows me.
Reply
#12
I told you how to fix your problem. Write a little program that prints "Fahrenheit" or "Celsius". When you get that working you will know how to write a temperature conversion program.
Reply
#13
When called as a method, the instance is automatically passed in as the first argument. So you could do:

    return self.conversionC()
Reply
#14
def conversionF(self):  < Notes 1
    if choix.get() == 'Celcius à Fahrenheit':  < Notes 2, 3, 4
        resultat = float((9 * self.valeur) / 5 + 32)  < Notes 5
        return resultat.configure(text=str(fahrenheit))  < Notes 6, 7
 
    else:
        return self.conversionC(self)            ///////// <------i still want to know if it is logical and possible to that.   < Notes 8
Notes 1:
Indenting is wrong. This is not part of class Temperature.

Notes 2:
There should not be an "if" statement in this function. This function converts temperature to Fahrenheit. it should not care about choix. The GUI code should call the appropriate method, conversionF() or conversionC() based on the value of choix.

Notes 3:
Temperature conversion class should not know about choix. The Temperature class should do temperature conversion and the GUI should take care of all the user interface stuff. choix is GUI related and should not appear in the Temperature class

Notes 4:
Do not use hard coded strings or numbers in comparisons. It is too easy to make a typing error and have this comparison return False when you want it to return True. These "magic values" are also hidden inside the code and if you decide to change the string in the GUI you may not remember it has to change here too.

Notes 5:
Why are you converting to float(). The equation will produce a float. There is no reason to call float() to change the float result to a float.

Notes 6:
resultat is a float. It does not understand .configure(). If resultat was something capable of .configure() it would not belong in this method. Calculate the number and return the value.

Notes 7:
There should be no "if" and no "else" in this function.

Six lines of code and 7 errors (at least). This is why I think you should toss the code and start fresh. All the errors make it difficult for me to understand what you think this code is supposed to do, and that makes it difficult to offer advice. Start simple. Get simple to work. Fully understand simple. Graduate to something more complex.
Reply
#15
Here is my temperature converter using my temperature class. I didn't have to make any changes to the Temperature class to use it in the GUI program (I added some more units for fun). The Temperature class is responsible for doing the unit conversion, and the GUI is responsible for getting user input, calling the Temperature methods to do the conversion, and displaying the results. I think your biggest problem was that you mashed all this together and there was no clear definition of who was responsible for what.
"""
Temperature converter panel.  Enter temperature in entry.  Specify units for the
"input" temperature and the tempeerature display.  Converted temperatur appears
in label.
"""
import enum
import tkinter as tk
from tkinter import ttk
 
###### THIS IS THE TEMPERATURE CLASS PART   ######
class Temperature:
    """I am a temperature.  You can specify my units.  I do unit conversion"""

    # Temperature unts and unit conversion information.  All temperatures are
    # converted to and from Celsius regardless of the specified or default units.
    class Unit(enum.Enum):
        CELSIUS = "C"
        FAHRENHEIT = "F"
        KELVIN = "K"
        RANKINE = "Ra"
        REAUMER = "R"
 
    # Convert from unit to Celsius
    convert_from = {
        Unit.CELSIUS: lambda x: x,
        Unit.KELVIN: lambda x: x - 273.15,
        Unit.FAHRENHEIT: lambda x: (x - 32) / 1.8,
        Unit.RANKINE: lambda x: (x - 491.67) / 1.8,
        Unit.REAUMER: lambda x: x * 1.25
    }
 
    # convert from Celsius to unit
    convert_to = {
        Unit.CELSIUS: lambda x: x,
        Unit.KELVIN: lambda x: x + 273.15,
        Unit.FAHRENHEIT: lambda x: x * 1.8 + 32,
        Unit.RANKINE: lambda x: x * 1.8 + 491.67,
        Unit.REAUMER: lambda x: x * 0.8
    }
 
    def __init__(self, value=None, unit=Unit.CELSIUS):
        self.units = unit
        self.set(0 if value is None else value)
 
    def set(self, value, unit=None):
        """Set temperature value.  Can specify unit for value."""
        if unit is None:
            unit = self.units
        self.degreesC = self.convert_from[unit](value)
        return self.degreesC
 
    def set_units(self, units):
        """Change the default temperature units"""
        self.units = units
 
    def get(self, unit=None):
        """Get temperature value.  Can specify unit for value."""
        if unit is None:
            unit = self.units
        return self.convert_to[unit](self.degreesC)
 
    def __str__(self):
        """Get str for printing."""
        return f"{self.get()} °{self.units.value:0.2f}"
 
 
###### THIS IS THE GRAPHICAL USER INTERFACE PART   ######
class TemperatureConverter(tk.Tk):
    """
    Panel that uses Temperature class to do temperature unit conversion
    Converts temperature from one temperature unit to another.
    """
    def __init__(self, *args, **kvargs):
        super().__init__(*args, **kvargs)
        self.wm_title("Temperature Converter")
 
        self.temperature = Temperature()
        self.units = {unit.name:unit for unit in self.temperature.Unit}
        unit_names = list(self.units.keys())
 
 
        tk.Label(self, text="Convert").pack(padx=5, pady=5, side=tk.LEFT)
 
        # "from" temperature widgets
        self.from_units = tk.StringVar(value=unit_names[0])
        self.from_value = tk.DoubleVar(value=0.0)
        tk.Entry(self, textvariable=self.from_value, width=8, justify=tk.RIGHT) \
            .pack(padx=5, pady=5, side=tk.LEFT)
        ttk.Combobox(self, textvariable=self.from_units, values=unit_names, width=12) \
            .pack(padx=5, pady=5, side=tk.LEFT)
     
        tk.Label(self, text="to").pack(padx=5, pady=5, side=tk.LEFT)
 
        # "to" temperature widgets
        self.to_units = tk.StringVar(value=unit_names[0])
        self.to_value = tk.StringVar(value="0.00")
        tk.Label(self, textvariable=self.to_value, width=8, anchor=tk.E).pack(padx=5, pady=5, side=tk.LEFT)
        ttk.Combobox(self, textvariable=self.to_units, values=unit_names, width=12) \
            .pack(padx=5, pady=5, side=tk.LEFT)
 
        # Bind variable write event to convert method.  Convert method ignores arguments
        for var in (self.from_value, self.from_units, self.to_units):
            var.trace("w", self.convert)
 
    def convert(self, *_):
        """Peform temperature unit conversion"""
        try:
            degrees = self.from_value.get()
            self.temperature.set(degrees, self.units[self.from_units.get()])
            degrees = self.temperature.get(self.units[self.to_units.get()])
            self.to_value.set(f"{degrees:0.2F}")
        except tk.TclError:
            self.to_value.set("-NA-")
 
TemperatureConverter().mainloop()
Reply
#16
(Mar-04-2022, 11:18 PM)Frankduc Wrote: when you guys comes with sopheticated answers like this.

I don't think the code I showed was particularly sophisticated, but I can appreciate you may not be familiar with testing or enumerations. The main point I want to get across now though is that the Temperature class I wrote (that passed my tests) was simple. Why simple? Because it represents a single idea: what it means to be a temperature - there's a value and a unit and one can convert between units. Your class, on the other hand, is complicated. It mixes together the idea of what it means to be a temperature and displaying a temperature on a GUI. That makes it harder to understand and harder to change if you needed to - with multiple things going on in a class, if you change one thing you risk breaking another. Try to separate out different ideas like this - remember the Unix philosophy of "do one thing and do it well".
Reply
#17
Just one question.

from tkinter import *


class Temperature:

    def __init__(self):
     self.valeur = 0


def conversionF(self):

    resultat = float((9 * self.valeur) / 5 + 32)
    return resultat.configure(text=str(fahrenheit))


def conversionC(self):

    resultat = float((self.valeur - 32) * 5 / 9)
    return resultat.configure(text=str(celcius))



    matemp = Temperature()
    matemp.valeur = float(entree.get())
    matemp.conversionF()
    matemp.conversionC()

fen1 = Tk()
fen1.title('Conversion')

txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)

entree = Entry(fen1)
entree.grid(row=0, column=1)

txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)

resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)

bouton = Button(fen1, text='Conversion', command=conversionF)
bouton.grid(row=2, column=0)





fen1.mainloop()
Why it return this error:
Error:
TypeError: conversionF() missing 1 required positional argument: 'self'
It was my first question and still is. You guys are probably sick of that thread but...
What does it want.
Reply
#18
Your indentation is wrong, that's the problem.

from tkinter import *
 
 
class Temperature:
 
    def __init__(self):
     self.valeur = 0
 
 
    def conversionF(self):     
        result = float((9 * float(entree.get()) / 5 + 32))
        resultat.configure(text=str(result))
          
    def conversionC(self):    
        result = float((float(entree.get() - 32) * 5 / 9))
        resultat.configure(text=str(result))
 
t = Temperature()
fen1 = Tk()
fen1.title('Conversion')
 
txt1 = Label(fen1, text='Température en Fahrenheit')
txt1.grid(row=0, column=0, sticky=E)
 
entree = Entry(fen1)
entree.grid(row=0, column=1)
 
txt2 = Label(fen1, text='Température en Celcius')
txt2.grid(row=1, column=0, sticky=E)
 
resultat = Label(fen1, text='')
resultat.grid(row=1, column=1)
 
bouton = Button(fen1, text='Conversion', command=t.conversionF)
bouton.grid(row=2, column=0)

 
fen1.mainloop()
Reply
#19
Actually we've explained this over and over and over. One last try.

The error message could not be any more descriptive.

The function conversionF(self) has an argument named "self". When you press the conversion button you call conversionF() without passing any arguments. Your function call is "missing 1 required positional argument".

But this is not the error. This error is one of two things. Either conversionF() is supposed to be a method of class Temperature, or it is supposed to be a standalone function.

Either your program should look more like this:
import tkinter as tk
 
class Temperature:
    """All classes should have a docstring describing their purpose"""
    def __init__(self):
        self.valeur = 0 

    # Indentation is important.  Needs to be indented to same level as __init__()
    def conversionF(self):
        """Methods should also have docstrings"""
        fahrenheit = float((9 * self.valeur) / 5 + 32)
        return resultat.configure(text=str(fahrenheit))
    
    def conversionC(self):
        """To describe what they do"""
        celcius = float((self.valeur - 32) * 5 / 9)
        return resultat.configure(text=str(celcius))
 
# This is not part of class temperature because it is indented the same level as "class Temperature"
fen1 = tk.Tk()
matemp = Temperature()
entree = tk.Entry(fen1).pack()
resultat = tk.Label(fen1, text='')
resultat.pack()
tk.Button(fen1, text='Conversion', command=matemp.conversionF).pack()
fen1.mainloop()
Or it should look more like this:
import tkinter as tk
 
# Treating this as a function.  There is no temperature class anymore
def conversionF():
    """Methods should also have docstrings"""
    fahrenheit = float((9 * valuer) / 5 + 32)
    return resultat.configure(text=str(fahrenheit))

def conversionC():
    """To describe what they do"""
    celcius = float((valuer - 32) * 5 / 9)
    return resultat.configure(text=str(celcius))
 
 # These should not all be global variables
fen1 = tk.Tk()
valuer = 0
entree = tk.Entry(fen1).pack()
resultat = tk.Label(fen1, text='')
resultat.pack()
tk.Button(fen1, text='Conversion', command=conversionF).pack()
fen1.mainloop()
Both programs convert 0 to something. Both programs are still riddled with logic errors.
Reply
#20
Thank you very much to both of you, gentlemen, for your patience and wisdow.
That is what i wanted to know. What specificaly was going wrong in the code.
I didn't understand that t = Temperature() or matemp = Temperature() belong to the scope of the Class temperature.
I got confused because in the book in some examples the funtions are at the same level of the class and sometimes at the level of the init self function. I wonder if its always the case. That points out to what you are saying:
Quote: Either conversionF() is supposed to be a method of class Temperature, or it is supposed to be a standalone function.

Now i can fix the rest.

Axel, Dean have a nice evening!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Error: _vhstack_dispatcher() takes 1 positional argument but 9 were given alexfrol86 3 5,827 May-09-2022, 12:49 PM
Last Post: deanhystad
  positional argument: 'self' mcmxl22 8 3,298 Dec-13-2021, 10:11 PM
Last Post: deanhystad
  TypeError: run_oracle_job() missing 1 required positional argument: 'connection_strin python_student 1 1,974 Aug-06-2021, 08:05 PM
Last Post: SheeppOSU
  TypeError: sum() missing 1 required positional argument: 'num2' Insen 3 5,476 Jan-06-2021, 04:25 PM
Last Post: Insen
  TypeError: forward() missing 1 required positional argument: 'x' sveto4ka 4 12,304 Jun-17-2020, 07:25 PM
Last Post: sveto4ka
  missing 1 required positional argument: 'self' yasser 7 11,481 Jun-07-2020, 06:48 AM
Last Post: ndc85430
  TypeError: _linspace_dispatcher() missing 1 required positional argument: 'stop' Ae_Lovecraft 3 8,580 May-28-2020, 03:33 PM
Last Post: Larz60+
  SyntaxError: positional argument follows keyword argument syd_jat 3 5,834 Mar-03-2020, 08:34 AM
Last Post: buran
  Type error: dump() missing 1 required positional argument: fp jaycuff13 2 21,933 Jul-13-2019, 10:21 AM
Last Post: jaycuff13
  missing 1 required positional argument: psosmol 7 13,188 Apr-16-2019, 10:07 AM
Last Post: DeaD_EyE

Forum Jump:

User Panel Messages

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