stupid awesome python tricks

Post on 14-Apr-2017

118 Views

Category:

Engineering

5 Downloads

Preview:

Click to see full reader

TRANSCRIPT

stupidstupid awesome

stupid awesome pythonstupid awesome python tricks

stupid awesome python tricks stupidstupid awesome python tricks stupid awesome

stupid awesome python tricks stupid awesome pythonstupid awesome python tricks stupid awesome python tricks

stupid awesome python tricks stupid awesome python bryan helmig

# python has... oddities

import sys

print >>sys.stdout, 'hello world!'# hello world!

from __builtin__ import int# ... uh thanks?

from __builtin__ import True as False# uh oh...

from __future__ import braces# ... SyntaxError: not a chance

likes_art = True

# trivia: what am i?where_to_go = likes_art and 'museum' or 'nascar'

# this is another way to do it...where_to_go = ('nascar', 'museum')[bool(likes_art)]

# lazily now!where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]()

# greanevrf - gunax tbq sbe clguba >2.5!# jure_g_tb = 'zhfrhz' vs yvxrf_neg ryfr 'anfpne'

likes_art = True

# trivia: what am i?where_to_go = likes_art and 'museum' or 'nascar'

# this is another way to do it...where_to_go = ('nascar', 'museum')[bool(likes_art)]

# lazily now!where_to_go = (lambda: 'nascar', lambda: 'museum')[bool(likes_art)]()

# ternaries - thank god for python >2.5!where_to_go = 'museum' if likes_art else 'nascar'

# str encoding

print 'hello world!'.encode('rot13')# uryyb jbeyq!

print 'hello world!'.encode('rot13').decode('rot13')# hello world!

print 'hello world!.'.encode('zlib')# x\x9c\xcbH\xcd\xc9\xc9W(\xcf/\xcaIQT(\xc9\xc8...

print 'hello world!'.encode('zlib').decode('zlib')# hello world!

# registering custom str encoding

def register_codec(name, encode=None, decode=None): import codecs if not encode: def encode(val): raise Exception(name + ' does not support encoding') if not decode: def decode(val): raise Exception(name + ' does not support decoding') def codec(searched_name): if searched_name != name: return None return codecs.CodecInfo( name=name, encode=encode, decode=decode) codecs.register(codec)

# custom "reverser" encoding

def reverser(val): return val[::-1], len(val)

register_codec('reverser', encode=reverser, decode=reverser)

print 'hello world!'.encode('reverser')# !dlrow olleh

print 'hello world!'.encode('reverser').decode('reverser')# hello world!

# custom "hail mary" decoder

def hail_mary_decode(val): import chardet result = chardet.detect(val) return val.decode(result['encoding']), len(val)

register_codec('hail_mary', decode=hail_mary_decode)

print '\xe3\x82\xab\xe3\x83\xac\xe3\x83\xb3\xe3\x83\x80'.decode('utf-8')# print '\xe3\x82\xab\xe3\x83\xac\xe3\x83\xb3\xe3\x83\x80'.decode('hail_mary')#

print '\xa5\xab\xa5\xec\xa5\xf3\xa5\xc0'.decode('euc_jp')# print '\xa5\xab\xa5\xec\xa5\xf3\xa5\xc0'.decode('hail_mary')#

# slicing / indexing / keying

print range(10)[0]# 0

print range(10)[0:5]# [0, 1, 2, 3, 4]

print range(10)[::2]# [0, 2, 4, 6, 8]

print range(10)[::-1]# [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

print dict(hello='world')['hello']# world

# deep slicing / indexing / keying

class PassThrough(object): def __getitem__(self, name): # magic method to return syntax args directly return name

pass_through = PassThrough()

print pass_through[1]# 1

print pass_through[1, 2, 3]# (1, 2, 3)

print pass_through['hello world!']# hello world!

# slicing gets weird

print pass_through[:]# slice(None, None, None)

print pass_through[...]# Ellipsis

print pass_through[..., ..., ..., ...]# (Ellipsis, Ellipsis, Ellipsis, Ellipsis)

print pass_through[..., :, ...]# (Ellipsis, slice(None, None, None), Ellipsis)

# abusing slicing

class parens_be_gone(object): # square brackets are better than parens

def __init__(self, func): self.func = func

def __getitem__(self, args): if not isinstance(args, tuple): args = (args,) return self.func(*args)

def __call__(self, *a, **kw): raise Exception('We do not like (), try []?')

# activate slice abuse

@parens_be_gonedef sum_nums(*args): return sum(args)

@parens_be_gonedef shout_it(name): return 'HELLO {}!'.format(name.upper())

print sum_nums[1, 2, 3, 4, 5]# 15

print shout_it['bryan']# HELLO WORLD!

# magic methods

class Roughly(object): def __init__(self, num): self.num = num

def __invert__(self): return '%d ± 10%' % self.num

print ~Roughly(5)# 5 ± 10%

# magic methods continued

class DoublePlus(object): def __init__(self, plusses=0): self.plusses = plusses

def __pos__(self): return DoublePlus(self.plusses + 1)

def __repr__(self): return '%d plusses' % self.plusses

print ++DoublePlus()# 2 plusses

# complementary magic methods for operators

class Man(object): def __add__(self, right_other): if right_other == 'Dog': return 'best buds' return self

def __radd__(self, left_other): if left_other == 'Dog': return 'bestest buds' return self

print Man() + 'Dog'# best buds

print 'Dog' + Man()# bestest buds

# magic methods to act like you aren't using python

class pipe(object): def __init__(self, func): self.func = func

def __ror__(self, other): return self.func(other)

def __call__(self, *a, **kw): return pipe(lambda x: self.func(x, *a, **kw))

# magic methods to act like you aren't using python continued

@pipedef _map(iterable, func): return [func(i) for i in iterable]

@pipedef _filter(iterable, func): return [i for i in iterable if func(i)]

print (range(10) | _map(lambda i: i * 3) | _filter(lambda i: i % 2 == 0) | _map(str))# ['0', '6', '12', '18', '24']

# magic methods for elegant DSLs

class RegexEquals(object): def __init__(self, regex): import re self.regex = re.compile(regex)

def __eq__(self, other): return bool(self.regex.match(other))

class TypeEquals(object): def __init__(self, *tipes): self.tipes = tipes

def __eq__(self, other): return isinstance(other, self.tipes)

# magic methods for elegant DSLs continued

URL = RegexEquals(r'(https?|ftp)://[^\s/$.?#].[^\s]*')NUM = RegexEquals(r'\d+')INT = TypeEquals(int, long)

print 'larry' == URL# False

print 'http://zapier.com/' == URL# True

print '123' == NUM# True

print {'url': 'http://zapier.com/', 'visits': 4} == {'url': URL, 'visits': INT}# True

# magic methods for abuse

class DidYouMean(object): def __getattr__(self, name): if name.startswith('__'): raise AttributeError('No magic did you mean.') from difflib import SequenceMatcher scored_attrs = [ (SequenceMatcher(None, name, attr).ratio(), attr) for attr in dir(self) if not attr.startswith('__') ] sorted_attrs = sorted([ (score, attr) for score, attr in scored_attrs if score > 0.5 ], reverse=True) best_name = next(iter(sorted_attrs), (None, None))[1] if not best_name: raise AttributeError('No "matching" `%s` attribute' % name) return getattr(self, best_name)

# activate magic methods abuse

class SomeModel(DidYouMean): first_name = 'bryan' last_name = 'helmig'

person = SomeModel()

print person.first_name# bryan

print person.furst_name# bryan

print person.address# .. AttributeError: No "matching" `address` attribute

# magic methods for evil

class specialint(int): def __add__(self, right_other): if self == 1 and right_other == 1: return 3 return super(specialint, self).__add__(right_other)

print specialint(1) + 1# 3

__builtins__.int = specialintprint int(1) + 1# 3

print 1 + 1# 2

# literals get coerced way before builtins are referenced... ¯\_( )_/¯ # https://benkurtovic.com/2015/01/28/python-object-replacement.html# http://blaag.haard.se/Using-the-AST-to-hack-constants-into-Python/

# ast / parser

import parser

tree = parser.expr('(a + 1) or {1: "test"}').tolist()print tree# [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] ..# [ ... [3, '"test"'], [27, '}']], [4, ''], ...]

def recurse(val): import token if isinstance(val, int): return token.tok_name.get(val, val) elif isinstance(val, list): return [recurse(v) for v in val] return val

print recurse(tree)# [258, [327, [312, [313, [314, [315, [316, [317, [318, [7, '('] ..# [ ... ['STRING', '"test"'], ['RBRACE', '}']], ['NEWLINE', ''], ...]

# ast tools can be repurposed and practical

def pyson(val): # JSON is lame. Eval is lame. import ast return ast.literal_eval(val)

print pyson('"hello world!"')# hello world!

print pyson("{1234: 'integer keys!'}")# {1234: 'integer keys!''}

print pyson('import json')# ... SyntaxError: invalid syntax

# mini lisp calc

def tokenize(program): return program.replace('(', ' ( ').replace(')', ' ) ').split()

def reshape_tokens(tokens): token = tokens.pop(0) if '(' == token: deep_tokens = [] while tokens[0] != ')': deep_tokens.append(reshape_tokens(tokens)) tokens.pop(0) return deep_tokens try: return int(token) except: return token

program = '(* 2 (+ 3 5))'print tokenize(program)# ['(', '*', '2', '(', '+', '3', '5', ')', ')']

print reshape_tokens(tokenize(program))# ['*', 2, ['+', 3, 5]]

# mini lisp calc continued

import operatorglobal_env = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.div}

def evaluate(tokens, env=global_env.copy()): if isinstance(tokens, basestring) and tokens in env: return env[tokens] elif not isinstance(tokens, list): return tokens else: func = evaluate(tokens[0], env) args = [evaluate(arg, env) for arg in tokens[1:]] return func(*args)

program = '(* 2 (+ 3 5))'print evaluate(read_tokens(tokenize(program)))# 16

# http://norvig.com/lispy.html & http://norvig.com/lispy2.html

top related