I'm trying to define a simply Fraction
class
And I'm getting this error:
python fraction.py
Traceback (most recent call last):
File "fraction.py", line 20, in <module>
f.numerator(2)
TypeError: 'int' object is not callable
The code follows:
class Fraction(object):
def __init__( self, n=0, d=0 ):
self.numerator = n
self.denominator = d
def get_numerator(self):
return self.numerator
def get_denominator(self):
return self.denominator
def numerator(self, n):
s开发者_如何学运维elf.numerator = n
def denominator( self, d ):
self.denominator = d
def prints( self ):
print "%d/%d" %(self.numerator, self.denominator)
if __name__ == "__main__":
f = Fraction()
f.numerator(2)
f.denominator(5)
f.prints()
I thought it was because I had numerator(self)
and numerator(self, n)
but now I know Python doesn't have method overloading ( function overloading ) so I renamed to get_numerator
but that's not the problems.
What could it be?
You're using numerator
as both a method name (def numerator(...)
) and member variable name (self.numerator = n
). Use set_numerator
and set_denominator
for the method names and it will work.
By the way, Python 2.6 has a built-in fraction class.
You can't overload the name numerator
to refer to both the member variable and the method. When you set self.numerator = n
, you're overwriting the reference to the method, and so when you call f.numerator(2)
, it's trying to do a method call on the member variable, which is an int
, and Python doesn't let you do that. It's like saying x = 2; x(4)
-- it just doesn't make any sense.
You should rename the setter methods to set_numerator
and set_denominator
to remove this naming conflict.
You are using
numerator
as both a method name and a name for an instance attribute. Since methods are stored on the class, when you lookup that attribute you get the number, not the method. (Python will look up attributes on the instance before looking at the class.)That is to say that on the line where you say
f.numerator(2)
, it looks upf.numerator
and finds that it is0
, then tries to call that0
, which obviously shouldn't work.If you have any practical purpose for this code, you can use the stdlib
fractions
module: http://docs.python.org/library/fractions.html- This is new in Python 2.6. If I needed to represent fractions but was using an earlier version of Python, I'd probably use sympy's
Rational
type.
- This is new in Python 2.6. If I needed to represent fractions but was using an earlier version of Python, I'd probably use sympy's
A more practical default value for
denominator
is probably1
. (That wayFraction(5)
would be five, not some undefined operation tending towards infinity.)Rather than a
prints
method, it would be more typical to define__str__
and just print your object.Your methods are just getting and setting an attribute. In Python, we generally do not use getters and setters—we just let users set our attributes.
- You're coming from a Java background, where one of the basic rules is always to use getter and setter methods rather than let users access attributes. The rationale for this rule is that if, at some future date, you needed to do more than just get and set (you needed to process the data), it would require an API change. Since in Python we have properties, we would not need an API change in that instance so we can safely avoid the boilerplate and cruft of setters and getters.
It wouldn't hurt to inherit
numbers.Rational
(Python 2.6 and up), which lets your class automatically do several things numbers are expected to. You will have to implement everything it needs you to, but then it will automatically make a lot more work. Check out Check out http://docs.python.org/library/numbers.html to learn more.
Spoiler alert:
class Fraction(object):
"""Don't forget the docstring....."""
def __init__(self, numerator=0, denominator=1):
self.numerator = numerator
self.denominator = denominator
def __str__(self):
return "%d / %d" % (self.numerator, self.denominator)
# I probably want to implement a lot of arithmetic and stuff!
if __name__ == "__main__":
f = Fraction(2, 5)
# If I wanted to change the numerator or denominator at this point,
# I'd just do `f.numerator = 4` or whatever.
print f
精彩评论