Upload
bryan-helmig
View
118
Download
5
Embed Size (px)
Citation preview
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