Welcome, guest | Sign In | My Account | Store | Cart

If you like obfuscated but powerful Oneliners you will really enjoy this one. It allows to use reverse, sort and extent "on the fly" with tuples, strings or list types. It returns a new instance of the same type as the input type. Extending a tuple results in a new tuple. Sorting a string results in a new string and so on. Thanks to Patrick Maupin since version 1.2 it handles Null-Strings and tuples correctly.

Though the functionality can be expressed in a 290-character "Oneliner" i recommend that you use the longer 15-line code (at the end) as it is more understandable and "pythonic".

Python, 111 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# If you ever wanted to do something like:

for line in open('file').readlines().reverse():
   print line 

# you will have noticed that reverse is an "In-Place" method.
# it modifies the list itself and returns None.
# So the for loop sees just a (non-iterable) None.
# Even worse, you can't use reverse/sort/extend on tuples or strings.
# "hallo".reverse() or (3,1,5).sort() does not exist.  

# The obfuscated oneliner below solves these problems so that
# you can write 

for line in reverse(open('file').readlines()):
   print line # lines of the file in reverse order

# Additionally it allows you to use reverse/sort/extend 
# on tuples and strings and it always maintains Types.

sort([3,7,5])  # gives you a sorted list [3,5,7]

reverse("hallo") # returns reversed string "ollah"

extend( (1,2,3), (4,5) ) # returns (1,2,3,4,5)

# recursion/iteration of course works like usual:

print reverse(sort([7,3,5])) # prints [7,5,3]  

print extend(reverse(range(4)),([42],reverse('32')))
# will give you [3, 2, 1, 0, [42], '23']
# the last line shows, that types are really preserved!


# OK. Now on to the actual "Oneliner". I told you it's obfuscated 
# so don't complain. It actually has 275 characters so i
# split it here in four lines to make it (hopefully) "pastable"

for n,m in ( ('reverse(o)','n.reverse()'),('sort(o)','n.sort()'),\
 ('extend(o,o1)','n.extend(o1)')): exec "def %s:\n t=type\n to=t(o)\
\n if to in (t(''),t(())): n=list(o)\n else: n=to(o)\n %s\n return n and\
(to==t('') and ''.join(n) or to==t(()) and tuple(n) or n) or to()\n" % (n,m)

# paste this code into your interpreter or module 
# and the above examples should work. If you are interested in how
# it basically works (i hope so:-) read on




################
# Obviously you don't want me to talk about this code in compact form...
# (I have put an easily readable version at the end of the page)
# How does it work?
# It actually puts three functions into your current namespace. 
# Let me show you the first one, "reverse"

def reverse(o):
 t=type        # shortcut 
 to=t(o)       # store type of object to be reversed
 if to in (t(''),t(())): n=list(o)  # for tuples and strings construct list 
 else: n=to(o) # otherwise call copy-constructor
 n.reverse()   # now call the inplace method
 return n and (to==t('') and ''.join(n) or to==t(()) and tuple(n) or n) or to()

# The last line ensures that the result is of the same type as the input
# and that Results with length 0 are correctly returned.
# Actually reverse does not only work on strings, tuples and lists.
# It also works on any object which has an "Inplace-" reverse method, 
# a copy constructor and has the conversion into bool. 

# the generated "sort"-method is - apart from name - exactly like reverse.
# But "extend" is different because it needs another argument!
# If you look in the "for ... :"-part of the onliner you will 
# see that "extend" comes out slightly differently:

def extend(o,o1): # NOTE THIS LINE
 t=type
 to=t(o)
 if to in (t(''),t(())): n=list(o)
 else: n=to(o)
 n.extend(o1)  # NOTE THIS LINE
 return n and (to==t('') and ''.join(n) or to==t(()) and tuple(n) or n) or to()

# but actually it differs only in number of arguments: 
# - def extend(o,o1): has two arguments
# - n.extend(o1) gets the second argument

# If you want to play with it you should really use
# the following "longish" version of the code and put it in a module. 

signatures = (('reverse(o)','n.reverse()'),\
              ('sort(o)','n.sort()'), \
              ('extend(o,o1)','n.extend(o1)'))

functemplate="""
def %s:
    t=type
    to=t(o)
    if to in (t(''),t(())):
        n=list(o)
    else:
        n=to(o)
    %s
    return n and (to==t('') and ''.join(n) or to==t(()) and tuple(n) or n) or to()
"""

for n,m in signatures:
    #print functemplate % (n,m) # remove comment if you want to see
    exec functemplate % (n,m)

7 comments

Patrick Maupin 19 years, 8 months ago  # | flag

Be careful! Your return technique will not do the right thing if the function is passed an empty tuple or a null string. In these cases it will return an empty list.

In some cases, of course, this doesn't matter, but you have to be careful when promoting generic solutions.

Patrick Maupin 19 years, 8 months ago  # | flag

To fix this.

Add
    if not o:
        return o

near the top of the function
H. Krekel (author) 19 years, 8 months ago  # | flag

Thanks, fixed. Ouch. you are right. Actually i wasn't aware that empty string/tuples have a "false" boolean value. Thanks for pointing this out!

Your fix is correct for "reverse" and "sort" and but not for "extend". As i don't want to lose the function template i have modified the return magic to handle null results. (version 1.2)

anurag uniyal 19 years, 8 months ago  # | flag

really good. but really obfuscated lets try to obfuscate it further :)

kevin parks 19 years, 7 months ago  # | flag

let's not and say we did... Let's *NOT obfuscate it further. That might be fun for comp.lang.python but i really don't see that this is the place for obfuscated code or showing off. It is supposed to be a repository for useful code. Useful means that the code is called for often and that the code is resonably efficient, clean, and readable. People who are bored and want to show off their programming ability should consider another forum.

Pierre Johnson 19 years, 4 months ago  # | flag

Great Code...Learning = Playing = Purpose. Great code example. Any code example is practical if one really gives some thought. This excellent piece of work might become the basis of a larger solution for someone.

If one bothers to read a real cookbook, you know, one written for food recipes; then one would see that often, major recipes refer to sub-recipes, say, for a sauce.

This type of code is sauce code. One can use it within a larger recipe. That's why this is a cookbook, and not a "here's how you solve your specific problem, book." If you are looking for a book like that, email me. Those kind of books are known as a "consultant".

Matthew Wood 17 years, 4 months ago  # | flag

Good God. Wow. I gotta remember more of my functional/logical programming skills.

Do you care to give a brief desctiption of how that return statement works? I'm just not seeing how the casted (is that a word) value is returned instead of the rest. (I'm upset that I haven't been able to figure it out yet, BTW.)

Created by H. Krekel on Thu, 4 Apr 2002 (PSF)
Python recipes (4591)
H. Krekel's recipes (4)

Required Modules

  • (none specified)

Other Information and Tasks