By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,345 Members | 1,758 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,345 IT Pros & Developers. It's quick & easy.

Customizing sequence types

P: n/a
Hi,
I'm trying to create a class which inherit a list to change some behavior.
This list should contain other instance objects and has to manage
these instances in a particular way.

1) I need to sort this elements in this list, but they must be sorted
using an instance variable. What does Python use to sort elements? I
mean, there is a __sort__ method in the class list or it just uses
comparison operators? In this case, shall I just redefine this
operators in the element classes?

2) I need to have just unique elements. Maybe this is related to first
question (or maybe not). Again, to estabilish the uniqueness of an
element I have to use an instance variable. I think I have to rewrite
both the methods append() and __contains__(), but I'm not sure how.

For the first one I did:

def append(self, element):
if element in self:
pass
else:
list.append(self, element)

It seems right to me, but I have no idea what to do with __contains__()

Suggestion?
Nov 16 '08 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Mr.SpOOn <mr********@gmail.comwrites:
Hi,
I'm trying to create a class which inherit a list to change some behavior.
This list should contain other instance objects and has to manage
these instances in a particular way.

1) I need to sort this elements in this list, but they must be sorted
using an instance variable.
I don't understand what this means.
What does Python use to sort elements? I mean, there is a __sort__
method in the class list or it just uses comparison operators?
Comparison operators are always used but you can sort elements according
to a key (or you can use a compare function in 2.x).

See http://docs.python.org/library/stdty...sequence-types
In this case, shall I just redefine this operators in the element
classes?
Or sort them according to a key.
2) I need to have just unique elements. Maybe this is related to first
question (or maybe not). Again, to estabilish the uniqueness of an
element I have to use an instance variable. I think I have to rewrite
both the methods append() and __contains__(), but I'm not sure how.

For the first one I did:

def append(self, element):
if element in self:
pass
else:
list.append(self, element)

It seems right to me, but I have no idea what to do with __contains__()
Why do you need to redefine __contains__?

If I were you, I wouldn't inherit from list because it seems that your
list-like object quite different from a plain list.

--
Arnaud
Nov 16 '08 #2

P: n/a
Mr.SpOOn wrote:
On Sun, Nov 16, 2008 at 7:15 PM, Arnaud Delobelle
>You should probably use the `bisect` module
(http://docs.python.org/library/bisect.html) for searching and
inserting into the list as it takes advantage of and ensures that the
list keeps sorted. It also means that __contains__ and some other
operations become O(log N) rather than O(N).

This seems good too, but I'd always have to check the presence of an
element before inserting a new one and it's still not clear to me how
to do it.
Read the doc on the bisect module. The first or second function is what
you need. If you read bisect.py in /Lib, you will discover that only
two of the 6 possible comparisons are used, so you only need to define
those two if you want.

The choice between using set and sorted versus list and bisect depends
on how frequently you do which operations.

Nov 17 '08 #3

P: n/a
It seems that I solved my main problem, but I still have some doubt.

I'll make an example:
>>class foo:
.... def __init__(self, a):
.... self.a = a
....
>>f = foo(1)
f2 = foo(2)
f3 = foo(3)
f1 = foo(1)
s = set()
s.add(f)
s
set([<__main__.foo instance at 0x8311fac>])
>>s.add(f2)
s.add(f3)
s.add(f1)
s
set([<__main__.foo instance at 0x831934c>, <__main__.foo instance at
0x83191cc>, <__main__.foo instance at 0x8311fac>, <__main__.foo
instance at 0x831932c>])

I want that f and f1, that have both self.a set to 1, look the same to
the set, so that it doesn't add f1. In this case the instances looks
all different, so it adds them all.

I tried rewriting __hash__ and __cmp__ in the foo class, so that
__hash__ simply returns self.a and __cmp__ return self.a == other.a

I thought this would work, but I was wrong.
I had to rewrite __eq__ with the same code of __cmp__

Why it doesn't work with __cmp__ or __hash__ ?
Nov 17 '08 #4

P: n/a
On Mon, Nov 17, 2008 at 10:05 AM, Mr. SpOOn <mr********@gmail.comwrote:
It seems that I solved my main problem, but I still have some doubt.

I'll make an example:
>>>class foo:
... def __init__(self, a):
... self.a = a
...
>>>f = foo(1)
f2 = foo(2)
f3 = foo(3)
f1 = foo(1)
s = set()
s.add(f)
s
set([<__main__.foo instance at 0x8311fac>])
>>>s.add(f2)
s.add(f3)
s.add(f1)
s
set([<__main__.foo instance at 0x831934c>, <__main__.foo instance at
0x83191cc>, <__main__.foo instance at 0x8311fac>, <__main__.foo
instance at 0x831932c>])

I want that f and f1, that have both self.a set to 1, look the same to
the set, so that it doesn't add f1. In this case the instances looks
all different, so it adds them all.

I tried rewriting __hash__ and __cmp__ in the foo class, so that
__hash__ simply returns self.a and __cmp__ return self.a == other.a
__cmp__ does rich comparisons and is supposed to return 0 for
equality, -1 if the object is less than the other, and 1 if it's
greater than the other. So, using == as its definition is broken as it
returns just a boolean. You'd want cmp(self.a, other.a) if you were
defining __cmp__. However, == obviously works fine for __eq__, hence
why switching to __eq__ fixed your problem.

Also, __hash__ should probably delegate and be defined as
hash(self.a) rather than just self.a itself.
>
I thought this would work, but I was wrong.
I had to rewrite __eq__ with the same code of __cmp__

Why it doesn't work with __cmp__ or __hash__ ?
Probably on account of one of the above errors I explained.

Cheers,
Chris
--
I wonder if there's a Mrs. FoRk...
--
http://mail.python.org/mailman/listinfo/python-list
Nov 17 '08 #5

P: n/a
Mr.SpOOn wrote:
It seems that I solved my main problem, but I still have some doubt.

I thought this would work, but I was wrong.
I had to rewrite __eq__ with the same code of __cmp__

Why it doesn't work with __cmp__ or __hash__ ?
Sets and dicts use __hash__ and __eq__ together, as documented.

"If a class does not define an __eq__() method it should not define a
__hash__() operation either;" (3.0 manual, but same earlier).

Nov 17 '08 #6

P: n/a
On Mon, Nov 17, 2008 at 8:30 PM, Terry Reedy <tj*****@udel.eduwrote:
Sets and dicts use __hash__ and __eq__ together, as documented.

"If a class does not define an __eq__() method it should not define a
__hash__() operation either;" (3.0 manual, but same earlier).
Well, maybe, but in the docs, for the __hash__ method I read:

"If a class does not define a __cmp__() method it should not define a
__hash__() operation either;"
>From here: http://www.python.org/doc/2.5.2/ref/customization.html
Nov 18 '08 #7

P: n/a
En Mon, 17 Nov 2008 16:21:39 -0200, Chris Rebert <cl*@rebertia.com>
escribió:
__cmp__ does rich comparisons and is supposed to return 0 for
equality, -1 if the object is less than the other, and 1 if it's
greater than the other. So, using == as its definition is broken as it
Just a little correction: __cmp__ is the "old" comparison method, the
"rich" comparisons are the six __eq__, __lt__, __gt__, ...
(__cmp__ assumes that any object is either equal, or greater, or less than
another, and no other possibility exists; this isn't true for many
objects, that's why the "rich" methods had to be introduced).

--
Gabriel Genellina

Nov 18 '08 #8

P: n/a
En Mon, 17 Nov 2008 22:04:43 -0200, Mr.SpOOn <mr********@gmail.com>
escribió:
On Mon, Nov 17, 2008 at 8:30 PM, Terry Reedy <tj*****@udel.eduwrote:
>Sets and dicts use __hash__ and __eq__ together, as documented.

"If a class does not define an __eq__() method it should not define a
__hash__() operation either;" (3.0 manual, but same earlier).

Well, maybe, but in the docs, for the __hash__ method I read:

"If a class does not define a __cmp__() method it should not define a
__hash__() operation either;"
>From here: http://www.python.org/doc/2.5.2/ref/customization.html
Yes, __cmp__ is gone in 3.0
You said you wrote __cmp__ the same as __eq__ and that's wrong, they
return different results. Try something like this (untested):

class X:
def __init__(self, a): self.a = a
def __cmp__(self, other): return cmp(self.a, other.a)
def __hash__(self): return hash(self.a)

x1 = X(1)
x2 = X(2)
x3 = X(3)
x4 = X(1)

print len(set([x1, x2, x3, x4]) # should be 3!

--
Gabriel Genellina

Nov 18 '08 #9

P: n/a
On Tue, Nov 18, 2008 at 1:59 AM, Gabriel Genellina
<ga*******@yahoo.com.arwrote:
Yes, __cmp__ is gone in 3.0
You said you wrote __cmp__ the same as __eq__ and that's wrong, they return
different results. Try something like this (untested):

class X:
def __init__(self, a): self.a = a
def __cmp__(self, other): return cmp(self.a, other.a)
def __hash__(self): return hash(self.a)

x1 = X(1)
x2 = X(2)
x3 = X(3)
x4 = X(1)

print len(set([x1, x2, x3, x4]) # should be 3!
Yes, this works. Thanks.
Nov 18 '08 #10

This discussion thread is closed

Replies have been disabled for this discussion.