这不是一个真实的世界计划,但我想知道为什么不能这样做。
我正在考虑numpy.r_
对象,并尝试做类似的事情,但只是创建一个类而没有实例化。
整数的简单代码(有一些缺陷)可能是:
class r_:
@classmethod
def __getitem__(clc, sl):
try:
return range(sl)
except TypeError:
sl = sl.start, sl.stop, sl.step
return range(*(i for i in sl if i is not None))
但是当我尝试r_[1:10]
时,我会收到TypeError: 'type' object is not subscriptable
。
当然,代码与r_.__getitem__(slice(1,10))
一起使用,但这不是我想要的。
在这种情况下,我可以做些什么,而不是使用r_()[1:10]
?
答案 0 :(得分:3)
解析obj[index]
的协议是直接在__getitem__
的类型,不中查找obj
方法在obj
上查找方法(如果obj
没有名称为__getitem__
的实例属性,通常会回退到查找类型的方法。
这很容易验证。
>>> class Foo(object):
pass
>>> def __getitem__(self, index):
return index
>>> f = Foo()
>>> f.__getitem__ = __getitem__
>>> f[3]
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
f[3]
TypeError: 'Foo' object does not support indexing
>>> Foo.__getitem__ = __getitem__
>>> f[3]
3
我不知道为什么它会以这种方式运作,但我猜想至少部分原因正是为了防止你想要做的事情;如果每个定义__getitem__
的类使其实例可转换,意外地获得了自己索引的能力,那将是令人惊讶的。在绝大多数情况下,尝试索引类的代码将是一个错误,因此如果__getitem__
方法碰巧能够返回某些内容,那么如果没有被捕获则会很糟糕。
为什么不直接将该类调用为其他类,并将其实例绑定到名称r_
?然后你就可以r_[1:10]
。
答案 1 :(得分:2)
您尝试执行的操作类似list[1:5]
或set[1:5]
=)特殊__getitem__
方法仅适用于实例。
通常做的只是创建类的单个(“单例”)实例:
class r_class(object):
...
r_ = r_class()
现在你可以做到:
r_[1:5]
您也可以使用元类,但这可能不仅仅是必要的。
“不,我的问题是关于课程中的 getitem ,而不是实例”
然后你确实需要元类。
class r_meta(type):
def __getitem__(cls, key):
return range(key)
class r_(object, metaclass=r_meta):
pass
演示:
>>> r_[5]
range(0, 5)
如果您传入r_[1:5]
,您将获得slice
个对象。请help(slice)
获取更多信息;您可以访问key.stop if isinstance(key,slice) else key
等值。
答案 2 :(得分:1)
将__getitem__()
定义为r_
的{{3}}中的常规方法。
答案 3 :(得分:1)
这种行为的原因在于如何查找__getitem__()
之类的特殊方法。
首先在对象__dict__
中查找属性,如果在那里找不到,则在类__dict__
中查找属性。这就是为什么,例如这有效:
>>> class Test1(object):
... x = 'hello'
...
>>> t = Test1()
>>> t.__dict__
{}
>>> t.x
'hello'
类主体中定义的方法存储在类__dict__
中:
>>> class Test2(object):
... def foo(self):
... print 'hello'
...
>>> t = Test2()
>>> t.foo()
hello
>>> Test2.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Test2 instance as first argument (got nothing
instead)
到目前为止,这并不奇怪。然而,当谈到特殊方法时,Python的行为有点(或非常)不同:
>>> class Test3(object):
... def __getitem__(self, key):
... return 1
...
>>> t = Test3()
>>> t.__getitem__('a key')
1
>>> Test3['a key']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'type' object is unsubscriptable
错误消息非常不同。使用Test2,Python会抱怨一个未绑定的方法调用,而使用Test3则会抱怨unsubscriptability。
如果你尝试调用一个特殊的方法 - 通过在对象上使用它的关联运算符 - ,Python不会尝试在对象__dict__
中找到它,而是直接到对象类的__dict__
,如果对象本身是一个类,是一个元类。所以你必须在那里定义它:
>>> class Test4(object):
... class __metaclass__(type):
... def __getitem__(cls, key):
... return 1
...
>>> Test4['a key']
1
别无他法。引用PEP20:应该有一个 - 最好只有一个 - 显而易见的方法。