9 ms·
Python Best Practice Patterns
- Axsuul 13y agoIs there something like this for Ruby?
- deleted 13y ago[deleted]
- unoti 13y agoI never knew you could use __enter__ and __exit__ to code your own things that work with the 'with' statement. Well worth the read!
- ajtulloch 13y agoFor simple context managers, an easier method is to use contextlib.contextmanager (http://docs.python.org/library/contextlib.html http://docs.python.org/library/contextlib.html). from contextlib import contextmanager @contextmanager def tag(name): print "<%s>" % name yield print "</%s>" % name with tag("h1"): print "foo" """ <h1> foo </h1> """
- masklinn 13y agoYou don't even have to create a full object if there's no need to: @contextlib.contextmanager def manager(*args): object = initialize(args) try: yield object finally: # cleanup object.close()
- gmjosack 13y agoYou might be interested in the docs on the Data Model [0] to learn more about the various "dunder" (__foo__) methods. There are a ton of cool things you can do with python objects. [0] http://docs.python.org/2/reference/datamodel.html http://docs.python.org/2/reference/datamodel.html
- CmonDev 13y agoAnd the most important pattern: http://stackoverflow.com/questions/1275646/python-3-and-static-typing http://stackoverflow.com/questions/1275646/python-3-and-stat...
- sitkack 13y agoexcept no tools use it, yet. I would absolutely love a version of shedskin that moved to Python3 syntax and used optional typing.
- tveita 13y agoPyCharm will read simple type annotations like def get_error_message(error_code: int) -> string: ... and use them for autocompletion hints and type warnings.
- Walkman 13y agoYou should name a classmethod first variable "cls", not "class_".
- lukasm 13y agoI'm skeptical about the last one return None
- Walkman 13y agoI saw this code yesterday: def is_file_for(is_nagyker, type): if type == KIS_ES_NAGYKER: return True elif type == KISKER and not is_nagyker: return True elif type == NAGYKER and is_nagyker: return True At the first glance, I thought it always return True. Would have been more clear an explicit return False at the end!
- famousactress 13y agoSeems rude to return None instead of False for an is_. I think I would have written: def is_file_for(is_nagyker, type): return type == KIS_ES_NAGYKER or \ (type == KISKER and not is_nagyker) or \ (type == NAGYKER and is_nagyker)
- MereInterest 13y agoAs another change, it is recommended to avoid explicit line continuations by using parentheses instead. def is_file_for(is_nagyker, type): return ((type == KIS_ES_NAGYKER) or (type == KISKER and not is_nagyker) or (type == NAGYKER and is_nagyker)) This way, it doesn't break if there is extra whitespace at the end of the line.
- famousactress 13y agoThanks! I've wondered about this.. I do like the parens better, and it looks like PEP-8 agrees with you: http://legacy.python.org/dev/peps/pep-0008/#maximum-line-length http://legacy.python.org/dev/peps/pep-0008/#maximum-line-len...
- meowface 13y agoAs yet another change, PEP8 recommends placing comparison operators (and dots, when method chaining) at the beginning of each line to make things a little clearer. def is_file_for(is_nagyker, type): return ((type == KIS_ES_NAGYKER) or (type == KISKER and not is_nagyker) or (type == NAGYKER and is_nagyker))
- bru 13y agoSeveral of those patterns are incomplete or frowned upon: * if a method does not use the object's state (no `self` usage) make it a `class-` or `staticmethod`. * Some magic methods are presented. There's more to them[0]. * one should not write `class MyClass:` but `class MyClass(object):` (new style class[1]) * the last one (`return None`) make me very dubious * Cascading methods: that's a big no. The idiom is that if a method may change the state of the object then it should return None (eg `set.add`) 0: well-written and comprehensive guide: http://www.rafekettler.com/magicmethods.html http://www.rafekettler.com/magicmethods.html 1: http://www.python.org/doc/newstyle/ http://www.python.org/doc/newstyle/
- halflings 13y agoIt seems he's using Python 3 (using print as a function), so no need to inherit object.
- Walkman 13y agoThere is a print function in Python 2 either! http://docs.python.org/2/library/functions.html#print http://docs.python.org/2/library/functions.html#print
- famousactress 13y agoFor certain use-cases (like constructing queries for an ORM) or other things where you're effectively passing around curried ideas to eventually be executed, I think cascading methods is a huge win.
- Goopplesoft 13y agoYeah these things aren't as black and white as both the blogger and the original commenter make it seem. Software design is very subjective.
- jlujan 13y agoWhat you are referring to is a design pattern called fluent interfaces[1]. They do make for very usable APIs when used to represent pipelines and filters. They are also used heavily in creating domain specific language features. In your SQL example it works very well such as in SQLAlchemy. But in that example, the chained methods are building a query as opposed to mutating the actual data. Splitting hairs. [1]http://en.m.wikipedia.org/wiki/Fluent_interface http://en.m.wikipedia.org/wiki/Fluent_interface
- sloria 13y agoAuthor here. Must give credit where it's due: These patterns come from a talk by Vladimir Keleshev, author of docopt and excellent Pythonista. These are NOT my original work.
- atrk 13y agoSeveral of these are generally applicable to programming: * Keep functions small and composable * Keep functions at a consistent level of abstraction * Use constructors to ensure objects always exist in a complete, usable state * Use meaningful method names in place of comments It is nice to see that other people struggle with functions with lots of parameters + lots of partial state variables. I don't suppose anyone here has a better solution?
- collyw 13y agoComments should explain why you are doing something while method names are a guide to what they are doing. I see them as for different purposes and one should not replace the other.
- mercurial 13y agoAbsolutely, unless you're writing end-user documentation.
- collyw 13y agoI was playing about in Django recently, having written previous views as functions, I wrote some new ones as class based views. I felt that the OOP approach kept it cleaner and inheritance could be used in the same way as currying could for the function based views (but less complex - maybe because I understand OOP concepts better).
- codelucas 13y agoThis is the guy who authored TextBlob! https://github.com/sloria/TextBlob https://github.com/sloria/TextBlob
- IgorPartola 13y agoAgree with all of these but two. The first is the example of doing: class Foo(object): highlight = reverse No, that is not clearer. Now I have no idea what this method does. Making it explicit requires more keystrokes, but allows you to properly document the method. Also, when I run help(Foo.highlight) I won't get the generic documentation for `reverse`. Second, using `each` for a generic iteration variable. This is an opinion, not a best practice. I would argue that either the loop is a one liner, at which point use whatever you want (x works well), or it's more than one line and then I want a proper name for the thing you are iterating over.
- mercurial 13y agoThe whole "use __iter__ whenever you can" thing is dubious too. It may be fine sometimes but the example is poorly chosen. If the department gains a name and a manager, using __iter__ makes much less sense. And now you also need to implement __len__ if you want to count your employees, etc.
- IgorPartola 13y agoAnd possibly allow indexing: `department[3]`. Yeah, I don't like that. It's not clear whether it's a generator or a full sequence. Generators when you don't expect them are evil (you cannot iterate over them twice). I would much rather see something like department.get_employees() and department.iget_employees() that return a tuple and a generator respectively.
- mercurial 13y agoThat's the sort of things people used(?) to complain about C++: gratuitous operator overloading. It sometimes makes sense, but you really need to think long and hard about the semantics.
- pak 13y ago`highlight = reverse` also flies in the face of TOOWTDI (from PEP 20). Which is a shame, because this means that convenience methods that Ruby has, e.g. ary.first → ary[0], ary.compact → ary.reject{|x| x.nil? }, ary.map → ary.collect are pruned out of the stdlib and frowned on in contributed libraries. This chilling effect that descends from PEP20 is one of the worse aspects of Python. They increase readability and should be encouraged. Even if ary.last is one more character, it uses less of my brain to read than ary[-1]. ary.map might be more readable if other code uses ary.reduce, while ary.collect is more readable if other code uses ary.inject, ary.detect, etc. The OP gave a perfect example with this---in an event handler for a drag operation within an editor, I'd rather communicate that text is being .highlight()-ed, even if the underlying view methods are reversing the pixels. If I used .reverse(), it might confuse a coder into thinking the text itself is being reversed when I drag. Perhaps if more Pythonistas consider this a "best practice," it will swing favor for amending the Zen. But I wouldn't bet on it. Also, you're incorrect about help(). help(Foo.highlight) will provide the docstring for Foo.reverse if Foo.highlight = Foo.reverse.
- simon_weber 13y agoMany of these tips address the idea that good naming improves readability. I couldn't agree more! If you're looking for more on this topic, Brandon Rhodes gave an excellent talk on this at PyCon US last year [0]. [0] http://pyvideo.org/video/1676/the-naming-of-ducks-where-dynamic-types-meet-sma http://pyvideo.org/video/1676/the-naming-of-ducks-where-dyna....
- binarysolo 13y agoCommenting to save for later reading. :)
- maxerickson 13y agoIf you go to your user page: https://news.ycombinator.com/user?id=binarysolo https://news.ycombinator.com/user?id=binarysolo One of the links is 'Saved stories'. That's every story you vote up.
- SoftwareMaven 13y agoHaving gone through a couple thousand lines of Javascript that adhered to the "keep methods small", I call bollocks on that. Make methods as big as they need to be. function doFooOnList(l) { for (var i=0; i<l.length; i++) { doFoo(l[i]); } } function doFoo(i) { i.foo(); } gets old, very quickly. After designing and building code for 20+ years, I can comfortably say that there are no arbitrary rules of software design, and some of the worst code I've seen has been a result of following "best practices" instead of thinking for oneself. Write code like it is meant to be read, because that's what happens most often.
- hiisi 13y agoI'd say methods should be small enough so that their intent is clear. Usually it means that methods should have exactly one responsibility, otherwise they seem bloated.
- jcampbell1 13y agoYou are calling bollocks on a claim he doesn't make.
- nine_k 13y ago`for (var i=0; i<l.length; i++)` is so 1970. In Javascript, you have array.map and $.each, and can define functions in-place. Same applies to Python, BTW; get used to list comprehensions and generators and you cannot look back.
- gnaritas 13y ago
- Jiliwang 13y agoVery learnsome, Thanks!
- frodopwns 13y agoNot enough explanation as to what problems are being solved or why your solutions are "best practices".
- deleted 13y ago[deleted]
- abecedarius 13y agoFor the 'method object' one, I use nested functions. Python is not Java or Smalltalk. The @classmethod example I'd write with an ordinary function also, outside the class.