base64 is Python's module for providing various standard encoding functionalities, especially the eponymous base64. Little quirk about the decoding in Python 2.7, it ignores invalid characters!
>>> import base64
>>> test_str = base64.b64encode('123456789')
>>> base64.b64decode(test_str[:-4] + '....' + test_str[-4:])
'123456789'
>>> base64.b64decode(test_str[:-4] + '...' + test_str[-4:])
'123456789'
>>> base64.b64decode(test_str[:-4] + '.' + test_str[-4:])
'123456789'
>>> test_str[:-4]
'MTIzNDU2'
>>> base64.b64decode(test_str[:-4])
'123456'
Python 3 adds a flag, validate, but it's off by default. Oh well!
Kind of like "hey guys, check it out you can just duct tape down the dead-man's switch on this power tool and use it one handed". In Python.
Wednesday, March 4, 2015
Thursday, December 4, 2014
better translate()
translate is a simple, efficient function for doing fast byte-by-byte replacement on a string in Python.
However, Python Does What is always on the lookout for dangerous alternatives to simple things. Instead of a function call, isn't it better to mutate global interpreter state so that the same result is achieved as a side-effect of a completely different operation? (The answer is yes.)
>>> import ctypes
>>> def maketrans(inp, outp):
... inp = list(inp)
... outp = list(outp)
... for aa, bb in zip(inp, outp): # there's a fun reason single letter variable names are a bad idea here
... ctypes.memset(ctypes.pythonapi.PyString_AsString(id(aa)), ord(bb), 1)
...
>>> maketrans("jkl", "xyz")
>>> "".join("jkl")
'xyz'
This method also has application to single character variable names that bears further exploration.
However, Python Does What is always on the lookout for dangerous alternatives to simple things. Instead of a function call, isn't it better to mutate global interpreter state so that the same result is achieved as a side-effect of a completely different operation? (The answer is yes.)
>>> import ctypes
>>> def maketrans(inp, outp):
... inp = list(inp)
... outp = list(outp)
... for aa, bb in zip(inp, outp): # there's a fun reason single letter variable names are a bad idea here
... ctypes.memset(ctypes.pythonapi.PyString_AsString(id(aa)), ord(bb), 1)
...
>>> maketrans("jkl", "xyz")
>>> "".join("jkl")
'xyz'
This method also has application to single character variable names that bears further exploration.
yade (yet another dict extension)
>>> from collections import defaultdict
>>> class TypeDict(dict):
... def __missing__(self, key):
... self[key] = defaultdict(key)
... return self[key]
...
>>>
>>> td = TypeDict()
>>> td[float]['test']
0.0
>>> class TypeDict(dict):
... def __missing__(self, key):
... self[key] = defaultdict(key)
... return self[key]
...
>>>
>>> td = TypeDict()
>>> td[float]['test']
0.0
Tuesday, November 25, 2014
ctypes short string shenannigans
| >>> >>> >>> 42105668 >>> 42105668 >>> 'f' >>> 'ab' >>> 'f' |
import ctypes b_char = 'b' ctypes.pythonapi.PyString_AsString(id(b_char)) ctypes.memset(_, ord('f'), 1) b_char 'ab' 'ab'[1:] |
Single character strings are interned in a special array in CPython. This means mutation to the internals of a single character string will have global consequences.
(http://www.laurentluce.com/posts/python-string-objects-implementation/ has more information.)
Wednesday, November 19, 2014
assignment order
Variable assignment in a chained "=" goes left-to-right.
>>> a = [None]
>>> a[0][0] = a # fails, as expected
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object has no attribute '__getitem__'
>>> a[0] = a[0][0] = a # succeeds
The second form is equivalent to:
>>> a[0] = a
>>> a[0][0] = a
With a bit of code we can explicitly see that the assignments are happening in left-to-right order:
>>> class Squawker(object):
... def __init__(self, name): self.name = name
... def __setitem__(self, key, val): print self.name
...
>>> Squawker("a")[0] = Squawker("b")[0] = 1
a
b
Wednesday, November 12, 2014
what to expect except to accept
Any object can be the target of an except, not just subclasses of BaseException.
>>> try:
... raise Exception("these are all fine!")
... except dict as not_exception:
... pass
... except 42 as not_a_type:
... pass
... except type as super_meta:
... pass
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception: these are all fine!
>>> try:
... raise Exception("these are all fine!")
... except dict as not_exception:
... pass
... except 42 as not_a_type:
... pass
... except type as super_meta:
... pass
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception: these are all fine!
except block types evaluated lazily
>>> try:
... raise Exception()
... except Exception:
... print "OK"
... except doesntexist:
... pass
...
OK
>>>
>>> try:
... raise Exception()
... except doesntexist:
... pass
... except Exception:
... print "OK"
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
NameError: name 'doesntexist' is not defined
... raise Exception()
... except Exception:
... print "OK"
... except doesntexist:
... pass
...
OK
>>>
>>> try:
... raise Exception()
... except doesntexist:
... pass
... except Exception:
... print "OK"
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
NameError: name 'doesntexist' is not defined
Subscribe to:
Posts (Atom)