I have a custom object in this project of mine, called Page. A Page's identifying feature is its title. A Page is normally created by calling Wiki.page
, Wiki.category
, or Wiki.template
, or by generating them from other methods like Wiki.random
. (I recommend you look a little bit at what that is before going on.)
Sometimes, users of this module might want to generate some Pages and convert that generator into a normal list
. After they obtain that list of Pages, they might want to check if another page they got is in that list. However, this:
>>> wp = mw_api_client.Wiki('https://en.wikipedia.org/w/api.php')
>>> wp.page('title') in [wp.page('title'),
wp.page('not this'),
wp.page('not this either')]
False
should be True, not False, because there is a page with the title
"title" in it. Is there a magic method I can use to make that True? I already tried using __eq__
(for equality) and __hash__
(for hash checking) (commit), but neither seemed to do the trick. Do lists simply use identity? Or is there something else I'm missing? How do I do this properly?
My original answer went down the wrong rabbit hole... (see the history).
It's always worth implementing a simplified version of what is breaking... see below (using these 1,2,3,4 as inspiration)
#!/usr/bin/env python3
from pprint import pprint
class Page(object):
def __init__(self, wiki, **data):
self.wiki = wiki
self.title = None
self.__dict__.update(data)
def __eq__(self, other):
return self.title == other.title
class Wiki(object):
def __init__(self, api_url):
self.api_url = api_url
def page(self, title, **evil):
if isinstance(title, Page):
return title;
return Page(self, title=title, **evil)
w = Wiki('url')
pprint(w)
pprint(w.__dict__)
p1 = w.page('testing')
pprint(p1)
pprint(p1.__dict__)
p2 = w.page('testing')
pprint(p2)
pprint(p2.__dict__)
p3 = w.page('testing something else')
pprint(p3)
pprint(p3.__dict__)
pprint(p1 == p2)
pprint(p1 == p3)
pprint(p1 in [ p2 ])
pprint(p1 in [ p2, p3 ])
Output:
<__main__.Wiki object at 0x7f2891957d30>
{'api_url': 'url'}
<__main__.Page object at 0x7f2891957dd8>
{'title': 'testing', 'wiki': <__main__.Wiki object at 0x7f2891957d30>}
<__main__.Page object at 0x7f2891957e48>
{'title': 'testing', 'wiki': <__main__.Wiki object at 0x7f2891957d30>}
<__main__.Page object at 0x7f289190cf60>
{'title': 'testing something else',
'wiki': <__main__.Wiki object at 0x7f2891957d30>}
True
False
True
True
As you can see, this works...
I'm not sure how I feel about your use of self.__dict__.update(data)
... it caught me off guard first time round... and I'm currently suspicious of it's use here and here (both lines do the same thing...)
class Page(object):
def __init__(self, wiki, getinfo=None, **data):
# ...
if getinfo is None:
getinfo = GETINFO
if getinfo:
self.__dict__.update(self.info())
def info(self):
# ...
self.__dict__.update(page_data)
return page_data
Can you make sure that these calls don't override the title
?
Wait, now it works!
>>> w = mw.Wiki('https://en.wikipedia.org/w/api.php')
>>> a = [w.page('hi'), w.page('ih'), w.page('ij')]
>>> w.page('hi') in a
True
Okay, I don't know what went wrong before. This is solved now. I'll keep Attie's answer in mind, though.