Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Styling long chains in Python

Tags:

python

I've written a Python API that is "chain based" (similar to jQuery). So I can write:

myObject.doStuff().doMoreStuf().goRed().goBlue().die()

The problem is that I haven't found a way to keep the syntax clean with long chains. In JavaScript I could simply do

myOjbect
   .doStuf()
   .doMoreStuf()
   .goRed()
   .goBlue()
   .die()

but Python has indentation restrictions...

like image 935
Randomblue Avatar asked Jan 11 '12 11:01

Randomblue


3 Answers

Though I wouldn't call it "clean", it is possible to break inside the parenthesis:

myOjbect.doStuf(
   ).doMoreStuf(arg1, arg2
   ).goRed(
   ).goBlue(
   ).die()

Tastes vary though, so I'm putting it in an answer for completeness.

like image 178
Lauritz V. Thaulow Avatar answered Nov 18 '22 23:11

Lauritz V. Thaulow


PEP8-compliant solution: formatting the line

Actually PEP8 says:

Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation. Make sure to indent the continued line appropriately.

So I suppose your code should look like this:

(
    myOjbect
    .doStuf()
    .doMoreStuf()
    .goRed()
    .goBlue()
    .die()
)

Alternative solutions: splitting into separate statements

Judging from the syntax, there are two options possible regarding the values returned by each method call:

  1. Every method (maybe except die(), which is not required, as its result is not being used) returns modified instance (the same instance, on which it was called).
  2. Every method (still, die() is not required to do that) returns copy of the instance on which it was called.

Solution for mutable objects (methods return original instance)

In first case (when returning same instance), the solution to split longer lines into several statements is:

myObject.doStuf()
myObject.doMoreStuf()
myObject.goRed()
myObject.goBlue()
myObject.die()

Real world example involves mutable objects:

my_stuff = []
my_stuff.append('laptop')  # my_stuff == ['laptop']
my_stuff.append('jacket')  # my_stuff == ['laptop', 'jacket']
my_stuff.append('apple')  # my_stuff == ['laptop', 'jacket', 'apple']

(although list.append() does not return anything, just for consistency and for stating explicitly that it is mutable)

Solution for immutable objects (methods return modified copy)

In the second case (when returning copy), the solution to do similar thing is:

myObject = myObject.doStuf()
myObject = myObject.doMoreStuf()
myObject = myObject.goRed()
myObject = myObject.goBlue()
myObject.die()

Real world example involves immutable objects:

name = '-Tadek-'
name = name.strip('-')  # name == 'Tadek'
name = name.lower()  # name == 'tadek'
name = name.replace('k', 'ck')  # name == 'tadeck'
like image 21
Tadeck Avatar answered Nov 18 '22 23:11

Tadeck


myOjbect \
   .doStuf() \
   .doMoreStuf() \
   .goRed() \
   .goBlue() \
   .die()

(I feel sorry for myObject. That all sounds quite painful.)

like image 7
Joe Avatar answered Nov 18 '22 22:11

Joe