Python Language Features and Tricks(sahandsaba.com) |
Python Language Features and Tricks(sahandsaba.com) |
I'm also not ashamed to say that despite having written quite a few LOC of Python I wasn't aware of named slices for some reason and I think they can clear up some chunks of code I have produced (make it more readable)
There's always tricks to learn, and it's hard to remember everything when you're first starting out with a new language.
(I've been using python for many years, but not full time. It's the language I use for one-off scripts, small tools that make use of its handy standard library, or prototypes for things I'm going to write in some other language. That's my excuse for the gaps in my knowledge.)
I wasn't either. But I wouldn't call them a hidden feature of the language. A slice object is an object. So you can make it the value of a named variable, just like any other object. Somehow that wasn't obvious, though.
Now I'm wondering how else I might be able to improve my code by giving names to non-obvious things.
# let i = (1,2,3) ;;
val i : int * int * int = (1, 2, 3)
# let a,b,c = i;;
val a : int = 1
val b : int = 2
val c : int = 3
I believe Python supports pattern matching other than Regex as well.
One thing that strikes odd for me is how people describe Python/Ruby are way more readable than Java.
I felt that Python, while more readable than Ruby (because Python uses less symbols), still contain more nifty tricks compare to Java.
It's true that the resulting code is less code but behind that less line of code bugs might linger around because there might be plenty "intents" being hidden deep in the implementation of Python.
The Python way that is touted many times is "explicit is better than implicit" seems to correlate better with the much maligned "Java is too verbose".
Anyhow, the other day I was refreshing my Python skill and learned the default implicit methods that I can override ( those eq, gte, gt, lte, lt) and I wonder how overriding those resulted in less lines of code compare to Java overriding equals, hashCode, and implementing one Comparator method than can return -1, 0, 1 to cover the whole spectrum of gte, gt, lte, (and even equality, given the context).
I suppose everything is relative...
Instead of
mi = dict(zip(m.values(), m.keys()))
Do mi = {v: k for (k, v) in m.iteritems()} mi = dict((v,k) for k,v in m.iteritems())1. I'm unfamiliar with the term 'unpacking'. Is it any different from pattern matching in, say, Haskell (but perhaps not as feature-rich)?
2. Aren't slices pretty much a staple in Python? I didn't think using them was considered a 'trick'.
unpacking < destructuring < pattern matching < first-class patterns
where first-class patterns are increasingly becoming available in some languages which offer pattern matching (in particular, Haskell will have them soon). a,(b,c),d = [1,[2,3],4]I'll also think about the "collection of simple examples" next time I want to document something.
I just bookmark the HN discussion. Not only does that retain a link to the tutorial, but it also retains a link to a discussion that usually adds value to the tutorial.
I'm assuming that HN discussions remain available for many years. Anyone know for sure if that is/isn't true?
1.29 happened to be exactly what I was looking for:
for subset in itertools.chain(*(itertools.combinations(a, n) for n in range(len(a) + 1)))
I spent way too much time writing a function to come up with these combinations. itertools.chain.from_iterable(itertools.combinations(a, n) for n in range(len(a) + 1))I believe in 2.7 zip is still returning a list rather than an iterator (izip in Python 2, zip in Python 3+).
Another unappreciated stdlib is definitely functools. mock is also another awesome stdlib.
functools, collections and itertools are definitely useful to make things faster. Also check out the list of stdlib. http://docs.python.org/2/library/
Just remember that for positive indices, len(slice(n,m)) == m - n
I don't understand how this one to flatten lists works:
a = [[1, 2], [3, 4], [5, 6]]
[x for l in a for x in l]
Can somebody explain what the order of operations is here and what the variables refer to in the various stages of evaluation? x = [[1,2], [3,4], [5,6]]
[x for x in x for x in x]
More perversely, we can also flatten with my invention: list(None for x in x if (yield from x) and False) # Python >=3.3
More reasonably, of course, list(itertools.chain.from_iterable(x)) result = []
for l in a:
for x in l:
result.append(x)Obviously not, after all I did say "I know bugger all Python".
I did know about slices.
Wake me up when Python will support tail call elimination and will get rid of GIL. For now this language is no better than PHP.
For the GIL, there are alternative implementations of Python (Jython, IronPython, etc.)
It's too bad it's apparently not good for... whatever it is you do. It is pretty great for some things, and having spent more than a few years with both Python and PHP, I can say without reservation that there is absolutely no comparison in terms of language quality.
[0] http://paulgraham.com/avg.html
[1] http://c2.com/cgi/wiki?BlubParadox
[2] http://weblog.raganwald.com/2006/10/are-we-blub-programmers....
I do prefer Ruby to Python though. I much prefer monadic enumerators combined with lambdas to list comprehensions, even though these tend to be eager in Ruby but have the option of being lazy in Python. Itertools helps, but is deeply hampered by Python's overly verbose lambda syntax.
By symbol I mean the use of tilda, pound sign, ampersand colon.
Seems to me that it's more of personal preference than anything else and this is why for me personally, Ruby is pretty close to Perl.
Somehow I prefer verbose than too terse. I prefer to read the code in words than in mix of words and symbols.
I think comparisons about readability aren't very useful (they are subjective, 'enough' counts), but I sure like the relative terseness of Python (to the point that I lament people who come over and write Java in Python (I don't mean to direct that at you, it's just a thing that happens, where people don't take advantage of things that are very idiomatic and thus clear even when terse)).
There's similar thing re eq/gte/etc for Python. Particulars escape me at the moment.
Writing some C will cure that disease, but the treatment has possible side effects, like carpal tunnel syndrome.
It seems you have read some generic criticism of Python to copy from, and don't have much first-hand experience
Really enjoy his style as well :)
php > $t = array(1, 2);
php > list($a, $b) = $t;
php > echo "$a, $b";
1, 2I think that Python's unpacking allows most, if not all, of Clojures sequence destructuring for tuples and lists. Clojure takes it a bit further, however, by applying it to all sequences. For example, you could do this:
a,b,c = "XYZ"
because strings are also sequences. You can also do something like this (excuse the awkward syntax as I try to express it in pseudo-Python): a,b : c as d = [1,2,3,4,5]
# a = 1
# b = 2
# c = [3, 4, 5]
# d = [1, 2, 3, 4, 5]
This might not be so useful in python, since the list already is d and c is simply slicing the end from the list, but Clojure allows you to destructure function arguments: (defn foo [[a, b & c :as d]] ...) when passed the above list (foo [1 2 3 4 5]) would bind the variables as shown in the above comments.Where destructuring really shines, though, is that you can destructure maps (dictionaries in Python) and vectors can also be treated as maps (their keys are the indices), so you can do stuff like this:
a, {[b {:keys [c, d]} :foo}, e = [1, {foo: [2, {c: 3, d: 4}, bar: 9}, 5]
# a = 1
# b = 2
# c = 3
# d = 4
# e = 5
http://clojure.org/special_forms#binding-formshttp://neopythonic.blogspot.co.uk/2009/04/final-words-on-tai...
Is Guido's take on it.
Essentially, as I understand it, his take is that massive recursion is confusing, and 'unpythonic'. And with the whole 'explicit is better than implicit' thing, I guess there is a point.
Some times recursion is the best/most obvious solution, and then it is a bit annoying to not have TCO, but you can usually work around it.
import sys
sys.setrecursionlimit(x)
Kind of a "hackish" way to do things but you can do it if you need to.
For example, 1000 levels of recursion is more than enough to count all the nodes in a binary tree unless the tree is extremely poorly balanced or inordinately large.
I see now that the Python docs explain this very clearly...
> I believe Python supports pattern matching other than Regex as well.
That's pattern matching on strings. The kind of pattern matching being discussed here is pattern matching on data types (see [1]).
It doesnt have functional style pattern matching though.
That's the haskell extension.
To see a very nice use of them, check out this paper (pdf) http://strictlypositive.org/CJ.pdf
I spoke too eagerly—the new feature is just named and namespaced patterns. It's a bit of a bump in power, but it's not fully general yet.
For true(-ish) first-class patterns take a look at Prisms in the lens package or some of the other first-class pattern libraries.
I think it's a lack of naming convention - the word "list" on its own means "strict list" in some languages and "lazy list" in others.
What does this have to do with anything? If the construct was defined as lazy, then it would be just as explicit. There is nothing about generator expressions that says "here, here, this is lazy".