Re: Thoughts and proposals about types and classes

Tim Peters (tim@ksr.com)
Sun, 12 Sep 93 23:50:59 -0400

> [jack]
> def oldstyle(x):
> if type(x) in (type(()), type([])):
> for i in range(len(x)):
> print i, x[i]
> else:
> print x
>
> def newstyle(x):
> if allowed(x[0]):
> for i in range(len(x)):
> print i, x[i]
> else:
> print x

Is

if allowed(expression):
block1
else:
block2

different from (assuming 'ok' and 'dummy' are otherwise unused)

ok = 1
try:
dummy = expression
except (TypeError, AttributeError):
ok = 0

if ok:
block1
else:
block2

? I suppose you don't actually want to evaluate 'expression', though, or
more likely specifically want _not_ to evaluate 'expression'. I'm not
sure that's possible in general, though. For example, even if x is an
instance of a class that supports a __sub__ method, there's no guarantee
that, e.g.,

x-1

will end up invoking x.__sub__: it depends on what x.__coerce__ decides
to do, and I doubt that's determinable, in general, without executing the
code.

I like the _idea_, because it gets directly at Guido's pragmatic "does
the object support the operation or not?" test. I'm just dubious that it
can be made to work unless the argument is restricted to operations on
built-in objects (about whose behavior Python knows everything up front).

> [steve]
> >>> hasattr( 1, '__add__' )
> >>> 0

Cute! Makes sense, though, eh?

Here's another one to ponder:

>>> class K:
... def __len__(self):
... return 12
...
>>> temp=K(); hasattr(temp,'__len__'); len(temp)
1
12
>>> temp=K; hasattr(temp,'__len__'); len(temp)
1
Stack backtrace (innermost last):
File "<stdin>", line 1
TypeError: len() of unsized object
>>>

I.e., just because something has a __len__ attribute doesn't necessarily
mean you can apply the len function to it. Presumably Jack's
'allowed(len(K))' would have returned 0 here.

> [jaap]
> def altstyle(x)
> try:
> for i in range(len(x)):
> print i, x[i]
> except TypeError:
> print x

I'm not clear on what Jack intended in the original example.

"oldstyle" did the "for i in range ..." bit for and only for tuples and
lists.

"newstyle" did it (I think) for and only for tuples, lists, and objects
that support __getitem__. However, it would raise an exception for
objects that did support __getitem__ but not __len__. In any case, it
doesn't do the same thing as "oldstyle" in all cases.

The code of which I asked "does this differ from oldstyle?" has somewhat
different behavior from both of those, and from "altstyle". altstyle
hides what might be legitimate runtime type errors in an object's __len__
or __getitem__ method, and raises AttributeError for objects that don't
support __len__, or that do support a __len__ that returns a value > 0
but don't support __getitem__.

I don't mean to be irritatingly pedantic there <grin>; the primary real
point is that I think the problem we're trying to _solve_ with this stuff
is remarkably ill-defined (else at least _some_ pair of proposed
solutions would get close to having the same behavior <wink>).

> Here you would rely on the fact that len(x) would return TypeError on an
> unsized object. Or, the x[i] would return TypeError on an unsubscriptable
> object.

Just noting that the absence of __getitem__ yields AttributeError instead
of TypeError.

> Either way, if Python would move towards a more pure OO paradigm, the
> subscription would become a method and you should be able the turn the
> allowed() into a simple check whether a method exists.

See the "class K" example above for a context where this doesn't work as
hoped. Is that the only exception? Suspect it is.

instinctively-suspicious-of-"pure"-anything<wink>-ly y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp