Interesting list Validity (True/False)

mensanator at aol.com mensanator at aol.com
Wed May 16 02:16:59 EDT 2007


On May 15, 7:07 pm, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
wrote:
> En Tue, 15 May 2007 14:01:20 -0300, mensana... at aol.com
> <mensana... at aol.com> escribió:
>
> > On May 15, 12:30 am, "Gabriel Genellina" <gagsl-... at yahoo.com.ar>
> > wrote:
> >> And said section 5.9 should be updated too: "The objects need not have
> >> the
> >> same type. If both are numbers or strings, they are converted to a
> >> common
> >> type.
>
> > Except when they aren't.
>
> I think you don't get the difference between a builtin object, fully under
> the Python developers' control, and a user defined class that can behave
> arbitrarily at wish of its writer and for which the Python documentation
> barely can say a word.
> The docs say how will the Python interpreter try to compare objects
> (invoke the rich comparison methods, invoke __cmp__, etc) and how the
> *builtin* objects behave. For other objects, it's up to the object
> *writer* to provide such methods, and he can do whatever he wishes:
>
> py> class Reversed(int):
> ...   def __lt__(self, other): return cmp(int(self),other)>0
> ...   def __gt__(self, other): return cmp(int(self),other)<0
> ...   def __le__(self, other): return cmp(int(self),other)>=0
> ...   def __ge__(self, other): return cmp(int(self),other)<=0
> ...
> py>
> py> j=Reversed(6)
> py> j==6
> True
> py> j>5
> False
> py> j>10
> True
> py> j<=5
> True
>
> You can't blame Python for this.
>
> >>>> import gmpy
> >>>> a = 2**177149-1
> >>>> b = gmpy.mpz(2**177149-1)
> >>>> a==b
> > True
> >>>> print '%d' % (b)
>
> > Traceback (most recent call last):
> >   File "<pyshell#4>", line 1, in <module>
> >     print '%d' % (b)
> > TypeError: int argument required
>
> > So although the comparison operator is smart enough to realize
> > the equivalency of numeric types and do the type conversion,
> > the print statement isn't so smart.
>
> This is up to the gmpy designers/writers/maintainers. Anyone writing a
> class chooses which features to implement, which ones to omit, how to
> implement them, etc. The code may contain bugs, may not be efficient, may
> not behave exactly as the users expect, may not have anticipated all usage
> scenarios, a long etc. In this case, probably the gmpy writers have chosen
> not to allow to convert to int, and they may have good reasons to not do
> that (I don't know what platform are you working in, but I feel that your
> b object is somewhat larger than sys.maxint...).

Then how does this work?

>>> print '%d' % (long(gmpy.mpz(2**177149-1)))
1454...<53320 digits snipped>...3311

I honestly don't understand why there's a problem here.
If print can handle arbitrary precision longs without
a problem, why does it fail on mpzs > sys.maxint?
If the gmpy writers are not allowing the conversion,
then why do small mpz values work? Something smells
inconsistent here.

How is it that

>>> print '%d' % (1.0)
1

doesn't make a type mismatch? Obviously, the float
got changed to an int and this had nothing to do with
gmpy. Is it the print process responsible for doing
the conversion? Maybe I should say invoking the
conversion? Maybe the gmpy call tries to literally
convert to an integer rather than sneakily substitute
a long?

How else can this phenomena be explained?

> >> Otherwise, objects of different builtin types always compare
> >> unequal, and are ordered consistently but arbitrarily. You can control
> >> comparison behavior of objects of non-builtin types by defining a
> >> __cmp__
> >> method or rich comparison methods like __gt__, described in section
> >> 3.4."
>
> >> I hope this helps a bit. Your performance issues don't have to do with
> >> the
> >> *definition* of equal or not equal,
>
> > I didn't say that, I said the performance issues were related
> > to type conversion. Can you explain how the "definition" of
> > equal does not involve type conversion?
>
> There is no type conversion involved for user defined classes, *unless*
> the class writer chooses to do so.
> Let's invent some new class Number; they can be added and have basic
> str/repr support
>
> py> class Number(object):
> ...   def __init__(self, value): self.value=value
> ...   def __add__(self, other): return Number(self.value+other.value)
> ...   def __str__(self): return str(self.value)
> ...   def __repr__(self): return 'Number(%s)' % self.value
> ...
> py> x = Number(2)
> py> y = Number(3)
> py> z = x+y
> py> z
> Number(5)
> py> z == 5
> False
> py> 5 == z
> False
> py> z == Number(5)
> False
> py> int(z)
> Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
> TypeError: int() argument must be a string or a number
> py> "%d" % z
> Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
> TypeError: int argument required
>
> You can't compare them to anything, convert to integer, still nothing.
> Let's add "int conversion" first:
>
> py> Number.__int__ = lambda self: int(self.value)
> py> int(z)
> 5
> py> "%d" % z
> '5'
> py> z == 5
> False
> py> 5 == z
> False
>
> Ok, a Number knows how to convert itself to integer, but still can't be
> compared successfully to anything. (Perhaps another language would try to
> convert automagically z to int, to compare against 5, but not Python).
> Let's add basic comparison support:
>
> py> Number.__cmp__ = lambda self, other: cmp(self.value, other.value)
> py> z == Number(5)
> True
> py> z > Number(7)
> False
> py> z == z
> True
> py> z == 5
> Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
>    File "<stdin>", line 1, in <lambda>
> AttributeError: 'int' object has no attribute 'value'
>
> Now, a Number can be compared to another Number, but still not compared to
> integers. Let's make the comparison a bit smarter (uhm, I'll write it as a
> regular function because it's getting long...)
>
> py> def NumberCmp(self, other):
> ...   if isinstance(other, Number): return cmp(self.value, other.value)
> ...   else: return cmp(self.value, other)
> ...
> py> Number.__cmp__ = NumberCmp
> py> z == 5
> True
> py> z == 6
> False
> py> 5 == z
> True
>
> As you can see, until I wrote some code explicitely to do the comparison,
> and allow other types of comparands, Python will not "convert" anything.
> If you find that some class appears to do a type conversion when comparing
> instances, it's because the class writer has explicitely coded it that
> way, not because Python does the conversion automagically.

Ok, ok. But how does the subroutine that the class
writer created to do the actual conversion get invoked?

>
> >> only with how someone decided to write  the mpz class.
> > I'm beginning to think there's a problem there.
>
> Yes: you don't recognize that gmpy is not a builtin package, it's an
> external package, and its designers/writers/implementors/coders/whatever
> decide how it will behave, not Python itself nor the Python developers.
>
> --
> Gabriel Genellina





More information about the Python-list mailing list