Python slice 如何区分切片参数和默认参数(例如,x[i:] vs. x[i:None])?

Python slice how to distinguish slice arguments and default arguments (e.g., x[i:] vs. x[i:None])?

假设variable = None,如何以编程方式区分以下切片语法(具有相同的效果)?

obj[variable:]
obj[variable:None]

obj[:variable]
obj[None:variable]

obj[:]
obj[::]
obj[None:None]
obj[None:None:None]

我正在尝试自定义 class __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() Implements TOS = TOS[:].

SLICE+1() Implements TOS = TOS1[TOS:].

SLICE+2() Implements TOS = TOS1[:TOS].

SLICE+3() Implements TOS = TOS2[TOS1:TOS].

所以任何人都可以使用一些内省技巧来分辨不同的语法(inspect, dis, ast, 等)吗?

进一步问题:

如何区分函数中的传入参数和默认参数?例如,

def add(x, delta=1):
    return x + delta

add函数中,我们如何判断它是被调用为add(x)还是add(x, 1)

链接:

[我们可以为 slice 使用一个独特的、不同的默认参数(None 除外)吗?]

https://docs.python.org/2/c-api/slice.html#c.PySlice_New http://www.boost.org/doc/libs/1_39_0/libs/python/doc/v2/object.html#slice_nil-spec

任何 comments/workarounds/hacks 不胜感激!

对于第二部分,确定调用什么函数:

import inspect
>>> def add(a, b=0):
...     return a + b
... 
>>> inspect.getargspec(add)
(['a', 'b'], None, None, (0,))
>>> len(inspect.getargspec(add)[0])
2

给定一个 slice 对象,无法确定使用何种类型的索引表达式来创建它。从 a[:14] 创建的 slicea[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__ 方法被显式调用,这将没有多大帮助,但也许它会满足您的需要。