一种类方法,当作为实例方法调用时表现不同?

Ben*_*ank 26 python methods class

我想知道是否有可能使一个方法在被称为类方法时比在被调用为实例方法时表现不同.

例如,作为一个技能提升项目,我正在编写一个Matrix类(是的,我知道那里已经有非常好的矩阵类).我已经为它创建了一个类方法,它identity返回一个指定大小的单位矩阵.

现在,当调用一个实例Matrix,似乎不需要指定大小; 它应该返回一个与Matrix调用它相同大小的单位矩阵.

换句话说,我想定义一个方法,可以确定它是否是通过实例调用的,如果是,则访问该实例的属性.不幸的是,即使在深入阅读文档和一些Google搜索之后,我也没有找到任何暗示这是可行的.有谁知道不同?

编辑:

哇!显然,我还不太习惯一流的功能.这就是我最终得到的结果 - 感谢Unknown提供密钥!

class Foo(object):
    def __init__(self, bar):
        self.baz = bar
        self.bar = MethodType(lambda self: self.__class__.bar(self.baz), self, self.__class__)

    @classmethod
    def bar(cls, baz):
        return 5 * baz

Foo.bar(3) # returns 15

foo = Foo(7)
foo.bar() # returns 35
Run Code Online (Sandbox Code Playgroud)

编辑2:

只是一个简单的说明 - 这种技术(以及下面介绍的大多数)不适用于定义的类__slots__,因为您无法重新分配该方法.

Unk*_*own 39

有用的Python黑客是我的强项.

from types import *

class Foo(object):
    def __init__(self):
        self.bar = methodize(bar, self)
        self.baz = 999

    @classmethod
    def bar(cls, baz):
        return 2 * baz


def methodize(func, instance):
    return MethodType(func, instance, instance.__class__)

def bar(self):
    return 4*self.baz


>>> Foo.bar(5)
10
>>> a=Foo()
>>> a.bar()
3996
Run Code Online (Sandbox Code Playgroud)

  • Kudos和一个upvote,用于代码示例中的努力,特别是对于"有问题的Python hacks是我的强项"这句话:-) (9认同)

Ben*_*ork 7

[编辑:使用属性是一个更直接的答案; 看John Fouhy的有用评论]

您可以使用描述符来执行您想要的操作:

class cls_or_inst_method(object):
    def __init__(self, class_method, instance_method):
        self.class_method = class_method
        self.instance_method = instance_method

    def __get__(self, obj, objtype):
        if obj is None:
            return self.class_method
        else:
            return lambda: self.instance_method(obj)

def my_class_method(baz):
    return baz + 1

def my_instance_method(self):
    return self.baz * 2

class Foo(object):
    baz = 10
    bar = cls_or_inst_method(my_class_method, my_instance_method)
Run Code Online (Sandbox Code Playgroud)

使用以上:

>>> print Foo.bar(5)
6
>>> my_foo = Foo()
>>> print my_foo.bar()
20
Run Code Online (Sandbox Code Playgroud)


Ale*_*Ale 7

@Unknown你和这之间的区别是什么:

class Foo(object):

    def _bar(self, baz):
        print "_bar, baz:", baz

    def __init__(self, bar):
        self.bar = self._bar
        self.baz = bar

    @classmethod
    def bar(cls, baz):
        print "bar, baz:", baz

In [1]: import foo

In [2]: f = foo.Foo(42)

In [3]: f.bar(1)
_bar, baz: 1

In [4]: foo.Foo.bar(1)
bar, baz: 1

In [5]: f.__class__.bar(1)
bar, baz: 1
Run Code Online (Sandbox Code Playgroud)

  • @Unknown:如果"悬空"`f._bar()`是一个问题,那么只需在`__init __()中使用lambda或嵌套函数定义它.这里的代码直观明显是如何工作的,而另一个解决方案涉及晦涩的Python巫术,更不用说模块可见的顶级函数`methodize()`和`bar()` (4认同)