Home > Mobile >  Why does this print the wrong thing?
Why does this print the wrong thing?

Time:03-29

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

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

First, your code looks strange, I don't know why you wrote it in that way but why not?

class Bob: #Capitalized Class
    subjectTemp='test'
    levelTemp='test'

    @staticmethod # if you don't need 'self'
    def set_subject(function_subject): # not camelcase, use undercore
        bob.subjectTemp=function_subject
        print(bob.subjectTemp)
    @staticmethod
    def set_level(function_level):
        bob.levelTemp=function_level
        print(bob.levelTemp)
    @staticmethod
    def join(subject=subjectTemp, level=levelTemp):
        print("So it must be:", subject, level)


bob = Bob()
bob.setSubject("hello")
bob.setLevel("it's me")
bob.join()

Another thing is that is a difference between class attributes and instance attributes, I think that, when you use bob.subjectTemp you are changing the instance attribute and when you refer subjectTemp, you are calling class attribute.

Then, your code for works, maybe can looks like:

class Bob:
    subject_temp='test'
    level_temp='test'

    def set_subject(self, function_subject):
        self.subject_temp=function_subject
        print(self.subject_temp)

    def set_level(self, function_level):
        self.level_temp=function_level
        print(self.level_temp)

    def join(self, subject=None, level=None):
        if subject is None:
            subject = self.subject_temp
        if level is None:
            level = self.level_temp
        print("So it must be:", subject, level)


bob = Bob()
bob.set_subject("hello")
bob.set_level("it's me")
bob.join()

class attributes vs instance attributes

  • Related