Snakes for Camels

Python 101 for Perl programmers

Why?

Easy to learn

Easy to read

import collections
class Solution:
  def canFinish(self, n, prs):
    m = collections.defaultdict(lambda: collections.defaultdict(set))
    map(lambda pr: m[0][pr[0]].add(pr[1]) or (m[1][pr[1]].add(pr[0])), prs)
    m[2][0].update(set(filter(lambda c: not m[0][c], xrange(n))))
    while m[2][0]:
      v = (lambda x: (m[2][1].add(x) or x))(m[2][0].pop())
      m[2][0].update(filter(lambda o: m[0][o].discard(v) or 
        (not m[0][o] and o not in m[2][1]), m[1][v]))
    return len(m[2][1]) == n
					

Source: https://leetcode.com/discuss/34793/my-10-line-unreadable-python-solution

Focus on productivity

The actual reasons

Lots of platforms/implementations

  • CPython (reference implementation)
  • ActivePython (from ActiveState)
  • IronPython (.NET and Mono platforms)
  • Jython (JVM)
  • Pypy (Python implemented in RPython)

Lots of awesome projects

  • BitTorrent
  • Ansible
  • Calibre
  • Deluge
  • Mercurial
  • Bazaar
  • Trac
  • GNU Mailman
  • OpenERP
  • YUM
  • Portage
  • And several more ...

Job oportunities!

Source: http://www.indeed.com/jobtrends

What is it?

  • Scripting language
  • Interpreted
  • General purpose
  • Multi paradigm (imperative, functional, ...)
  • Dynamically typed

Perl, anyone?

  • Scripting language
  • Interpreted
  • General purpose
  • Multi paradigm (imperative, functional, ...)
  • Dynamically typed

What's really different?

  • Syntax (obviously)
  • Strongly typed
  • Philosophy: TIMTOWTDI vs. "import this"
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
use Acme::this;
The Zen of Perl, by bellaire

Beauty is subjective.
Explicit is recommended, but not required.
Simple is good, but complex can be good too.
And although complicated is bad,
Verbose and complicated is worse.
Brief is better than long-winded.
But readability counts.
So use whitespace to enhance readability.
Not because you're required to.
Practicality always beats purity.
In the face of ambiguity, do what I mean.
There's more than one way to do it.
Although that might not be obvious unless you're a Monk.
At your discretion is better than not at all.
Although your discretion should be used judiciously.
Just because the code looks clean doesn't mean it is good.
Just because the code looks messy doesn't mean it is bad.
Reuse via CPAN is one honking great idea -- let's do more of that!

Credit: bellaire
Source: http://www.perlmonks.org/?node_id=752029

Getting started

Install Python to play around

virtualenv is a tool to to create isolated Python environments


$ virtualenv my_python
Using base prefix '/usr'
New python executable in my_python/bin/python3
Also creating executable in my_python/bin/python
Installing setuptools, pip, wheel...done.

$ source my_python/bin/activate
(my_python)$ which python
/home/mruiz/my_python/bin/python

(my_python)$ deactivate
$ which python
/usr/bin/python
				

Where is my CPAN?!?!

Fear not! PyPI to the rescue
The Python Package Index
The official third-party software repository for Python

Not to be confused with PyPy (the implementation and JIT compiler)

Let's install some shit

pip vs. easy_install

pip ➔ cpanm
easy_install ➔ cpan

pip (2008) easy_install (2004)
Install from Wheels Yes No
Uninstall Packages Yes (pip uninstall) No
Dependency Overrides Yes No
List Installed Packages Yes (pip list) No
PEP438 Support Yes No
Installation format 'Flat' packages Encapsulated Egg
sys.path modification No Yes
Install from Eggs No Yes
pylauncher support No Yes
Multi-version Installs No Yes

Source: https://packaging.python.org/en/latest/pip_easy_install.html

Python vs. Perl: Fight!


use strict;
use warnings;

use feature 'say';
use feature 'signatures';
no warnings 'experimental::signatures';
				

Syntax overview


x = 0
while x < 10:
  print(x)
  x += 1

def sum(x, y):
  return x + y

print(sum(2, 3))
				

my $x = 0;
while ($x < 10) {
  say $x++;
}

sub sum($x, $y) {
  return $x + $y;
}

say sum(2, 3);
				

Types

Python

  • int
  • float
  • str
  • byte
  • dict
  • list
  • set
  • tuple

Perl

  • scalar
  • array
  • hash

Everything's an object


list = ["Objects", "all", "over", "the", "place"]
print('.'.join(list))
list.append('xxx')

dict = {'key1': 'value1', 'key2': 'value2'}
keys = dict.keys()

(1.3).hex()
				

Anonymous functions


anon = lambda x:
  if x > 5:
    raise Exception("Too big")
  else:
    return x ** 2

print(anon(2))
				

my $anon = sub {
  my $x = shift;
  if ($x > 5) {
    die "Too big";
  } else {
    return ** 2;
  }
};
say $anon->(2);
				

anon = lambda x: x ** 2
print(anon(2))
				

Classes


class MyObj(object):

  def __init__(self, value):
    if value > 5:
      raise Exception('Too big')
    self.value = value

  def __add__(self, obj):
    return MyObj(self.value + obj.value)

  def __str__(self):
    return 'odd' if self.value % 2 else 'even'

  def double(self):
    return self.value * 2

a = MyObj(1)
b = MyObj(2)
c = a + b

print(c.value)
print(str(c))
print(c.double())
				

package MyObj;
use Moo;

use overload
  '+'  => \&_add,
  '""' => \&_str;

has value => (
  is => 'ro',
  isa => sub { die "Too big" if shift > 5; },
  required => 1,
);

sub _add {
  MyObj->new({value => shift->value + shift->value});
}

sub _str { shift->value % 2 ? 'odd' : 'even' }

sub double { shift->value * 2 }

1;
				

Other Pythonic cool stuff

Generators (state variables / Coro)


def gen():
    i = 0
    while True:
        yield str(i)
        i = i + 1

x = gen()
for i in range(0, 10):
    print(next(x))
				

use 5.010;

sub gen {
    state $i = 0;
    return $i++;
}

say gen() for (0..9);
				

List comprehensions (map, grep)


list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
squared_even = [x ** 2 for x in list if x % 2 == 0]
				

my @list = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
my @squared_even = map { $_ ** 2 } grep { $_ % 2 == 0 } @list;
				

More stuff

  • built in exceptions (Try::Tiny)
  • built in REPL (re.pl)
  • huge standard library (cpan)

Versioning shitshow

Python 2 vs. Python 3

Perl, anyone?

Perl 5 vs. Perl 6

Versioning shitshow

  • Python 3 released in December 2008
  • Breaks backwards compatibility with Python 2.x
  • No new features will go into 2.x branch
  • 3.x does not offer enough coolness to encourage migration
  • Lots of projects still in 2.x
  • 13779 PyPI ported packages out of 65396 (source: caniusepython3.com)

How to write portable code?

Prepend this to your Python 2 modules


from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
				

Further reading