Calling a class method returns the hex address

Second week studying Python, and I ran into this conundrum:

class Circle:
    pi = 3.14159

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

    def area(self):
        return self.pi * self.radius**2

    def circumference(self):
        return 2 * self.pi * self.radius

circle = Circle(10)
print(circle.area)
print(circle.pi)

Output: <bound method Circle.area of <main.Circle object at 0x105c5ea50>>
3.14159

When I call the class attribute it works. When I call the instance attribute ‘area’ it does not return the result, it returns what I think is a description of the method, and it’s address.

Not sure what I am doing wrong here…

ADVthanksANCE if you have a pointer!!

Hello,

print(circle.area)

since you’re calling a method (what you call a function when it is within a class … terminology is all for differentiation), you need to use parantheses as in:

print(circle.area())

One small observation. The pi = 3.14159 value is not necessarily an instance attribute. It is a class attribute (note that it is assigned under the class header and not created with the self prefix). It can be accessed with the name of the class as its prefix.

More appropriately:

def area(self):
    return Circle.pi * self.radius**2  # Multiplying a class attribute with an instance attribute

Updating the other method:

def circumference(self):
    return 2 * Circle.pi * self.radius

Thanks Paul! Yes pi as written is a class attribute, not an instance one. This was from a tutorial at Understanding Python Class Attributes By Practical Examples

The issue came when I tried to play around with their code in IDLE. Your clue that the call to a method requires () helped to clarify. I thought that since I had already passed a value to Circle(10), that the methods for area(self) and circumference(self) were rendered into values by calling them.

You actually can do that with the @property decorator, which allows you to reference methods as though they were simple attributes.

>>> class Circle:
    pi = 3.14159

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

    @property
    def area(self):
        return self.pi * self.radius**2

    @property
    def circumference(self):
        return 2 * self.pi * self.radius

>>> circle = Circle(10)
>>> print(circle.area)
314.159
>>> print(circle.circumference)
62.8318

Wow, great tip thanks! I will use this going forward (making every class method a property). I find the code easier to scan without tons of () all over the place.

Do note that’s only going to work if the method doesn’t require any arguments besides self. A method is just a function that belongs to a class, and can take any number of arguments, so @property is only a shortcut for very simple use cases.

1 Like

There are also conventional expectations from a property - it’d be unexpected that accessing an attribute requires lots of computation, or changes the state of the object for example. A method call hints better that those sorts of things would happen.

1 Like