引用类的方法,而非实例的方法
我正在写一个函数,用来计算一个对象的幂,也就是说,给定一个数a和一个指数n,返回a的n次方。因为a不一定是内置类型,所以这个函数接受一个关键字参数,用来执行乘法。如果没有提供这个参数,默认会使用对象的__mul__
方法,也就是对象本身应该有乘法的定义。这部分其实比较简单:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
if mul is None :
mul = lambda x,y : x*y
问题在于,在计算a的n次方的过程中,会有很多中间的平方计算,而通常有更高效的方法来计算这些平方,而不是简单地把对象自己乘以自己。我们可以很容易地定义另一个函数来计算平方,并把它作为另一个关键字参数传入,像这样:
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
但问题来了,如果计算平方的函数不是一个独立的函数,而是被幂运算的对象的方法,这样做是很合理的。对此,我想到的唯一方法是这样的:
import inspect
def bin_pow(a, n, **kwargs) :
mul = kwargs.pop('mul',None)
sqr = kwargs.pop('sqr',None)
if mul is None :
mul = lambda x,y : x*y
if sqr is None :
sqr = lambda x : mul(x,x)
elif inspect.isfunction(sqr) == False : # if not a function, it is a string
sqr = lambda x : eval('x.'+sqr+'()')
虽然这样可以实现,但我觉得这种方式非常不优雅……我对面向对象编程的掌握有限,但如果能让sqr指向类的方法,而不是实例的方法,那我就可以用类似sqr = lambda x : sqr(x)
,或者sqr = lambda x: x.sqr()
的方式来实现。这能做到吗?有没有其他更符合Python风格的方法?
5 个回答
如果你想调用类里的方法,而不是实例(可能被重写过的)里的方法,你可以这样做:
instance.__class__.method(instance)
而不是这样:
instance.method()
不过我不太确定这是否是你想要的。
这是我会做的:
import operator
def bin_pow(a, n, **kwargs) :
pow_function = kwargs.pop('pow' ,None)
if pow_function is None:
pow_function = operator.pow
return pow_function(a, n)
这是最快的方法。你也可以看看 object.__pow__
和 operator
模块的文档。
现在,如果你想传递一个对象的方法,可以直接传递,不需要用字符串来传递方法名。实际上,尽量不要用字符串来做这种事情,直接使用对象会更好。
如果你想要未绑定的方法,也可以这样传递:
class MyClass(object):
def mymethod(self, other):
return do_something_with_self_and_other
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
如果你想要类的方法,那就直接传递它:
class MyClass(object):
@classmethod
def mymethod(cls, x, y):
return do_something_with_x_and_y
m = MyClass()
n = MyClass()
bin_pow(m, n, pow=MyClass.mymethod)
你可以用实例作为第一个参数来调用未绑定的方法:
class A(int):
def sqr(self):
return A(self*self)
sqr = A.sqr
a = A(5)
print sqr(a) # Prints 25
所以在你的情况下,其实你不需要做什么特别的,只需要这样做:
bin_pow(a, n, sqr=A.sqr)
要注意,这种方式是早绑定的,也就是说,如果你有一个子类B重写了sqr方法,调用时仍然会执行A.sqr方法。要实现晚绑定,你可以在调用的地方使用一个lambda表达式:
bin_pow(a, n, sqr=lambda x: x.sqr())