* 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
for each in enumerate(items):
if each.match(self):
# This fails because enumerate yields an (index, value) tuple.
# Match isn't a function defined on tuples.So methods that mutate state, and don't return None are un-Pythonic?
What about this example:
a = [1, 2, 3]
b = a.pop()
pop() mutates the state of a and returns a value that is not None. Is the Python code language itself un-Pythonic?I'm curious, as someone who uses this pattern quite a bit, how would you improve on this?
> if a method does not use the object's state (no `self` usage) make it a `class-` or `staticmethod`.
Uh, that's a little too "cookbook" for my tastes. The decision of whether to make something a class / static method or not should be decided based on what the function is doing, rather than some pointless dogma. I'm assuming he means this method:
> def alarm(self): > with open(BUZZER_MP3_FILE) as f: > play_sound(f.read())
It's a design decision, and one that is particularly trivial at that. Let's say the effects an alarm ultimately change, resulting in an internal state read / write on the object. Now you have to go back and update the class despite the fact that it at a higher philosophical level one could argue that an alarm should only be triggered on an individual boiler.
Point being: it's nit-pickery for nit-pickery's sake. I don't personally use `return None`, but it's certainly more explicit and is fine to use if your judgment has found it to make sense.
For example, when looking through someone elses code, if it does not have deep levels of nesting I prefer longer methods you can read like a script rather than having to jump around the place to see what is each method.
Likewise with the 80 character guideline in PEP. It can take a lot longer to find the closing brace if it is hidden in columns that look like a newspaper article.
What I really disliked is storing intermediate results of a multi-stage computation in instance variables. It is so easy to return multiple values from Python functions. Also, thinking what you need and need not pass and return between interconnected functions helps structure them much better, into smaller, clearer pieces (as #1 correctly advises).
simply `return` would be enough
Is this really true?
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.
Correct, and if you do that, methods will invariably end up small. What you cite above is small no matter how you write it, so that's not the point of the advice to keep methods small. Methods pretty much never need to be long; they're long because they're poorly written code. Well written code tends towards small methods.
If you'd said "usually", I'd have agreed with you, but "invariably" is far too strong. Sometimes the logic you need to implement is fundamentally complicated, and so the code you write to implement it must inevitably be at least that complicated. If that means writing a 100 line function, but the function really is doing one job, at one level of abstraction, in a cohesive way, then so be it.
Very very true. This phrase suggests there is no better way to do something, and that it should always be used because it is "best", and the dogmatic application of rules replaces actual thought and understanding. I am not against a "recommendation" or "suggestion", but to call it "best practice" is cargo-cult-like.
Same applies to Python, BTW; get used to list comprehensions and generators and you cannot look back.
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.
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.
This has nothing to do with whether it's a good idea. If you read a lot of python code, the latter is easier to grok. And when you have separate ways of doing things, it takes a longer and longer time to absorb those idioms and internalize them to the point where you don't need to think. Adding a bunch of "convenience" methods that do minor permutations on common operations might read better when a line of code is given as an isolated example, because it can read more like an english sentence. But when you're reading over code, the resemblance to english only helps when you're looking at application code which isn't a part of the language or standard library. Having the language and standard library present a single way to do things makes it easier to get to a base level of familiarity.
Endless variety in doing simple things doesn't buy you much.
That being said, the python stdlib is full of stuff built up over many years, so it doesn't follow that idea everywhere. Also, higher level design is never going to fit into the TOOWTDI concept because things at that level are more subjective.
> Also, you're incorrect about help(). help(Foo.highlight) will provide the docstring for Foo.reverse if Foo.highlight = Foo.reverse.
That's what I was trying to say. When doing help(Foo.highlight) I want it to say something like "Event handler for highlighting text", not "Reverse pixel color for the given rectangle."
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! def is_file_for(is_nagyker, type):
return any([
type == KIS_ES_NAGYKER,
type == KISKER and not is_nagyker,
type == NAGYKER and is_nagyker])
I know unsolicited code improvements from strangers isn't the coolest thing in the world, but `any` (and `all`) can really improve clarity for stuff like this. I know I use them quite a bit. 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)* 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?
from contextlib import contextmanager
@contextmanager
def tag(name):
print "<%s>" % name
yield
print "</%s>" % name
with tag("h1"):
print "foo"
"""
<h1>
foo
</h1>
""" @contextlib.contextmanager
def manager(*args):
object = initialize(args)
try:
yield object
finally:
# cleanup
object.close()These patterns come from a talk by Vladimir Keleshev, author of docopt and excellent Pythonista. These are NOT my original work.
http://stackoverflow.com/questions/1275646/python-3-and-stat...
I would absolutely love a version of shedskin that moved to Python3 syntax and used optional typing.
def get_error_message(error_code: int) -> string:
...
and use them for autocompletion hints and type warnings.https://news.ycombinator.com/user?id=binarysolo
One of the links is 'Saved stories'. That's every story you vote up.
The @classmethod example I'd write with an ordinary function also, outside the class.
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-dyna....