[Python-Dev] trunc()

Guido van Rossum guido at python.org
Sun Jan 27 17:43:14 CET 2008


On Jan 26, 2008 11:14 PM, Raymond Hettinger <python at rcn.com> wrote:
> >. You may disagree, but that doesn't make it nuts.
>
> Too many thoughts compressed into one adjective ;-)
[snip]

> > I don't think that Excel should be held up as a shining example for
> > Python.
>
> It is simply a datapoint.
[snip]

You're beginning to repeat your argument; none of that was new.

> One other thought:  In Python, it has been nice that we have simple type coercions using the type name:
> * set(p)-->q    can accept a list, tuple, string, or any iterable and make a set
> * int(p)-->q     can accept an int, long, float, or string and make an int
> * float(p)-->q  can accept an int, long, float, or string and make an int
> * list(p)-->q    can accept a list, tuple, string, or any iterable and make a list
> * unicode(p)--> can accept a str, buffer, or unicode object and make a unicode object
> It's a bit weird to decide that int() needs to lose that capability so we get generalized Integrals as output.  What's wrong with
> coercion to a concrete type?

Let me get back to you on that.

I first want to point out that you snipped the core of my argument in
the post you otherwise quoted. I will repeat it here because I would
like your explicit reaction:

[Guido]
> There is actually quite an important signal to the reader that is
> present when you see trunc(x) but absent when you see int(x): with
> trunc(x), the implication is that x is a (Real) number. With int(x),
> you can make no such assumption -- x could be a string, or it could be
> a totally different type that happens to define __int__, perhaps a
> custom date/time type (I believe mxDateTime supports this).

Can I assume that you agree with this? That would be progress.

Coming back to your argument that other types have a constructor that
takes all kinds of arguments, I'd like to point out that they all have
restrictions too (except for str()): list() and tuple() only accept
iterables, float() only accepts strings and certain numbers (not
complex), and so on. Taking the latter as an example:

>>> float(0j)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert complex to float; use abs(z)
>>>

I think that (eventually) int(0.0) could do something similar:

>>> int(0.0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't convert float to int; use round(x) or trunc(x)
>>>

But see below.

Yet another (minor) argument that has always made me uncomfortable
with int() == trunc(): the % operator. I think it's a big improvement
over C that Python's % operator is defined as

x%y == x - y*floor(x/y)      # where / is real division

rather than C's division, which uses trunc() instead of floor(). In C
this nicely meshes with the definition of int(): you can define x%y as
x - y*(int)(x/y); but not so in Python. I don't want to use this as an
argument for defining int(x) as floor(x), but I do want to point out
that it has always given me a twinge of discomfort.

FInally, there's the "one way" argument. That's a nice slogan, but
doesn't really hold anyways in practice. To copy a list, we can write
either L[:] or list(L). To get the keys of a dict, we can write either
D.keys() or list(D). To convert a number to a string we can write
either "%g" % X or str(X). For octal we can write "%#o" % X or oct(X).
To convert a unicode string to UTF-8, we can write either
U.encode("utf8") or str(U, "utf8"). And so on. In many cases, these
notations aren't exactly the same in semantics (e.g. list(X) always
returns a list, X[:] returns whatever sequence type X is), but
nevertheless they have large areas of overlap. This is how I see
trunc() and int() live together.

After all that, here's my current proposal:

- Deprecating int(<float>) is pretty radical, I think it would have to
happen in the distant future. OR not at all. I'm at best +0 on this,
more like exactly 0. I realize that in practice this kills the idea.
The "purist" argument for it would have worked better if it was made
18 years ago.

- trunc(), round(), floor() and ceil() should all be built-ins,
corresponding to __trunc__, __round__, __floor__ and __ceil__. Then we
have the four standard ways to go from Reals to Integers, which are
properly extensible for folks who write their own number types. (We
can't control how folks implement __round__, but we can document
expected behavior -- that's how we treat __add__ and all other
operators too, after all.)

- In the docs (especially for beginners) we recommend that users write
trunc() instead of int(), emphasizing that trunc() ensures the
argument is a number, while suggesting int(x) for conversion from
strings. But the implementation won't chastise users by issuing
annoying warnings.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-Dev mailing list