Python Forum
What is positional argument self?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
What is positional argument self?
#1
Hello,

I am having this error message and i just dont understand what it means in the context.

from tkinter import *


class Temperature:

    def __init__(self):

        self.valeur = 0


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)

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

    matemp = Temperature()
    matemp.valeur = str(entree.get())

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')




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)

bouton = Button(fen1, text='Conversion', command=conversionC)
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()
Error:
Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\faceo\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1892, in __call__ return self.func(*args) TypeError: conversionC() missing 1 required positional argument: 'self'
There is no line 1892 it stop at 71.

Thank you
Reply
#2
Line 1892 is in tkinter\__init__.py, a file in the tkinter package. This is where your error crashes Python. The error is that lines 11 through 32 which are either indented wrong and are not part of class Temperature, or are intentionally not part of class Temperature and should not have a first argument self. Decide which and fix. And then you'll start seeing the other errors in the code.

Think about this. What is class Temperature? What is it supposed to do? Right not it is not doing anything (it only has an __init__() method), and you have no instances of the class in you program (it is not used).

This code is such a mess that you're better off tossing it in the bin and starting over. You are being held back by this file full of mistakes influencing how you proceed. I think you should write a new program.

Write a program that prints "Fahrenheit" or "Celsius" when the user presses a button. The user selects what to print but is not allowed to type in either string. If you can write this program it should point out the wrong-thinking in your current program.
Reply
#3
You don't need the class to do that.

You never use the user input in entry.

def conversion():
    # use entree.get() for input
    result = 0.0
    if choix.get() == 'Celcius à Fahrenheit':
        result = (float(entree.get()) *9 / 5) + 32
    else:
        result = (float(entree.get()) - 32) * 5 / 9
    resultat.configure(text=str(result))
One conversion button is enough.

all together

from tkinter import *
 

def conversion():
    # use entree.get() for input
    result = 0.0
    if choix.get() == 'Celcius à Fahrenheit':
        result = (float(entree.get()) *9 / 5) + 32
    else:
        result = (float(entree.get()) - 32) * 5 / 9
    resultat.configure(text=str(result))
 
def changement(*args):
    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')
 
 
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=conversion)
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()
Reply
#4
Hello,

Is it possible to do what i did with the else statement in line 17?

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)

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(25)
valeur.valeur
valeur.conversionF()
valeur.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)

bouton = Button(fen1, text='Conversion', command=conversionC)
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()
Cant put a finger on the problem.
It does work alone with the class and constructor:

class Temperature:

    def __init__(self, valeur):
    
        self.valeur = valeur


    def conversionF(self):
        
        resultat = float((9 * self.valeur) / 5 + 32)
        return resultat
    
       
    def conversionC(self):
        resultat = float((self.valeur - 32) * 5 / 9)
        return resultat

valeur = Temperature(77)
valeur.valeur
valeur.conversionF()
valeur.conversionC()

print(valeur.conversionC())
It is returning an error:

Error:
Traceback (most recent call last): File "C:\Users\faceo\PycharmProjects\pythonProject18\main.py", line 40, in <module> valeur.conversionF() AttributeError: 'Temperature' object has no attribute 'conversionF'
Reply
#5
Axel,

The book is asking for 2 conversion methods.

Dean,

My original code without class and constructor is as follow:

from tkinter import *


def conversion():
    if choix.get() == 'Celcius à Fahrenheit':
        celcius = float(entree.get())
        fahrenheit = (celcius * 1.8) + 32
        resultat.configure(text=str(fahrenheit))

    else:
        fahrenheit = float(entree.get())
        celcius = (fahrenheit - 32) / 1.8
        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')


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=conversion)
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()
I am trying to add the class and both methods. The book ask for one class with attribute value, and must be initialize to zero.
2 methods one to convert c-f and the other for f to c.
The more i try the more it turn into a mess.
Reply
#6
Did you read my post above?
Reply
#7
Sorry i replied before i saw the post. Thank you but like i said i am following what the book wants and the book is not very good. 5 pages to explain user interface and 5 pages to explain classes and attributes is not much, in my opinion.
Reply
#8
This is a poor design.
class Temperature:

    def __init__(self, value):
        self.value = value

    def conversionF(self):
        return (9 * self.value) / 5 + 32

    def conversionC(self):
        return (self.value - 32) * 5 / 9

f32 = Temperature(32)
print(f32.conversionC())
print(f32.conversionF())
Output:
0.0 89.6
I set the temperature to 32 degrees F, why does it return 89.6 when I ask to convert that to degrees F? This is a poor design because "value" does not have units, but Temperature implies units. If I was using this object to hold temperature information I need to know the measurement units for the internal value so I can do the proper conversion.

This is a better design.
class Temperature:

    def __init__(self, F=None, C=None):
        if F is not None:
            self.F = F
            self.C = (F - 32) * 5 / 9
        else:
            self.c = 0 if C is None else C
            self.F = (9 * self.C) / 5 + 32

f32 = Temperature(F=32)
print(f32.F)
print(f32.C)
Output:
32 0.0
Now you can initialize the value using F or C and you get correct values if you ask for the temperature in F or C. But you can do better. In the previous example an unscrupulous user could set Temperature.C and Temperature.F to inconsistent values after the object is created. The Temperature class should have only one temperature value in some known units, and provide conversions to different units.
class Temperature:
    def __init__(self, Fahrenheit=None, Celcius=None, Kelvin=None):
        if Fahrenheit is not None:
            self.Fahrenheit = Fahrenheit
        elif Kelvin is not None:
            self.Kelvin = Kelvin
        else:
            self.Celcius = 0 if Celcius is None else Celcius

    @property
    def Celcius(self):
        return self.degreesC

    @Celcius.setter
    def Celcius(self, value):
        self.degreesC = value

    @property
    def Fahrenheit(self):
        return (9 * self.degreesC) / 5 + 32

    @Fahrenheit.setter
    def Fahrenheit(self, value):
        self.degreesC = (value - 32) * 5 / 9

    @property
    def Kelvin(self):
        return self.degreesC + 273.15

    @Kelvin.setter
    def Kelvin(self, value):
        self.degreesC = value - 273.15

temp = Temperature(Kelvin=273.15)
print(f"{temp.Fahrenheit} Fahrenheit, {temp.Celcius} Celcius, {temp.Kelvin} K")
Output:
32.0 Fahrenheit, 0.0 Celcius, 273.15 K
Of course this is based on their being a need for a Temperature class. If all you want to do is temperature unit conversion, functions are a better choice.
Reply
#9
(Mar-04-2022, 04:40 PM)Frankduc Wrote:
class Temperature:

    def __init__(self, valeur):
    
        self.valeur = valeur


    def conversionF(self):
        
        resultat = float((9 * self.valeur) / 5 + 32)
        return resultat
    
       
    def conversionC(self):
        resultat = float((self.valeur - 32) * 5 / 9)
        return resultat

So, you've chosen to use a class to represent a temperature. This is a good thing, because it expresses that temperature is an important concept in your program (or as we might say, in your program's domain). Why, then, do your conversion functions return the plain value instead of Temperature instances?

A temperature isn't just a value. As alluded to above, it's a value along with a unit. I'd then expect conversion functions to work in the following way:

import unittest

class TestTemperature(unittest.TestCase):
    def test_a_temperature_in_celsius_can_be_converted_to_fahrenheit(self):
        temperature = Temperature(0.0, TemperatureUnit.CELSIUS)

        converted = temperature.in_fahrenheit()

        self.assertAlmostEqual(converted.value, 32.0, places=2)
        self.assertEqual(converted.unit, TemperatureUnit.FAHRENHEIT)
        
    def test_a_temperature_in_fahrenheit_can_be_converted_to_celsius(self):
        temperature = Temperature(0.0, TemperatureUnit.FAHRENHEIT)

        converted = temperature.in_celsius()

        self.assertAlmostEqual(converted.value, -17.78, places=2)
        self.assertEqual(converted.unit, TemperatureUnit.CELSIUS)
        
    def test_a_temperature_in_celsius_is_unchanged_when_converted_to_celsius(self):
        temperature = Temperature(0.0, TemperatureUnit.CELSIUS)

        converted = temperature.in_celsius()

        self.assertAlmostEqual(converted.value, temperature.value)
        self.assertEqual(converted.unit, temperature.unit)

    def test_a_temperature_in_fahrenheit_is_unchanged_when_converted_to_fahrenheit(self):
        temperature = Temperature(0.0, TemperatureUnit.FAHRENHEIT)

        converted = temperature.in_fahrenheit()

        self.assertAlmostEqual(converted.value, temperature.value)
        self.assertEqual(converted.unit, temperature.unit)
        
if __name__ ==  "__main__":
    unittest.main()
When you have a fixed set of values (as for the units), an enumeration is a good choice, so TemperatureUnit is defined as follows:

from enum import Enum, auto

class TemperatureUnit(Enum):
    CELSIUS = auto()
    FAHRENHEIT = auto()
The test cases above can be run by saving them into a file and just running that script. It is left as an exercise for you to fulfil the implementations that make them pass ;).
Reply
#10
Nice! Adding a units enumeration makes this a lot more flexible. To add a new unit all I need to do is add it to the enumeration and provide equations for converting to and from Celsius.
import enum

class Temperature:
    """I am a temperature.  You can specify my units.  I do unit conversion"""
    class Unit(enum.Enum):
        CELSIUS = "C"
        FAHRENHEIT = "F"
        KELVIN = "K"

    # 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) * 5 / 9
    }

    # convert from Celsius to unit
    convert_to = {
        Unit.CELSIUS: lambda x: x,
        Unit.KELVIN: lambda x: x + 273.15,
        Unit.FAHRENHEIT: lambda x: (x * 9) / 5 + 32
    }

    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}"

temp = Temperature(273.15, Temperature.Unit.KELVIN)
print("Converting", temp)
for unit in Temperature.Unit:
    temp.set_units(unit)
    print(f"to {unit.name} {temp}")
Output:
Converting 273.15 °K to CELSIUS 0.0 °C to FAHRENHEIT 32.0 °F to KELVIN 273.15 °K
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Error: _vhstack_dispatcher() takes 1 positional argument but 9 were given alexfrol86 3 5,803 May-09-2022, 12:49 PM
Last Post: deanhystad
  positional argument: 'self' mcmxl22 8 3,275 Dec-13-2021, 10:11 PM
Last Post: deanhystad
  TypeError: run_oracle_job() missing 1 required positional argument: 'connection_strin python_student 1 1,962 Aug-06-2021, 08:05 PM
Last Post: SheeppOSU
  TypeError: sum() missing 1 required positional argument: 'num2' Insen 3 5,453 Jan-06-2021, 04:25 PM
Last Post: Insen
  TypeError: forward() missing 1 required positional argument: 'x' sveto4ka 4 12,259 Jun-17-2020, 07:25 PM
Last Post: sveto4ka
  missing 1 required positional argument: 'self' yasser 7 11,441 Jun-07-2020, 06:48 AM
Last Post: ndc85430
  TypeError: _linspace_dispatcher() missing 1 required positional argument: 'stop' Ae_Lovecraft 3 8,554 May-28-2020, 03:33 PM
Last Post: Larz60+
  SyntaxError: positional argument follows keyword argument syd_jat 3 5,820 Mar-03-2020, 08:34 AM
Last Post: buran
  Type error: dump() missing 1 required positional argument: fp jaycuff13 2 21,875 Jul-13-2019, 10:21 AM
Last Post: jaycuff13
  missing 1 required positional argument: psosmol 7 13,165 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