-2

why does this print "So it must be: test test" and not "So it must be: hello it's me"

class bob():
    subjectTemp='test'
    levelTemp='test'
    def setSubject(function_subject):
        bob.subjectTemp=function_subject
        print(bob.subjectTemp)
    def setLevel(function_level):
        bob.levelTemp=function_level
        print(bob.levelTemp)
    def join(subject=subjectTemp, level=levelTemp):
        print("So it must be:", subject, level)



bob.setSubject("hello")
bob.setLevel("it's me")
bob.join()
  • 1
    It won't print either since it'd probably complain that you're passing too many arguments to the functions. you need a [mcve] – Sayse Mar 29 '22 at 07:17
  • the `join` default arguments are the class variables of `bob` which are both `'test'`. – hiro protagonist Mar 29 '22 at 07:18
  • 1
    Because you bind `subject=subjectTemp` to the default value `subjectTemp` had at the time. – deceze Mar 29 '22 at 07:21
  • 1
    This is also not nearly how you're supposed to use classes. Yes, it "works" as far as it does because reasons, but there's basically no point to using a class here. – deceze Mar 29 '22 at 07:22
  • @deceze I needed to use classes cause this is just an example of what I needed, in reality, the class contains more, furthermore, it is a specific type of class required for the implementation of a library. – Riccardo Piana Mar 29 '22 at 21:30
  • In the end, the solution was so simple, and I was doing things in a needlessly complicated way. I was facing challenging (actually challenging) problems before and I went blind forgetting the basics of coding. – Riccardo Piana Mar 29 '22 at 21:32

3 Answers3

3

The immediate "problem" is that this binds at function definition time:

def join(subject=subjectTemp, level=levelTemp):

The value of subject will be the value of subjectTemp at the time the function was declared, and it won't change. See "Least Astonishment" and the Mutable Default Argument for details.

The bigger problem is that this isn't how you use classes at all. You want something like this:

class Bob():
    subject = 'test'
    level = 'test'

    def set_subject(self, subject):
        self.subject = subject
        print(self.subject)

    def set_level(self, level):
        self.level = level
        print(self.level)

    def join(self):
        print("So it must be:", self.subject, self.level)

b = Bob()
b.set_subject("hello")
b.set_level("it's me")
b.join()
deceze
  • 510,633
  • 85
  • 743
  • 889
1

subjectTemp and levelTemp have the default value.

You can write:

class bob():
  subjectTemp='test'
  levelTemp='test'

  def setSubject(function_subject):
      bob.subjectTemp=function_subject
      print(bob.subjectTemp)
    
  def setLevel(function_level):
      bob.levelTemp=function_level
      print(bob.levelTemp)
    
  def join():
      print("So it must be:", bob.subjectTemp, bob.levelTemp)

bob.setSubject("hello")
bob.setLevel("it's me")
bob.join()
Ali
  • 439
  • 1
  • 4
  • 14
0

The default values are evaluated, once, at function definition. This is a classic problem that new Pythonistas stumble upon when using mutable arguments such as lists — but this is another instance of the same gotcha.

You can read more about default arguments in the official documentation.

In particular: "Important warning: The default value is evaluated only once".

Edit: This is the technical explanation for what you ask about, but please read others' comments and answers here. This is a peculiar way to use Python classes which will probably trip your leg down the road. Please google 'Pythonic code' and 'idiomatic code'.

folkol
  • 4,752
  • 22
  • 25