1

I have written the following python code:

class Smartphone:
    def __init__(self, price):
        self.price = price

    def price():
        return price


def lowest_price(phones):
    cheapest = phones[0]
    for phone in phones:
        if phone.price() < cheapest.price():
            cheapest = phone
    return cheapest


if __name__ == "__main__":
    p1 = Smartphone(950)
    p2 = Smartphone(1950)
    phones = [p1, p2]
    cheapest = lowest_price(phones)

When I run this code, I get the following error:

Traceback (most recent call last):
  File "test.py", line 21, in <module>
    cheapest = lowest_price(phones)
  File "test.py", line 12, in lowest_price
    if phone.price() < cheapest.price():
TypeError: 'int' object is not callable

What does that mean and how do I resolve it? Also price could be a float too.

wjandrea
  • 28,235
  • 9
  • 60
  • 81
dnaiel
  • 11
  • 1
  • 1
    `def price(): return price` is not a correct method definition. It must be `def price(self): return self.price`. – DYZ Dec 13 '21 at 23:54
  • 2
    Does this answer your question? [What does "TypeError 'xxx' object is not callable" means?](https://stackoverflow.com/questions/21324940/what-does-typeerror-xxx-object-is-not-callable-means) Specifically, [wmorrison365's answer](/a/53263527/4518341). – wjandrea Dec 14 '21 at 00:04
  • @DYZ same error even after doing that – dnaiel Dec 14 '21 at 00:04
  • BTW, `lowest_price` can be simplified with `min()`. See [Python min function with a list of objects](/q/6085467/4518341) – wjandrea Dec 14 '21 at 00:06
  • In addition to the duplicate, you also have an attribute `price` defined in the `__init__`, and a method `price`. Methods and attributes cannot have the same name. Getter / setter property (link in previous comment) is a way to address it. – Valentino Dec 14 '21 at 00:11

1 Answers1

-1
  1. Instance methods must have a first parameter self (i.e. def price(self))
  2. if you want to return a class field you need to use self (i.e. return self.price)
  3. But there is no need to have a getter for self.price
  4. Python doesn't know if cheapest.price is the method price or the field price so it uses the field and then you get that an int is not a callable (method)

Here is fixed code that takes into account all issues with the code

class Smartphone:
    def __init__(self, price):
        self.price = price


def lowest_price(phones):
    cheapest = phones[0]
    for phone in phones:
        if phone.price < cheapest.price:
            cheapest = phone
    return cheapest


if __name__ == "__main__":
    p1 = Smartphone(950)
    p2 = Smartphone(1950)
    phones = [p1, p2]
    cheapest = lowest_price(phones)
wjandrea
  • 28,235
  • 9
  • 60
  • 81
OranShuster
  • 476
  • 2
  • 12
  • 1
    *"Python doesn't know if `cheapest.price` is the method `price`"* -- Python's not confused. Setting `self.price = price` overrides the method, there's nothing ambiguous about that. – wjandrea Dec 14 '21 at 00:00
  • @wjandrea, that worked. But does that mean we should not have methods like price() inside out objects? Could there be a way to achieve the result while having the method price()? – dnaiel Dec 14 '21 at 00:08
  • @dnaiel You don't need a method just to get an attribute. See [Aaron Hall's excellent answer here](/a/36943813/4518341) – wjandrea Dec 14 '21 at 00:11
  • @dnaiel yes you can have price method if you rename the variable self.price as self._price This is common in Python to name private like variables with a leading underscore. – Malo Dec 14 '21 at 00:13