Arximede
Arximede

Reputation: 391

Class attributes defined in __init__() vs. attributes defined by class method

Based on what I tested the in the following code, when I define the self.location attribute in the class Matter(), and when I'm trying to assign the value to the instance it doesn't work.

class Matter():
    """docstring for Matter"""

    def __init__(self):
        self.xcoord = 0
        self.ycoord = 0
        self.location = (self.xcoord, self.ycoord)

main = Matter()
#before changing values
print(main.xcoord, main.ycoord)

#changing values
main.xcoord = 5
main.ycoord = 10

print(main.xcoord, main.ycoord)
print(main.location)

output:

self.location did not change in this case. but when I do this:

main = Matter()
# before changinv the values
print(main.xcoord, main.ycoord)
# changing the values
main.xcoord = 5
main.ycoord = 10
print(main.xcoord, main.ycoord)
print(main.location)


class Matter():
    """docstring for Matter"""

    def __init__(self):
        self.xcoord = 0
        self.ycoord = 0

    def set_location(self):
        self.location = (self.xcoord, self.ycoord)


main = Matter()

print(main.xcoord, main.ycoord)
main.xcoord = 5
main.ycoord = 10

Matter.set_location(main)
print(main.xcoord, main.ycoord)
print(main.location)

output:

bonus question: Any attribute and method that I can create in the class, can be used and modified by using different functions that aren't in the class? I might have confused between attribute vs instance there but if someone can clarify I would be grateful!

Thank you!

Upvotes: 1

Views: 107

Answers (1)

Adam Smith
Adam Smith

Reputation: 54163

This is what properties are for.

Think of properties like methods that act like attributes. You need to calculate something on the fly when it's requested, but the thing it gets back isn't really an action it's more of a state. That's a property.

In this case you have:

class Matter():
    def __init__(self):
        self.x = 5
        self.y = 10

    @property
    def location(self):
        return (self.x, self.y)

Now you can use location as if it were an attribute, while it still works like a method.

m = Matter()
m.location  # (5, 10)
m.x, m.y = (20, 40)
m.location  # (20, 40)

However you CAN'T set via a property...

m.location = (40, 80)  # error

...unless you write a setter

# inside class Matter, after the code above
...
    @location.setter
    def location(self, newloc):
        self.x, self.y = newloc

Now you can, and it updates just like you say it should.

m.location = (40, 80)
m.x  # 40
m.y  # 80
m.location  # (40, 80)

Upvotes: 2

Related Questions