Python 引用类';方法,而不是实例';s

Python 引用类';方法,而不是实例';s,python,Python,我在写一个函数,对一个对象求幂,即给定a和n,返回一个。由于a不需要是内置类型,因此该函数接受一个执行乘法的函数作为关键字参数。如果未定义,则默认为objects\uuuu mul\uuu方法,即预期对象本身已定义乘法。这部分很简单: def bin_pow(a, n, **kwargs) : mul = kwargs.pop('mul',None) if mul is None : mul = lambda x,y : x*y 问题是,在计算a的过程中,有很

我在写一个函数,对一个对象求幂,即给定a和n,返回一个。由于a不需要是内置类型,因此该函数接受一个执行乘法的函数作为关键字参数。如果未定义,则默认为objects
\uuuu mul\uuu
方法,即预期对象本身已定义乘法。这部分很简单:

def bin_pow(a, n, **kwargs) :

    mul = kwargs.pop('mul',None)
    if mul is None :
        mul = lambda x,y : x*y
问题是,在计算a的过程中,有很多中间平方,通常有比简单地将对象本身相乘更有效的方法来计算它们。很容易定义另一个计算平方的函数,并将其作为另一个关键字参数传递,例如:

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+'()')
def bin_or_pow(a, x):
    pow_func = getattr(a, '__pow__', None)
    if pow_func is None:
        def pow_func(n):
            v = 1
            for i in xrange(n):
                v = a * v

            return v

    return pow_func(x)

这确实有效,但我发现这是一种极不公平的做事方式。。。我对OOP的掌握是有限的,但是如果有一种方法可以让sqr指向类的函数,而不是实例的函数,那么我可以使用类似
sqr=lambda x:sqr(x)
,或者
sqr=lambda x:x.sqr()
。这能做到吗?还有其他更具python风格的方法吗?

我知道您要修复的是末尾的sqr位。如果是这样,我建议
getattr
。例如:

class SquarableThingy:
  def __init__(self, i):
    self.i = i
  def squarify(self):
    return self.i**2

class MultipliableThingy:
  def __init__(self, i):
    self.i = i
  def __mul__(self, other):
    return self.i * other.i

x = SquarableThingy(3)
y = MultipliableThingy(4)
z = 5
sqr = 'squarify'
sqrFunX = getattr(x, sqr, lambda: x*x)
sqrFunY = getattr(y, sqr, lambda: y*y)
sqrFunZ = getattr(z, sqr, lambda: z*z)
assert sqrFunX() == 9
assert sqrFunY() == 16
assert sqrFunZ() == 25
我是这样做的:

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)
那是最快的方法。另请参见和模块文档

现在,要传递一个对象方法,您可以直接传递它,无需传递一个带有名称的字符串。事实上,永远不要为这种事情使用字符串,直接使用对象要好得多

如果需要未绑定的方法,也可以传递它:

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)

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

instance.__class__.method(instance)
而不是

instance.method()

但是我不确定这是否是您想要的。

您可以使用实例作为第一个参数调用unbound方法:

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)
class Multable(object):
    def __init__(self, x):
        self.x = x

    def __mul__(self, n):
        print 'in mul'
        n = getattr(n, 'x', n)
        return type(self)(self.x * n)

class Powable(Multable):
    def __pow__(self, n):
        print 'in pow'
        n = getattr(n, 'x', n)
        return type(self)(self.x ** n)

print bin_or_pow(5, 3)
print
print bin_or_pow(Multable(5), 5).x
print
print bin_or_pow(Powable(5), 5).x
请注意,这是早期绑定,因此如果您有覆盖sqr的子类B,那么仍然会调用a.sqr。对于后期绑定,可以在调用站点使用lambda:

bin_pow(a, n, sqr=lambda x: x.sqr())

如果我理解库函数的设计目标,那么您希望提供一个库“power”函数,它将把传递给它的任何对象提升到第n个power。但你也希望为提高效率提供一条“捷径”

设计目标似乎有点奇怪——Python已经定义了mul方法来允许类的设计者将其乘以任意值,以及pow方法来允许类的设计者将其提升到一个极限。如果我在构建这个,我希望并要求用户拥有一个mul方法,我会这样做:

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+'()')
def bin_or_pow(a, x):
    pow_func = getattr(a, '__pow__', None)
    if pow_func is None:
        def pow_func(n):
            v = 1
            for i in xrange(n):
                v = a * v

            return v

    return pow_func(x)
这将允许您执行以下操作:

bin_pow(a, n, sqr=A.sqr)
class Multable(object):
    def __init__(self, x):
        self.x = x

    def __mul__(self, n):
        print 'in mul'
        n = getattr(n, 'x', n)
        return type(self)(self.x * n)

class Powable(Multable):
    def __pow__(self, n):
        print 'in pow'
        n = getattr(n, 'x', n)
        return type(self)(self.x ** n)

print bin_or_pow(5, 3)
print
print bin_or_pow(Multable(5), 5).x
print
print bin_or_pow(Powable(5), 5).x
。。。你会得到

125

在mul中
在mul中
在mul中
在mul中
在mul中
3125

在功率
3125


嗯,也许不是你想要的答案,但是你可以使用内置函数hasattr来检查对象上是否存在方法或属性。用法是hasattr(object,“propertyname”),例如hasattr(1,“mul”)来检查对象是否有乘法运算符。“if inspect.isfunction(sqr)=False”应该读为“if not inspect.isfunction(sqr)”(这更漂亮,也提高了性能)为什么你违反了数字对象的封装?为什么不简单地要求每个对象提供一个合适的mul定义?所有内置的数字类型都提供了这个定义?内置的mul有什么问题吗?我想到了,但问题是pow指向m的pow函数,即它指向inst的函数ance,不是类的。被平方的对象将是与m相同类型的对象,但不是m本身,并且按照您的建议,定义的pow默认将m的self作为第一个参数。我刚刚尝试过它:>>>>a=TestClass(6)>>a.sqr()36>>b=TestClass(12)>>b.sqr()144>>func=a.sqr>>func(b)回溯(最近一次调用last):func(b)TypeError中第1行的文件“”:sqr()正好接受1个参数(给定2个)@Jaime添加了一个使用类方法的例子。这可能会起作用,尽管它需要一个糟糕的用户界面,但可能没有更好的方法来解决它…这就是我想要的…想法是提供一个库函数,可以用于用户的自定义对象。因此,如果他已经用B.sqr覆盖了a.sqr,他应该调用该函数与B.sqr。。。