一个类方法在作为实例方法调用时表现不同吗?
我在想,是否可以创建一个方法,让它在作为类方法调用时和作为实例方法调用时表现得不一样。
举个例子,作为一个提升技能的项目,我正在写一个 Matrix
类(是的,我知道市面上已经有很好的矩阵类了)。我为这个类创建了一个叫 identity
的类方法,它可以返回一个指定大小的单位矩阵。
现在,当这个方法在一个 Matrix 的实例上被调用时,我觉得没必要指定大小;它应该返回一个和被调用的 Matrix
实例大小相同的单位矩阵。
换句话说,我想定义一个方法,能够判断它是通过实例调用的,如果是的话,就能访问那个实例的属性。不幸的是,即使我翻阅了文档和做了一些谷歌搜索,我也没有找到任何表明这可能的线索。有没有人知道其他的情况呢?
编辑:
哇!显然,我还不太习惯一等函数。最后我得到了这个结果——感谢 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
编辑 2:
顺便说一句,这种技术(以及下面大部分介绍的技术)在定义了 __slots__
的类上是行不通的,因为你不能重新分配这个方法。
5 个回答
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
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)
使用上面的内容:
>>> print Foo.bar(5)
6
>>> my_foo = Foo()
>>> print my_foo.bar()
20
40
我擅长一些看起来有点奇怪但其实有用的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