Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a function which takes a slice?

I would like to write a function in Python which takes a slice as a parameter. Ideally a user would be to be able to call the function as follows:

foo(a:b:c)

Unfortunately, this syntax is not permitted by Python - the use of a:b:c is only allowed within [], not ().

I therefore see three possibilities for my function:

  1. Require the user to use a slice "constructor" (where s_ acts like the version provided by numpy):

    foo(slice(a, b, c))
    foo(s_[a:b:c])
    
  2. Put the logic of my function into a __getitem__ method:

    foo[a:b:c]
    
  3. Give up trying to take a slice and take start, stop and step individually:

    foo(a, b, c)
    

Is there a way to get the original syntax to work? If not, which of the workaround syntaxes would be preferred? Or is there another, better option?

like image 875
user200783 Avatar asked Apr 25 '15 08:04

user200783


People also ask

How do you define a slice function?

Definition and UsageThe slice() function returns a slice object. A slice object is used to specify how to slice a sequence. You can specify where to start the slicing, and where to end. You can also specify the step, which allows you to e.g. slice only every other item.


2 Answers

Don't surprise your users.

If you use the slicing syntax consistently with what a developer expects from a slicing syntax, that same developer will expect square brackets operation, i.e. a __getitem__() method.

If instead the returned object is not somehow a slice of the original object, people will be confused if you stick to a __getitem__() solution. Use a function call foo(a, b, c), don't mention slices at all, and optionally assign default values if that makes sense.

like image 108
gg349 Avatar answered Nov 15 '22 15:11

gg349


Slices make more sense when they're expressed as a slice of something. So, another alternative is to be more object-oriented: create a temporary object that represents your slice of something, and put your function as a method of it.

For example, if your function is really:

foo(bar, a:b:c)

or

bar.foo(a:b:c)

then you can replace this with:

bar[a:b:c].foo()

If bar[a:b:c] already has a different meaning, then come up with a another name baz and do:

bar.baz[a:b:c].foo()

It's hard to give convincing examples without a real context, because you're trying to name related things with names that make intuitive sense, let you write unambiguous code, and are relatively short.

If you're really just writing a function on its own operating on a slice, then either:

  1. Your function modifies a slice, returning a different slice:

    bar[foo(a:b:c)]
    

    If this is the case, whatever valid syntax you choose is going to look a little confusing. You probably don't want to use slices if you're aiming for a broad audience of Python programmers.

  2. Your function really operates on a slice of the integers, so you can make that explicit with a temporary object:

    the_integers[a:b:c].foo()
    
like image 45
Dan Getz Avatar answered Nov 15 '22 17:11

Dan Getz