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.
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.
Thursday, December 4, 2014
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
Tuesday, November 11, 2014
dictzip
def dictzip(*dicts):
return dict([(k, tuple([d[k] for d in dicts]))
for k in set(dicts[0]).intersection(*dicts[1:])])
zip() is a very handy function that takes a series of iterables and returns a list of tuples of the nth elements of each iterable:
>>> zip(['a', 'b', 'c'], [1, 2, 3])
[('a', 1), ('b', 2), ('c', 3)]
dictzip() takes an iterable of dictionaries and returns a dictionary of tuples of the elements of each dict on the same key:
>>> dictzip( {'a': 1}, {'a': 'cat'} )
{'a': (1, 'cat')}
This version is exclusive -- only keys that are in all dictionaries are output. A simple variant would be to substitute None for missing keys.
def dictzip(*dicts):
return dict([(k, tuple([d.get(k) for d in dicts]))
for k in set(dicts[0]).union(*dicts[1:])])
(Adapted from: http://stackoverflow.com/a/16458780)
Friday, May 2, 2014
NullAttributor
Sometimes, you have a deeply nested set of attributes which may not be present somewhere along the chain. A try/except would be clunky.
>>> class Foo(object): pass
...
>>> f = Foo()
>>> f.a = f
>>> f.a.b = f
>>> f.a.b.c.d
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'c'
This is a simple class which allows an expression to be wrapped and unwrapped, with the result at the end being either the value obtained or None.
>>> class na(object):
... '''
... A None-Attributator object. Allows for "safe navigation",
... similar to the ?. attribute in C#, or undefined in JavaScript.
... '''
... __slots__ = ("base",)
... def __init__(self, base):
... self.base = base
... def __getattr__(self, name):
... return na(getattr(self.base, name, None))
... def __getitem__(self, key):
... try:
... return na(self.base[key])
... except (KeyError, TypeError, IndexError):
... return na(None)
... def __call__(self):
... return self.base
...
>>>
>>> na(f).a.b.c.d.e()
>>> na(f).a.b['cat']()
>>> class Foo(object): pass
...
>>> f = Foo()
>>> f.a = f
>>> f.a.b = f
>>> f.a.b.c.d
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'c'
This is a simple class which allows an expression to be wrapped and unwrapped, with the result at the end being either the value obtained or None.
>>> class na(object):
... '''
... A None-Attributator object. Allows for "safe navigation",
... similar to the ?. attribute in C#, or undefined in JavaScript.
... '''
... __slots__ = ("base",)
... def __init__(self, base):
... self.base = base
... def __getattr__(self, name):
... return na(getattr(self.base, name, None))
... def __getitem__(self, key):
... try:
... return na(self.base[key])
... except (KeyError, TypeError, IndexError):
... return na(None)
... def __call__(self):
... return self.base
...
>>>
>>> na(f).a.b.c.d.e()
>>> na(f).a.b['cat']()
Friday, January 10, 2014
loopdefaultdict
Simple idiom for a tree.
>>> import collections
>>>
>>> def loopdefaultdict():
... return collections.defaultdict(loopdefaultdict)
...
>>> d = loopdefaultdict()
>>> d[1][2][3]
defaultdict(<function loopdefaultdict at 0x02B249B0>, {})
>>> d[1][2][3] = "cat"
Edit: wikipedia has an even better version
http://en.wikipedia.org/wiki/Autovivification#Python
>>> import collections
>>>
>>> def loopdefaultdict():
... return collections.defaultdict(loopdefaultdict)
...
>>> d = loopdefaultdict()
>>> d[1][2][3]
defaultdict(<function loopdefaultdict at 0x02B249B0>, {})
>>> d[1][2][3] = "cat"
Edit: wikipedia has an even better version
http://en.wikipedia.org/wiki/Autovivification#Python
Tree = lambda: defaultdict(Tree)
Subscribe to:
Posts (Atom)