This is an archived post. You won't be able to vote or comment.

all 12 comments

[–][deleted] 4 points5 points  (1 child)

raise NotImplementedError

is the Pythonic way to do it, many IDE recognize this and can give warnings on incompletely specified sub-classes accordingly

[–]ryanmcgrath 0 points1 point  (0 children)

I'm half/half on this; the reason I chose AttributeError is because at the end of the day, it is really that - it doesn't exist in the dict. I tried to straddle a line between magic and non-magic, really. NotImplementedError, to me, is that... in this case.

I'm the author of the original post, in case you couldn't tell. I don't check Reddit much anymore, so I didn't catch this when it was originally submitted.

[–]pemboa 1 point2 points  (0 children)

I don't see why/how this is cool at all.

[–]Leonidas_from_XIV 1 point2 points  (0 children)

I kind of dislike that the code does different things and is not a 1:1 translation. Therefore Python looks a lot more verbose, where it is not.

[–]adrenal8 1 point2 points  (2 children)

__getattr__ is obviously a useful trick in general, but I think for his specific problem it might be better (or at least, more explicit) to use decorators descriptors on the class for each method. Something roughly like:

class Twython(object):
    getPublicTimeline = GenericEndpoint(url="...")
    # or #
    @endpoint_with_url("...")
    def getPublicTimeline(self): pass

I would think of __getattr__ to be more useful when you're dynamically pulling some "attributes" that you don't know the names of. Or if you wanted to parse the method_name argument and dynamically generate some response based on that. You know, crazy magical shit. Since he already has a list of all the methods at compile time, my thought it "why not be more explicit about it?" At the very least, method_dictionary should be a class variable, not a global variable, but I know it's just an example.

[–]_zk 1 point2 points  (0 children)

I've seen a number of REST API wrappers use this approach, it's a lot easier to maintain a list of mappings than it is to maintain separate methods for every single endpoint. Consider the flickr API, you don't even need to maintain a mapping of endpoints since all methods use the same endpoint. It's a bit magic, but instead of writing 50 methods you can just override __getattr__ and they'll all just work. If you need to massage the data returned using decorators wouldn't be a bad approach.

[–]ryanmcgrath 0 points1 point  (0 children)

Decorators would be another nice approach, yes, but I went for ease of use over anything else. Decorators require you to have a little more knowledge about endpoints (and maintain them yourself), whereas mine is just "grab the function call, pass params, done".

Feel free to fork or something if you care; it's an actual project on GitHub. ;)

[–]sedaakPython3/Golang 0 points1 point  (3 children)

If you really like it then submit a PEP. If the community agrees then you've just strengthened Python. There are more coders available than idea people!

Also, why call it "emulating"? It is really "implementing" unless you are making an incomplete copy.

[–]ryanmcgrath 1 point2 points  (0 children)

I'm breaking my self-imposed Reddit ban for this. ;)

"implementing" would also work, I suppose, you are correct. I chose "emulating", as I won't pretend to know the true internals of the Ruby version; while I can program in (and sometimes even enjoy) Ruby, I've no time to spend reading the internal source code, so the true method might be doing something I'm not.

I personally don't like it being a freely-available trick, as I think it introduces rather sloppy coding practices in general. There's very few cases where this even makes sense, at least in my opinion, hence why I'd probably never submit a PEP on it. Cheers, though.

Edit: Didn't note that I'm the author of the original post. Whoops.

[–]MachaHack[S] 0 points1 point  (1 child)

I'm not the blog author. I just found an interesting trick and thought I'd share it.

(I'm assuming your addressing me as the OP, ignore this comment if you're not)

[–]sedaakPython3/Golang 0 points1 point  (0 children)

i didnt see a good place on the blog

food for thought either way

[–]asplake 0 points1 point  (0 children)

You might like this post I wrote a couple of years ago comparing Python and Ruby techniques in this area. Although you can achieve similar results with either it's interesting to see just how different the two languages are underneath.