TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Better Python APIs

160 pointsby ozkatzover 12 years ago

5 comments

JulianWasTakenover 12 years ago
It's true that double underscore methods are sometimes underused and that using them can often make for a better experience, but it's also easy to be overly clever, or to "misuse" them by using them to add semantics to an object that is already a bit mis-designed.<p>The first example in the post (using __repr__) is probably the least controversial. There are places in the official docs that explicitly recommend defining __repr__ for every object you create. This is mostly something that I do do (though there are exceptions of course), but one thing you do want to be careful with is to make sure that what appears in your repr is relevant, terse, and helpful. That means that I <i>will</i> and do sacrifice a repr that is eval'able (which I find to be useless) for a repr that is short and sweet. So for the example in the article, it may or may not make sense to put `self.objects` in there. For a "Container" class, it probably does, but don't extend that to "let's put all our data in the repr for everything".<p>__iter__ is nice, and is one of the most oddly underused methods, but rather than using it there, I think the better thing is to not have the object encapsulate a search, but to have the object encapsulate a YoutubeAPIClient or whatever, and have `search` be a method that returns an iterable. This is also kinda touchy-feely though since I guess there might be examples of __iter__ where I'd feel more comfortable with something like this (a results object).<p>The next one with __sub__ I don't like too much, because I don't like encouraging slow operations with syntax sugar (besides the typechecking).<p>Anyways, I guess I'm nitpicking on examples, mostly. Double underscore methods are generally underused I've found, and if you have doubts on whether you're overreaching, you can always add a method with the same behavior you're using them for in case anyone doesn't like how it reads.
pjscottover 12 years ago
Nice post overall, but I take issue with a couple of the examples. First, the YoutubeSearch class has no reason to be a class. It wants to be a function:<p><pre><code> def youtube_search(term): url = 'https://gdata.youtube.com/feeds/api/videos' params = {'q': term, 'alt': 'json', 'orderby': 'relevance', 'v': '2'} r = requests.get(url, params=params) r.raise_for_status() # 4xx and 5xx replies raise exception for video in r.json.get('feed').get('entry'): yield { 'title': video.get('title').get('$t'), 'url': video.get('link')[0].get('href'), } </code></pre> The ExpressiveList's __sub__() method, as written in the article, requires O(n*k) time to remove k things from a list of length n. By using a set of things to remove, we can get that down to O(n+k):<p><pre><code> class ExpressiveList(list): def __sub__(self, other): if isinstance(other, list): other_set = set(other) return ExpressiveList(x for x in self if x not in other_set) else: return ExpressiveList(x for x in self if x != other)</code></pre>
评论 #4897187 未加载
评论 #4896470 未加载
krosaenover 12 years ago
I suggest the author and readers watch the excellent pycon talk, "Stop Writing Classes":<p><a href="http://www.youtube.com/watch?v=o9pEzgHorH0" rel="nofollow">http://www.youtube.com/watch?v=o9pEzgHorH0</a><p>That said, some nice factoids in the post about making your objects readable in the repl etc.
ninetaxover 12 years ago
I disagree about the operator overloading. It's kind of like a hidden function that could have ambiguous connotations. It could confuse people because of the association with the traditional operations.<p>For simple things like list addition it might be intuitive what the result will be, but if I had a a Vector class and then you were reading some code and saw two vectors being multiplied like this<p><pre><code> a * b </code></pre> well is that a dot product or a cross product? Or maybe a is a scalar and it's scalar multiplication? If it's one of those what do the other operations get for symbols? isn't it easier to do a.cross(b)?<p>If you keep it simple a little syntactic sugar is probably find. Nobody wants to be writing a.add(b.subtract(c.mult(d))) for a + b - c *d .<p>Anyone have other thoughts on this?
评论 #4897810 未加载
评论 #4898007 未加载
评论 #4900319 未加载
评论 #4897915 未加载
lysolover 12 years ago
I always consider these nice to have, because often-times they fall on the implicit side of things rather than explicit. But if you explicitly state "X is also a generator" in your documentation, then by all means implement these methods.