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)
[编辑:使用属性是一个更直接的答案; 看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)
@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)