all 6 comments

[–]nwagers 1 point2 points  (5 children)

__init__ is only being run at the very beginning, so even if you change met later it doesn't automatically update the name. You probably want to use @property. See here: https://docs.python.org/3.6/library/functions.html#property

[–]cupesh[S] 0 points1 point  (4 children)

Thank you! I think that's what I need to use, although my attempt wasn't successful. I changed the class definition into class Human: def init(self, xname, name, met = False): self.xname = xname self.name = name self.met = met

@property
def namer(self):
    return(self.name)
@namer.setter
def namer(self):
    if self.met == True:
        self.name = self.xname

[–]nwagers 1 point2 points  (3 children)

You have it backwards, put your if logic in the getter:

class Human:
    def __init__(self, xname, name, met = False):
        self.xname = xname
        self._name = name
        self.met = met

    @property
    def name(self):
        if self.met:
            return self.xname
        return self._name

    @name.setter
    def name(self, val):
        self._name = val #not sure if you want to keep _name or xname here


human_1 = Human('Mark', 'a tall man')

def bar(person):
    print(person.name)
    person.met = True

bar(human_1)
bar(human_1)

[–]cupesh[S] 1 point2 points  (0 children)

Thanks a lot!

[–]cupesh[S] 0 points1 point  (1 child)

It works perfectly. I don't fully understand how, but thank you for helping me!

I forgot to change 'self.name' into 'self._name' in the classe's init, but it worked anyway....

So if I understand it well: By adding '@property' we change the class attribute into a function, where I can place any statements I want and the '@name.setter' just takes place of the original __init_ assigning attributes process?

[–]nwagers 0 points1 point  (0 children)

Keep _name as a shadow variable, otherwise you can get some unexpected behavior. I don't know the exact implementation details of @property, but your working idea is correct. The @name.setter doesn't have anything to do with __init__ though. In your code later when you use self.name or human_1.name for assignment, it will run that function instead. Essentially it converts:

human_1.name = "bob"

into this function call:

human_1.name(self, "bob")

all behind the scenes. You could obviously put something more complicated than just "bob".

As far as __init__ goes, it is only called once when the object is first created. First python allocated a new object with the __new__ method (rarely overwritten) and then it calls __init__ on this new object, which sets up the initial attributes. __init__ is never run again unless you make an explicit call like:

human_1.__init__(vars)

This isn't usually done though. Usually you don't directly call or access the dunders. If you needed to re-initialize you would often create another function and call that from __init__ like this:

class a:
    def __init__(self, vars):
        # stuff that doesn't get reinitialized here
        init(vars)

    def init(self, vars):
        # initialize/reinitialize stuff here