引用类的方法,而非实例的方法

0 投票
5 回答
598 浏览
提问于 2025-04-15 12:02

我正在写一个函数,用来计算一个对象的幂,也就是说,给定一个数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 个回答

1

如果你想调用类里的方法,而不是实例(可能被重写过的)里的方法,你可以这样做:

instance.__class__.method(instance)

而不是这样:

instance.method()

不过我不太确定这是否是你想要的。

3

这是我会做的:

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)
4

你可以用实例作为第一个参数来调用未绑定的方法:

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())

撰写回答