2

I think is is best explained with an example. Suppose I have a method that calculates the distances between two vectors and prints it. I also want that method to print the distance measure that was used. The distance measure is given to the function by the caller in the form of a callable object. If the callable is an instance of some class, I can provide the __str__ method to make it print out the name of the distance measure. But the callable can also be a function, and I have not found a way to change __str__ in that case. Some code:

def distance(v1, v2, d):
    print d
    dist = d(v1, v2)
    print dist
    return dist

If d is a function, print d will print out something like <function someFunc at 0x1b68830>. How can I change this? Just printing out the name of the function would be fine, since I usually give them readable names.

Björn Pollex
  • 72,744
  • 28
  • 189
  • 274

4 Answers4

2

I don't think functions can be subclassed, which is what you'd need to do in order to change a function's __str__ method. It's much easier to make a class behave like functions (using the __call__ method).

Functions have a func_name attribute, that returns the function's name.

If you choose to use the func_name attribute, then your callable objects would need a func_name attribute too.

Since you've already defined the class's __str__ method, you could make func_name a property to return str(self) like this:

def dfunc(v1,v2):
    return 1

class FooDist(object):
    def __call__(self,v1,v2):
        return 1
    @property
    def func_name(self):
        return str(self)
    def __str__(self):
        return 'My FooDist'


def distance(v1, v2, d):
    print d.func_name
    dist = d(v1, v2)
    print dist
    return dist

distance(1,2,dfunc)
# dfunc
distance(1,2,FooDist())
# My FooDist
unutbu
  • 777,569
  • 165
  • 1,697
  • 1,613
1

You can do

import types
if isinstance(d, types.FunctionType):
    print "<function %s>" % d.__name__
Jochen Ritzel
  • 99,912
  • 29
  • 194
  • 188
1

To get a function's name, see this question. To get a class's name, see this question. Putting them together:

def distance(v1, v2, d):
    if hasattr(d, '__name__'):
        print d.__name__
    elif hasattr(d, '__class__'):
        print d.__class__.__name__
    else:
        print d   # unsure about this case
    dist = d(v1, v2)
    print dist
    return dist
Community
  • 1
  • 1
snapshoe
  • 12,154
  • 1
  • 23
  • 28
0

You can uniformly give both classes and functions your own attributes:

class MyDistanceMeasure:
    name = "mine"
    #...

def another_distance_measure(x,y):
    #...

another_distance_measure.name = "another"

then:

def distance(v1, v2, d):
    print d.name
    # or..
    print getattr(d, 'name', "unknown")

    dist = d(v1, v2)
    print dist
    return dist
Ned Batchelder
  • 345,440
  • 70
  • 544
  • 649