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, 开发者_StackOverflow社区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.
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
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
You can do
import types
if isinstance(d, types.FunctionType):
print "<function %s>" % d.__name__
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
精彩评论