假设variable = None
,如何以编程方式区分以下切片语法(具有相同的效果(?
obj[variable:]
obj[variable:None]
obj[:variable]
obj[None:variable]
obj[:]
obj[::]
obj[None:None]
obj[None:None:None]
我正在尝试自定义我的类的__getitem__
方法,以[ab]使用切片语法进行高级索引(语法糖(,并希望以不同的方式处理不同的切片语法,因为我需要大量的语法糖......(这可能不是一个好的做法,但只是为了实验......
def __getitem__(self, slice_obj):
# slice_obj will be `slice(None, None, None)` for all
# `obj[variable:]`, `obj[:variable]` and `obj[:]`
我们可以看到使用 dis
库有不同的切片操作码:
https://docs.python.org/2/library/dis.html#opcode-SLICE+0
SLICE+0(( 实现 TOS = TOS[:]。
SLICE+1(( 实现 TOS = TOS1[TOS:]。
SLICE+2(( 实现 TOS = TOS1[:TOS]。
SLICE+3(( 实现 TOS = TOS2[TOS1:TOS]。
那么任何人都可以使用一些内省技巧来告诉不同的语法(inspect, dis, ast,
等(吗?
进一步的问题:
如何分辨函数中的传入参数和默认参数? 例如,
def add(x, delta=1):
return x + delta
在函数add
内部,我们如何判断它被称为add(x)
还是add(x, 1)
?
友情链接:
[我们可以为切片使用唯一的、不同的默认参数(除了 None(吗?
https://docs.python.org/2/c-api/slice.html#c.PySlice_Newhttp://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/object.html#slice_nil-spec
任何评论/解决方法/黑客不胜感激!
给定一个slice
对象,无法确定使用哪种类型的索引表达式来创建它。从a[:14]
创建的slice
与a[None:14]
或文字slice(None, 14)
创建的没有区别。
但是,如果您想变得有点混乱(并且很多不可移植(,那么通过查看父帧中的当前操作码,您可能会获得一些可靠的结果:
import sys, dis
class Moo(object):
def __getitem__(self, i):
parent_frame = sys._getframe().f_back
accessing_opcode = parent_frame.f_code.co_code[parent_frame.f_lasti]
return "This __getitem__ was invoked by way of a %s instruction"
% dis.opname[ord(accessing_opcode)]
这将给出如下结果:
>>> m = Moo()
>>> m[5]
'This __getitem__ was invoked by way of a BINARY_SUBSCR instruction'
>>> m[5:]
'This __getitem__ was invoked by way of a SLICE+1 instruction'
>>> m[:5]
'This __getitem__ was invoked by way of a SLICE+2 instruction'
>>> m[5:5]
'This __getitem__ was invoked by way of a SLICE+3 instruction'
>>> m[:5:]
'This __getitem__ was invoked by way of a BINARY_SUBSCR instruction'
>>> m[1:5:2]
'This __getitem__ was invoked by way of a BINARY_SUBSCR instruction'
显然,如果显式调用您的__getitem__
方法,这将不太有用,但也许它会满足您的需求。
对于确定调用函数的第二部分:
import inspect
>>> def add(a, b=0):
... return a + b
...
>>> inspect.getargspec(add)
(['a', 'b'], None, None, (0,))
>>> len(inspect.getargspec(add)[0])
2