Reputation: 315
I've created some Object Oriented Python code below, where a user instance has been created (called Ben). The functions work correctly however, I have found that when the last line is changed to ben.check_money = 100, no error is thrown. I know that this is not correct syntax. Adding the correct function call back in however, throws the listed error: TypeError: 'int' object is not callable
Original Code:
class User:
def __init__(self):
self.money = 200
self.score = 0
print('Created ')
def increase_money(self, amount):
self.money += amount
def decrease_money(self, amount):
self.money -= amount
def check_money(self):
print(self.money)
ben = User()
ben.check_money() # No error is thrown here
Modified Code 1;
class User:
def __init__(self):
self.money = 200
self.score = 0
print('Created ')
def increase_money(self, amount):
self.money += amount
def decrease_money(self, amount):
self.money -= amount
def check_money(self):
print(self.money)
**ben = User()
ben.check_money = 100 # No error thrown here
ben.check_money() # Error is thrown here**
Modified Code 2;
class User:
def __init__(self):
self.money = 200
self.score = 0
print('Created ')
def increase_money(self, amount):
self.money += amount
def decrease_money(self, amount):
self.money -= amount
def check_money(self):
print(self.money)
**ben = User()
ben.check_money = 100 # No error thrown here
ben.check_money # No Error is thrown here**
My question is; why does the error only occur in certain situations, depending on how you have previous called it? One would assume that it should throw an error for both Modification code 1 and Modification code 2.
Upvotes: 3
Views: 73
Reputation: 8510
Python is dynamic language, that mean that you can add, remove, or replace anything from almost any object you want at any time you want, unless measures are taken from doing that
for example
>>> class Fuu:
def show(self):
print("This is Esparta")
>>> y=Fuu()
>>> y.show()
This is Esparta
>>> y.show
<bound method Fuu.show of <__main__.Fuu object at 0x000000000357CC50>>
>>> y.show = 10
>>> y.show
10
>>> y.a
Traceback (most recent call last):
File "<pyshell#51>", line 1, in <module>
y.a
AttributeError: 'Fuu' object has no attribute 'a'
>>> y.a=42
>>> y.a
42
>>> def buu():
print("42 is the ultimate answer")
>>> y.fun = buu
>>> y.fun()
42 is the ultimate answer
>>>
in this example the class Fuu
only define 1 attribute/method, show
, but you can add additional ones like a
or fun
or replace existing ones like show
at any time as show in the example. In your code what you are doing is replacing your original check_money
method for a integer and python said nothing because it is in its nature to allow this unlike more static lenguajes
Upvotes: 2
Reputation: 136918
When you execute ben.check_money = 100
you replace the function that used to be called check_money
on the ben
object with the integer 100
. Calling an integer as a function doesn't work:
>>> 100()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
You will get a similar error when running ben.check_money()
after setting it to 100.
But if you simply access ben.check_money
you're not asking Python to run check_money
, simply to give it back to you, so you get the integer value back.
Upvotes: 4
Reputation: 5306
When you do this ben.check_money=100
you assigned an integer 100
to the ben.check_money attribute. And this attribute shadowed the method ben.check_money(). Now ben only has attribute check_money
. So if you call ben.check_money
you are actually calling the attribute, which is an int 100
. ben.check_money()
is calling the method but the method is shadowed now.
The right way to do this is probably writing a setter()
method:
class User:
def __init__(self):
self.money = 200
self.score = 0
print('Created ')
def increase_money(self, amount):
self.money += amount
def decrease_money(self, amount):
self.money -= amount
def set_money(self,amount):
self.money = amount
def check_money(self):
print(self.money)
**ben = User()
ben.set_money(100)
ben.check_money()
Upvotes: 3