Blog

Python: Non-standard use of dot operator

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 comment

Python: Adding a Method to Both Instances and Classes

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

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

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