On May 15, 7:07 pm, "Gabriel Genellina" <[EMAIL PROTECTED]> wrote: > En Tue, 15 May 2007 14:01:20 -0300, [EMAIL PROTECTED] > <[EMAIL PROTECTED]> escribió: > > > On May 15, 12:30 am, "Gabriel Genellina" <[EMAIL PROTECTED]> > > 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 -- http://mail.python.org/mailman/listinfo/python-list