Blog
Python: Non-standard use of dot operator
- Details
- Category: Python
- Written by Tigran G. Saluev
In PHP, there is a special . operator to concatenate strings. Of course, we aren't going to do that in Python; it is sort of weird. Instead of that, let's try to solve a legendary NumPy problem: how to distinguish element-wise array multiplication from matrix-matrix 'row-by-column' multiplication? We already know that the first thing is done like A * B
, and the second like A.dot(B)
, or like weird A @ B
construction in Python 3.5 draft. Well, let's see some code:
import inspect class Matrix(object): def __getattr__(self, which): frame = inspect.stack()[1][0] # we assume stack is deeper than 1 here locals = frame.f_locals if which in locals: return 'matvec' # return matrix-matrix multiplication result here else: return super(Matrix, self).__getattr__(which) a = Matrix() b = Matrix() print(a.b) # outputs 'matvec'! print(a.c) # raises AttributeError!
What's going on? An awesome thing about Python is that it gives access to the whole execution stack, including local and global namespaces for each frame. We just take the frame operator . was called from, find an element with the requested name, and 'multiply' our matrix by it. If there is no element with such name, we just return regular attribute.
So, it is just a little smart trick to implement an exotic behavior of dot operator. Enjoy using, if only you are brave enough!
Python is awesome.
Add a commentPython: Adding a Method to Both Instances and Classes
- Details
- Category: Python
- Written by Tigran G. Saluev
Have you ever wondered how to create a method that could be called for both a type object and it's instances? It is unachievable with class/static methods and metaclasses at all. But here is a simple solution.
import new class mutualmethod(classmethod): # subclassing classmethod! """mutualmethod(function) -> method Convert a function to be a mutual method, i. e. a method that can be called for both class object and it's instances. A mutual method receives the class or it's instance as it's first argument. """ def __get__(self, obj, t = None): if t is None: # I wonder what should I do in this situation. # Please leave a comment if you can explain! raise NotImplementedError if obj is None: # creating a method bounded to the type object return new.instancemethod(self.__func__, t, type(t)) else: # creating a method bounded to an instance return new.instancemethod(self.__func__, obj, t)
And here are some usage examples:
class A(object): @mutualmethod def myrepr(self): if isinstance(self, type): pass # you can handle type objects here else: pass # you can handle type instances here return repr(self) a = A() a.myrepr() # '<__main__.A object at 0x666666f>' A.myrepr() # "<class '__main__.A'>"
And a bit more comprehended example:
class HTMLNode(object): @mutualmethod def pseudo_selector(self, which): if isinstance(self, type): return '.%s:%s' % (self.__name__, which) else: return '#%r:%s' % (id(self), which) class div(HTMLNode): pass my_element = div() my_element.pseudo_selector('hover') # '#31415926:hover' div.pseudo_selector('hover') # '.div:hover'Add a comment
Python Code Snippets
- Details
- Category: Python
- Written by Tigran G. Saluev
Here I will keep some code that I could add to any of my projects as some utility
module.
Iteration tools
Besides the itertools
module itself, there is a big collection of recipes right in the official Python documentation. But I still wish to introduce some utility functions here.
import operator def split_by_condition(condition, iterable): """split_by_condition(function or None, sequence) -> \ pair of lists, tuples, or strings Split sequence into two subsequences by condition and return them. """ if condition is None: not_condition = operator.not_ else: not_condition = lambda item: not condition(item) t = filter(condition, iterable) f = filter(not_condition, iterable) return t, f def filter_element(element, iterable): """filter_element(object, iterable) -> list, tuple, or string Delete all occurrences of object in iterable and return new one.""" # this is surely not a big deal, of course. # but take a look at this incredibly clear and simple solution: return filter(element.__ne__, iterable) # well, it actually doesn't work in 100% of situations because # sometimes `__ne__` raises NotImplementedError.
Math
from math import copysign, pi, atan2 from numbers import Number from operator import mul # sign function. I wonder why there aren't any in Python. def sign(x): """sign(x) Return integer 1 or -1 depending on the sign of x. """ return int(copysign(1, x)) # `prod` function, brother of `sum`. def prod(iterable, start=1): """prod(sequence[, start]) -> value Returns the product of a sequence of elements, beginning with the value of parameter 'start' (which defaults to 1). When the sequence is empty, returns start.""" return reduce(mul, iterable, start) # WARNING: `reduce` is in `itertools` module in Python 3 # function finding cardinal direction name. def cardinal_direction(dx, dy): """cardinal_direction(dx, dy) Returns initials of cardinal direction pointed by (dx, dy). Usage examples: >>> cardinal_direction(1, 1) 'NE' >>> cardinal_direction(-1, 1) 'NW' """ angle = atan2(y, x) angle_idx = int(4. * angle / pi + 8.5) % 8 return ['E','NE','N','NW','W','SW','S','SE'][angle_idx] # now i'm going to introduce the shortest vector math class possible. # if you wish to use some vector math but don't want to depend on NumPy - # this is the solution. from numbers import Number import operator # some accessory decorators first. def _vectorize(op, name=None, doc=None): def fn(self, other): if isinstance(other, Number): return vector(op(item, other) for item in self) else: return vector(map(op, self, other)) fn.__name__ = name or op.__name__ fn.__doc__ = doc return fn def _reverse(op): return lambda *args: op(*args[::-1]) class vector(tuple): """The simpliest vector class possible. Supports basic vector-vector and vector-number arithmetical operations. """ __add__ = _vectorize(operator.add, '__add__') __sub__ = _vectorize(operator.sub, '__sub__') __mul__ = _vectorize(operator.mul, '__mul__') __div__ = _vectorize(operator.div, '__div__') __radd__ = _vectorize(_reverse(operator.add), '__radd__') __rsub__ = _vectorize(_reverse(operator.sub), '__rsub__') __rmul__ = _vectorize(_reverse(operator.mul), '__rmul__') __rdiv__ = _vectorize(_reverse(operator.div), '__rdiv__') # add any operations you wish here. def __abs__(self): """Computes euclidian length of a vector.""" return sum(abs(item) ** 2 for item in self) ** 0.5 def transpose(self): # yep, it works on matrices as well return vector(map(vector, zip(*self)))
Strings
import re # this is promising def split_by_capitals(s): """"split_by_capitals(S) -> string Return a copy of the string S with all case changes padded with spaces. >>> split_by_capitals('HiThere') ... 'Hi There'""" words = re.findall('[A-Z][^A-Z]*', s) return ' '.join(words) def decapitalize(s): """decapitalize(S) -> string Return a copy of the string S with its first character lowercase.""" return s[:1].lower() + s[1:] def untitle(s): """untitle(S) -> string Return an untitlecased version of S, i. e. words start with lowercase characters, all remaining cased characters keep their case.""" words = s.split(' ') words = map(decapitalize, words) return ' '.join(words)
Miscellaneous
def superposition(f, g, *args): """superposition(callable1, callable2, ...) -> function Create a function implementing superposition of arguments.""" def result(*args, **kwargs): return f(g(*args, **kwargs)) result.__name__ = '%s * %s' % (f.__name__, g.__name__) if args: result = superposition(result, *args) return result
Add a comment
Singletons and Other Unique Objects in Python
- Details
- Category: Python
- Written by Tigran G. Saluev
A brief depiction of the problem. As I was developing a backend for my Python game, I created a class for game objects which could create them from database records (in my case, MongoDB documents) and embed into the game core. And then I faced the problem of uniqueness of my objects. With many clients connecting to the backend, it is possible that some objects could be requested from database multiple times. But if I had allowed to create multiple objects for same entity, I would have surely encountered problems in my game logic.
I could surely create some dict which could contain references to created objects, but how to do that in a nice way? Here is the solution I've came to.
I have already wrote that metaclasses are awesome pythonic tool that allows to change completely object creation logic. Python __new__
methods can't do that. Consider the following code:
class A(object): objects_by_unique_data = {} def __new__(cls, data): if data in cls.objects_by_unique_data: return cls.objects_by_unique_data[data] else: result = object.__new__(cls) cls.objects_by_unique_data[data] = result return result def __init__(self, data): print "Hi there! I'm doing stuff!"
Yeah, you can save some memory using this. But actually __init__
method will run every time you create an object, even if the data is doubled. So what can we do?
Here is the solution using Python metaclasses.
from weakref import WeakValueDictionary class metaA(type): def __call__(self, data): if data in self.objects_by_unique_data: return self.objects_by_unique_data[data] else: result = type.__call__(self, data) self.objects_by_unique_data[data] = result return result class A(object): __metaclass__ = metaA objects_by_unique_data = WeakValueDictionary() #def __new__(...) - not needed! def __init__(self, data): print "I am now sure I'm unique. ^__^"
So, the call to A(...)
itself is redefined! There is no need in __new__
at all now, as all the work is done in type(A).__call__
. Also note use of WeakValueDictionary
. This dictionary contains auto-deleted weak references to objects, thus your objects will be garbage-collected if you won't need them in your program core. If we used dict
, it would keep the strong references forever, disallowing garbage collector to clean up the house.
Python is awesome.
Add a comment