0

Is there a simple way of comparing the string representation of an object to each object in a list?

The example code below (Python 2.7) works as intended, but I assume there's a much nicer way of doing this in Python!

class url(object):
    def __init__(self, address):
       self.address = address

    def __str__(self):
        return self.address

list_of_urls = [url('http://www.example.foo'), url('http://www.example.bar')]
test_url = url('http://www.example.foobar')

test_url_listed = False
for link in list_of_urls:
    if str(test_url) == str(link):
        test_url_listed = True

if not test_url_listed:
    list_of_urls.append(test_url)

Is it possible to make it closer in structure to the following?

if test_url not in list_of_urls:
    list_of_urls.append(test_url)

(As is, this fails since it compares the objects and not the strings they represent.)

2 Answers 2

1
if str(test_url) not in [str(url) for url in list_of_urls]

Or better yet, implement __cmp__ and/or __eq__ + __ne__ on the url class. (And probably also __hash__.) Then you could create a set of urls which would automatically ensure there are no duplicate urls.

Sign up to request clarification or add additional context in comments.

1 Comment

I was thinking more of how to implement it within a class, which the latter part of this solution does. Got my code working using __eq__.
1

The quickest way would be to implement the __cmp__ method.

class url(object):
    def __init__(self, address):
       self.address = address

    def __str__(self):
        return self.address

    def __cmp__(self, other):
        return cmp(self.address, other.address)


list_of_urls = [url('http://www.example.foo'), url('http://www.example.bar')]
test_url = url('http://www.example.foobar')

This in:

if test_url not in list_of_urls:
    print("Not in")

prints "Not in".

Alternatively you can use "rich" comparisons, but that's a little more effort. The total_ordering class method can help.

from functools import total_ordering

@total_ordering
class url(object):
    def __init__(self, address):
       self.address = address

    def __str__(self):
        return self.address

    def __eq__(self, other):
        return self.address == other.address

    def __lt__(self, other):
        return self.address < other.address

This makes all comparisons work with the string attribute named "address". This will fail if you compare other objects, however.

2 Comments

__cmp__ is obsolete, and does work in Python 3. In 3.2+ functools.total_ordering is an easy way to get those all comparisons for free. In previous versions, it's still only a one-liner each (only one oneliner if you only want equality and inequality).
@delnan True. Edited by adding that alternative.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.