Method default argument whose type is the class not yet defined

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Nov 11 23:31:09 CET 2012


On Sun, 11 Nov 2012 14:21:19 +0000, Oscar Benjamin wrote:

> On 11 November 2012 02:47, Chris Angelico <rosuav at gmail.com> wrote:
>> On Sun, Nov 11, 2012 at 1:43 PM, Ian Kelly <ian.g.kelly at gmail.com>
>> wrote:
>>> On Sat, Nov 10, 2012 at 7:13 PM, Chris Angelico <rosuav at gmail.com>
>>> wrote:
>>>> I would not assume that. The origin is a point, just like any other.
>>>> With a Line class, you could deem a zero-length line to be like a
>>>> zero-element list, but Point(0,0) is more like the tuple (0,0) which
>>>> is definitely True.

Don't conflate the set of all tuples of arbitrary length with points, 
which have fixed length. Points are not *sequences* -- in Python, we 
treat tuples as sequences first and records second, because that is a 
useful thing to do. (But it is not the only useful thing to do: if we 
treated them as records first and sequences second, we might want to say 
that a tuple t was falsey if all the fields in t were falsey.)

In the case of a Point class, a Point is definitely not a sequence. That 
we put the x-coordinate first and the y-coordinate second is a mere 
convention, like writing left to right. The mathematical properties of 
points do not depend on the x-coordinate coming first. Since points 
should not be treated as sequences, the requirement that non-empty 
sequences be treated as truthy is irrelevant.


>>> It's more like the number 0 than the tuple (0,0).
>>>
>>> 0 is the origin on a 1-dimensional number line. (0,0) is the origin on
>>> a 2-dimensional number plane.
>>>
>>> In fact, it might be pointed out that Point(0, 0) is a generalization
>>> of 0+0j, which is equal to 0.
>>
>> Ah, good point. In any case, though, it'd be an utterly inconsequential
>> bug.
> 
> You were right the first time, Chris. A point that happens to coincide
> with the arbitrarily chosen origin is no more truthy or falsey than any
> other. A vector of length 0 on the other hand is a very different beast.

Nonsense. The length and direction of a vector is relative to the origin. 
If the origin is arbitrary, as you claim, then so is the length of the 
vector.

Just because we can perform vector transformations on the plane to move 
the origin to some point other that (0,0) doesn't make (0,0) an 
"arbitrarily chosen origin". It is no more arbitrary than 0 as the origin 
of the real number line.

And yes, we can perform 1D vector transformations on the real number line 
too. Here's a version of range that sets the origin to 42, not 0:

def myrange(start, end=None, step=1):
    if end is None:
        start = 42
    return range(start, end, step)


Nevertheless, there really is something special about the point 0 on the 
real number line, the point (0,0) on the complex number plane, the point 
(0,0,0) in the 3D space, (0,0,0,0) in 4D space, etc. It is not just an 
arbitrary convention that we set the origin to 0.

In other words: to the extent that your arguments that zero-vectors are 
special are correct, the same applies to zero-points, since vectors are 
defined as a magnitude and direction *from the origin*.

To put it yet another way:

The complex number a+bj is equivalent to the 2D point (a, b) which is 
equivalent to the 2D vector [a, b]. If (0, 0) shouldn't be considered 
falsey, neither should [0, 0].


> The significance of zero in real algebra is not that it is the origin
> but rather that it is the additive and multiplicative zero:
> 
>    a + 0 = a  for any real number a
>    a * 0 = 0 for any real number a

I'm not sure what you mean by "additive and multiplicative zero", you 
appear to be conflating two different properties here. 0 is the additive 
*identity*, but 1 is the multiplicative identity:

a + 0 = a
a * 1 = a
for any real number a.

If the RHS must be zero, then there is a unique multiplicative zero, but 
no unique additive zero:

a * 0 = 0 for any real number a
a + -a = 0 for any real number a


> The same is true for a vector v0, of length 0:
> 
>    v + v0 = v for any vector v
>    a * v0 = v0 for any scalar a

Well that's a bogus analogy. Since you're talking about the domain of 
vectors, the relevant identify for the second line should be:

v * v0 = v0 for any vector v

except that doesn't work, since vector algebra doesn't define a vector 
multiplication operator.[1] It does define multiplication between a 
vector and a scalar, which represents a scale transformation.


> There is however no meaningful sense in which points (as opposed to
> vectors) can be added to each other or multiplied by anything, so there
> is no zero point.

I think that the great mathematician Carl Gauss would have something to 
say about that.

Points in the plane are equivalent to complex numbers, and you can 
certainly add and multiply complex numbers. Adding two points is 
equivalent to a translation; multiplication of a scalar with a point is 
equivalent to a scale transformation. Multiplying two points is 
equivalent to complex multiplication, which is a scale + a rotation.

Oh look, that's exactly the same geometric interpretation as for vectors. 
Hardly surprising, since vectors are the magnitude and direction of a 
line from the origin to a point.


> The relationship between points and vectors is analogous to the
> relationship between datetimes and timedeltas. Having Vector(0, 0)
> evaluate to False is analogous to having timedelta(0) evaluate to False
> and is entirely sensible. Having Point(0, 0) evaluate to False is
> precisely the same conceptual folly that sees midnight evaluate as
> False.

If you are dealing with datetimes, then "midnight 2012-11-12" is not 
falsey. The only falsey datetime is the zero datetime. Since it would be 
awfully inconvenient to start counting times from the Big Bang, we pick 
an arbitrary zero point, the Epoch, which in Unix systems is midnight 1 
January 1970, and according to the logic of Unix system administrators, 
that is so far in the distant past that it might as well be the Big Bang.

(People with more demanding requirements don't use Unix or Windows 
timestamps for recording date times. E.g. astronomers use the Julian 
system, not to be confused with the Julian calendar.)

The midnight problem only occurs when you deal with *times* on their own, 
not datetimes, in which case the relationship with timedeltas is not 
defined. How far apart is 1:00am and 2:00am? Well, it depends, doesn't 
it? It could be 1 hour, 25 hours, 49 hours, ... 

In any case, since times are modulo 24 hours, they aren't really relevant 
to what we are discussing.



[1] There is no single meaningful definition of vector multiplication 
that works for all dimensions. In two dimensions, you can define the dot 
product of two vectors to give a scalar; in three dimensions you have a 
dot product and a vector product.

Since vectors are equivalent to points, and points are equivalent to 
complex numbers, one could define a vector operation equivalent to 
complex multiplication. There is a natural geometric interpretation of 
this multiplication: it is a scaling + rotation. 


-- 
Steven


More information about the Python-list mailing list