3

With file xx.py:

class Foo(object):
    def __init__(self, x):
        self.x = x

    def __long__(self):
        return long(self.x)

    def __float__(self):
        return float(self.x)


y = Foo(22)

print '%d' % y
print '%d' % y

Interactive mode:

$ python -V
Python 2.6.7

$ python -i xx.py 
22
22
>>> 
TypeError: int() argument must be a string or a number, not 'Foo'
>>> '%d' % y
'22'
>>> '%d' % y
TypeError: int() argument must be a string or a number, not 'Foo'
>>> '%d' % y
'22'
>>> '%d' % y
TypeError: int() argument must be a string or a number, not 'Foo'

Why does it alternate between printing '22' and raising a TypeError?

Why does it raise an error on the first carriage return (with no input)?

Thanks.

4
  • Really strange error! I tried this code in Python 2.6.1 on OS X and I couldn't recreate this behavior. Commented Nov 15, 2011 at 2:42
  • Problem also exists as stated under Ubuntu 11.04 with Python 2.7.1+. Commented Nov 15, 2011 at 2:57
  • It does not matter what is typed at the first prompt (including undefined variables or raise(Exception()). It prints the same TypeError error message and not, say, a NameError or an Exception message. Commented Nov 15, 2011 at 21:32
  • Also, int(y) consistently prints a TypeError (except in the first instance as noted above). Commented Nov 15, 2011 at 21:33

2 Answers 2

2

Looks like a bug in python! My guess is it's caused by some leftover cruft from the old string-based exceptions.

The hexadecimal stuff is a red herring, you can also get strange behaviour with simply assigning y = Foo(1) and just using '%d' % y will exhibit the funny toggling stuff.

You should get an TypeError at the first print '0x%x' % y in your script, because that part is not well-defined. But somehow the result gets coerced, and it looks like a string-based exception somehow gets...missed, when it probably should have been turned into a TypeError.

If this string substitution stuff is buggy then it's one more reason to move to the preferred new method for string formatting, e.g. print '{0:x}'.format(22)

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for pointing out that the issue exists with '%d'. I have edited the post.
1

I know why you're getting the error message, it's because you haven't defined an __int__ method for the class, which is used for quite a few things, including old-style string formatting via int(). I seem to recall that int() will only work on numeric types, strings and objects that possess an __int__() method (although there may be others I've forgotten about).

When you add:

def __int__(self):
    return int(self.x)

to your class definition, then the error goes away.

If you just want the error to disappear, that's all you need to do.


What I'm not sure of is why you get the error on alternate runs. In fact, you don't have to do anything on the alternate runs, an ENTER key press will cause the error, the same as when you started:

pax$ python -i xx.py
0x16
0x16
>>> **ENTER**
TypeError: int() argument must be a string or a number, not 'Foo'
>>> '%x'%y
'16'
>>> **ENTER**
TypeError: int() argument must be a string or a number, not 'Foo'
>>> '%x'%y
'16'
>>> **ENTER**
TypeError: int() argument must be a string or a number, not 'Foo'
>>> **ENTER**
>>> **ENTER**
>>> **ENTER**
>>>

1 Comment

I realize that adding a int method would make the error message go away. But my question is why does python alternate between an error and no error with the given class definition. It should either consistently error or it should consistently call the long method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.