如何在不修改 class 的情况下使 len() 在 class 的不同实例上使用不同的方法?
How to make len() work with different methods on different instances of a class, without modifying the class?
有没有办法让 len()
在不修改 class 的情况下使用实例方法?
我的问题示例:
>>> class A(object):
... pass
...
>>> a = A()
>>> a.__len__ = lambda: 2
>>> a.__len__()
2
>>> len(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'A' has no len()
注:
A
的不同实例将附加不同的 __len__
方法
- 我无法更改 class
A
您必须在 class 的定义时定义特殊方法:
class A(object):
def __len__(self):
return self.get_len()
a = A()
a.get_len = lambda: 2
print len(a)
没有。 Python总是通过对象的class查找特殊方法。这样做有几个很好的理由,其中之一是 repr(A)
应该使用 type(A).__repr__
而不是 A.__repr__
,这是为了处理 A
而不是 A
的实例] class本身。
如果您希望 A
的不同实例以不同方式计算它们的 len
,请考虑让 __len__
委托给另一个方法:
class A(object):
def __len__(self):
return self._len()
a = A()
a._len = lambda: 2
必须在 class 上定义特殊方法,例如 __len__
(双下划线或 "dunder" 方法)。如果仅在实例上定义,它们将无法工作。
可以在实例上定义非 dunder 方法。但是,您必须通过向其添加包装器将您的函数转换为实例方法,这就是 self
的传递方式。(这通常在访问该方法时完成,因为在 class 是一个 return 包装器的描述符。)这可以按如下方式完成:
a.len = (lambda self: 2).__get__(a, type(a))
结合这些想法,我们可以在 class 上写一个 __len__()
委托给我们可以在实例上定义的 len()
:
class A(object):
def __len__(self):
return self.len()
a = A()
a.len = (lambda self: 2).__get__(a, type(a))
print(len(a)) # prints 2
你实际上可以在你的情况下简化这个,因为你不需要 self
来 return 你的常量 2
。所以你可以只分配a.len = lambda: 2
。但是,如果你需要self
,那么你需要制作方法包装器。
实际上可以不修改 class 基于这个 answer by Alex Martelli:
class A(object):
def __init__(self, words):
self.words = words
def get_words(self):
return self.words
a = A("I am a")
b = A("I am b")
def make_meth(inst, _cls, meth, lm):
inst.__class__ = type(_cls.__name__, (_cls,), {meth: lm})
make_meth(a, A, "__len__", lambda self: 12)
make_meth(b, A, "__len__", lambda self: 44)
print(len(b))
print(len(a))
print(a.get_words())
print(b.get_words())
如果我们运行代码:
In [15]: a = A("I am a")
In [16]: b = A("I am b")
In [17]: make_meth(a, A, "__len__", lambda self: 12)
In [18]: make_meth(b, A, "__len__", lambda self: 44)
In [19]: print(len(b))
44
In [20]: print(len(a))
12
In [21]: print(a.get_words())
I am a
In [22]: print(b.get_words())
I an b
根据链接答案最后一部分的最后一部分,您可以使用 inst.specialmethod
在每个实例的基础上添加任何方法,一旦您使用了 inst.__class__ = type(...
:
In [34]: b.__class__.__str__ = lambda self: "In b"
In [35]: print(str(a))
<__main__.A object at 0x7f37390ae128>
In [36]: print(str(b))
In b
您没有指定您使用的是 Python 2.x 还是 3.x,在这种情况下,这取决于!在3.x,你的问题已经被其他人回答了。在 2.x 中,您的问题实际上有一个简单的答案:停止派生自对象! (当然,如果你按照这种方法,你不能升级到 3.x 直到你找到另一种方法来做到这一点,所以不要按照我的建议去做,除非你没有计划很快升级.)
Type "copyright", "credits" or "license()" for more information.
>>> class A:pass
>>> a=A()
>>> a.__len__ = lambda: 2
>>> len(a)
2
>>>
尽情享受吧:)
有没有办法让 len()
在不修改 class 的情况下使用实例方法?
我的问题示例:
>>> class A(object):
... pass
...
>>> a = A()
>>> a.__len__ = lambda: 2
>>> a.__len__()
2
>>> len(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'A' has no len()
注:
A
的不同实例将附加不同的__len__
方法- 我无法更改 class
A
您必须在 class 的定义时定义特殊方法:
class A(object):
def __len__(self):
return self.get_len()
a = A()
a.get_len = lambda: 2
print len(a)
没有。 Python总是通过对象的class查找特殊方法。这样做有几个很好的理由,其中之一是 repr(A)
应该使用 type(A).__repr__
而不是 A.__repr__
,这是为了处理 A
而不是 A
的实例] class本身。
如果您希望 A
的不同实例以不同方式计算它们的 len
,请考虑让 __len__
委托给另一个方法:
class A(object):
def __len__(self):
return self._len()
a = A()
a._len = lambda: 2
必须在 class 上定义特殊方法,例如 __len__
(双下划线或 "dunder" 方法)。如果仅在实例上定义,它们将无法工作。
可以在实例上定义非 dunder 方法。但是,您必须通过向其添加包装器将您的函数转换为实例方法,这就是 self
的传递方式。(这通常在访问该方法时完成,因为在 class 是一个 return 包装器的描述符。)这可以按如下方式完成:
a.len = (lambda self: 2).__get__(a, type(a))
结合这些想法,我们可以在 class 上写一个 __len__()
委托给我们可以在实例上定义的 len()
:
class A(object):
def __len__(self):
return self.len()
a = A()
a.len = (lambda self: 2).__get__(a, type(a))
print(len(a)) # prints 2
你实际上可以在你的情况下简化这个,因为你不需要 self
来 return 你的常量 2
。所以你可以只分配a.len = lambda: 2
。但是,如果你需要self
,那么你需要制作方法包装器。
实际上可以不修改 class 基于这个 answer by Alex Martelli:
class A(object):
def __init__(self, words):
self.words = words
def get_words(self):
return self.words
a = A("I am a")
b = A("I am b")
def make_meth(inst, _cls, meth, lm):
inst.__class__ = type(_cls.__name__, (_cls,), {meth: lm})
make_meth(a, A, "__len__", lambda self: 12)
make_meth(b, A, "__len__", lambda self: 44)
print(len(b))
print(len(a))
print(a.get_words())
print(b.get_words())
如果我们运行代码:
In [15]: a = A("I am a")
In [16]: b = A("I am b")
In [17]: make_meth(a, A, "__len__", lambda self: 12)
In [18]: make_meth(b, A, "__len__", lambda self: 44)
In [19]: print(len(b))
44
In [20]: print(len(a))
12
In [21]: print(a.get_words())
I am a
In [22]: print(b.get_words())
I an b
根据链接答案最后一部分的最后一部分,您可以使用 inst.specialmethod
在每个实例的基础上添加任何方法,一旦您使用了 inst.__class__ = type(...
:
In [34]: b.__class__.__str__ = lambda self: "In b"
In [35]: print(str(a))
<__main__.A object at 0x7f37390ae128>
In [36]: print(str(b))
In b
您没有指定您使用的是 Python 2.x 还是 3.x,在这种情况下,这取决于!在3.x,你的问题已经被其他人回答了。在 2.x 中,您的问题实际上有一个简单的答案:停止派生自对象! (当然,如果你按照这种方法,你不能升级到 3.x 直到你找到另一种方法来做到这一点,所以不要按照我的建议去做,除非你没有计划很快升级.)
Type "copyright", "credits" or "license()" for more information.
>>> class A:pass
>>> a=A()
>>> a.__len__ = lambda: 2
>>> len(a)
2
>>>
尽情享受吧:)