rot13 in a more Pythonic style?

Discussion in 'Python' started by Andy Dingley, Feb 14, 2007.

  1. Andy Dingley

    Andy Dingley Guest

    I'm trying to write rot13, but to do it in a better and more Pythonic
    style than I'm currrently using. What would you reckon to the
    following pretty ugly thing? How would you improve it? In
    particular, I don't like the way a three-way selection is done by
    nesting two binary selections. Also I dislike stating the same
    algorithm twice, but can't see how to parameterise them neatly.

    Yes, I know of .encode() and .translate().
    No, I don't actually need rot13 itself, it's just a convenient
    substitute example for the real job-specific task.
    No, I don't have to do it with lambdas, but it would be nice if the
    final function was a lambda.


    #!/bin/python
    import string

    lc_rot13 = lambda c : (chr((ord(c) - ord('a') + 13) % 26 + ord('a')))

    uc_rot13 = lambda c : (chr((ord(c) - ord('A') + 13) % 26 + ord('A')))

    c_rot13 = lambda c : (((c, uc_rot13(c)) [c in
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
    'abcdefghijklmnopqrstuvwxyz']

    rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')


    print rot13( 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt' )
     
    Andy Dingley, Feb 14, 2007
    #1
    1. Advertising

  2. Andy Dingley

    Rune Strand Guest

    You could try "some_string".encode('rot_13')
     
    Rune Strand, Feb 14, 2007
    #2
    1. Advertising

  3. Andy Dingley

    Neil Cerutti Guest

    On 2007-02-14, Andy Dingley <> wrote:
    > I'm trying to write rot13, but to do it in a better and more
    > Pythonic style than I'm currrently using. What would you
    > reckon to the following pretty ugly thing? How would you
    > improve it? In particular, I don't like the way a three-way
    > selection is done by nesting two binary selections. Also I
    > dislike stating the same algorithm twice, but can't see how to
    > parameterise them neatly.
    >
    > Yes, I know of .encode() and .translate().


    str.translate is what I'd do.

    import string
    rot13table = string.maketrans(
    'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
    'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM')

    print 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'.translate(rot13table)

    > No, I don't actually need rot13 itself, it's just a convenient
    > substitute example for the real job-specific task. No, I don't
    > have to do it with lambdas, but it would be nice if the final
    > function was a lambda.


    How would it being a lambda help you?

    --
    Neil Cerutti
     
    Neil Cerutti, Feb 14, 2007
    #3
  4. Andy Dingley wrote:
    > I'm trying to write rot13, but to do it in a better and more Pythonic
    > style than I'm currrently using. What would you reckon to the
    > following pretty ugly thing? How would you improve it? In
    > particular, I don't like the way a three-way selection is done by
    > nesting two binary selections. Also I dislike stating the same
    > algorithm twice, but can't see how to parameterise them neatly.
    >
    > Yes, I know of .encode() and .translate().
    > No, I don't actually need rot13 itself, it's just a convenient
    > substitute example for the real job-specific task.
    > No, I don't have to do it with lambdas, but it would be nice if the
    > final function was a lambda.
    >
    >
    > #!/bin/python
    > import string
    >
    > lc_rot13 = lambda c : (chr((ord(c) - ord('a') + 13) % 26 + ord('a')))
    >
    > uc_rot13 = lambda c : (chr((ord(c) - ord('A') + 13) % 26 + ord('A')))
    >
    > c_rot13 = lambda c : (((c, uc_rot13(c)) [c in
    > 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
    > 'abcdefghijklmnopqrstuvwxyz']
    >
    > rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')
    >
    >
    > print rot13( 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt' )
    >


    Well first of all, for me (personal) being Pythonic means that I should
    separate the logic and variables, in this case there is the rotation
    mechanism and the variable with the amount it should rotate.
    Then of course the letters case is something I consider as a state of
    the letter itself, the meaning of the letter doesn't change.
    And being a sucker for dictionaries I use them a lot

    So with that in mind I would write a class like this:
    ###
    class Rot(object):
    def __init__(self,amount = 13):
    self.__alpha = 'abcdefghijklmnopqrstuvwxyz'
    self.__amount = amount
    self.__index_string = dict()
    self.__crypt_index_string = dict()
    self.__string_index = dict()
    self.__crypt_string_index = dict()
    self.__position = 0

    self.__create_dicts()


    def __cypher(self,number):
    alpha_len = len(self.__alpha)
    rotation_overflow = alpha_len - self.__amount
    new_number = None

    if number > rotation_overflow:
    new_number = number - self.__amount

    else:
    new_number = self.__position + self.__amount

    return(new_number)


    def __create_dicts(self):
    for letter in self.__alpha:
    self.__position += 1

    self.__index_string[self.__position] = letter
    self.__crypt_index_string[self.__cypher(self.__position)] =
    letter

    self.__string_index[letter] = self.__position
    self.__crypt_string_index[letter] =
    self.__cypher(self.__position)


    def encrypt(self,text):
    text_list = list()
    letter_capital = None

    for letter in text:
    letter_capital = letter.isupper()
    letter = letter.lower()

    if letter not in self.__alpha:
    text_list.append(letter)

    else:
    position_plain = self.__string_index[letter]
    letter_crypt = self.__crypt_index_string[position_plain]

    if letter_capital:
    letter_crypt = letter_crypt.upper()

    text_list.append(letter_crypt)

    return("".join(text_list))


    def decrypt(self,text):
    text_list = list()
    letter_capital = None

    for letter in text:
    letter_capital = letter.isupper()
    letter = letter.lower()

    if letter not in self.__alpha:
    text_list.append(letter)

    else:
    position_crypt = self.__crypt_string_index[letter]
    letter_plain = self.__index_string[position_crypt]

    if letter_capital:
    letter_plain = letter_plain.upper()

    text_list.append(letter_plain)

    return("".join(text_list))
    ###

    Testing if it works:
    >>> rot13.decrypt(rot13.encrypt("This is a TEST"))

    'This is a TEST'

    --
    mph
     
    Martin P. Hellwig, Feb 14, 2007
    #4
  5. Andy Dingley

    Andy Dingley Guest

    On 14 Feb, 16:23, Neil Cerutti <> wrote:

    > str.translate is what I'd do.


    That's what I hope to do too, but it might not be possible (for the
    live, complex example). It looks as if I have to make a test, then
    process the contents of the code differently depending. There might
    well be a translation inside this, but I think I still have to have an
    explicit 3-way switch in there.



    > How would it being a lambda help you?


    I'm going to use it in a context where that would make for cleaner
    code. There's not much in it though.

    I still don't understand what a lambda is _for_ in Python. I know what
    they are, I know what the alternatives are, but I still haven't found
    an instance where it permits something novel to be done that couldn't
    be done otherwise (if maybe not so neatly).
     
    Andy Dingley, Feb 14, 2007
    #5
  6. En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <>
    escribió:

    > I still don't understand what a lambda is _for_ in Python. I know what
    > they are, I know what the alternatives are, but I still haven't found
    > an instance where it permits something novel to be done that couldn't
    > be done otherwise (if maybe not so neatly).


    A lambda is a shorthand for a simple anonymous function. Any lambda can be
    written as a function:

    lambda args: expression

    is the same as:

    def __anonymous(args): return expression

    (but the inverse is not true; lambda only allows a single expression in
    the function body).

    Except for easy event binding in some GUIs, deferred argument evaluation,
    and maybe some other case, the're not used much anyway. Prior common usage
    with map and filter can be replaced by list comprehensions (a lot more
    clear, and perhaps as fast - any benchmark?)

    --
    Gabriel Genellina
     
    Gabriel Genellina, Feb 14, 2007
    #6
  7. On 14 Feb 2007 09:04:17 -0800, "Andy Dingley" <>
    declaimed the following in comp.lang.python:

    >
    > I still don't understand what a lambda is _for_ in Python. I know what
    > they are, I know what the alternatives are, but I still haven't found
    > an instance where it permits something novel to be done that couldn't
    > be done otherwise (if maybe not so neatly).


    The only useful spot I've seen for them has been in callbacks to
    Tkinter widgets... Rather than defining (silly example, I know)

    def do_stuff(i):
    ...

    def Button_0(event):
    do_stuff(0)

    def Button_1(event):
    do_stuff(1)
    ....
    def Button_9(event):
    do_stuff(9)


    with each button widget having a callback of

    ... =Button_0

    ... =Button_1

    ... ...

    ... =Button_9

    One can just have

    def do_stuff(i):
    ...

    ... =(lambda x=0: do_stuff(x))

    ... =(lambda x=1: do_stuff(x))

    ... ...

    ... =(lambda x=9: do_stuff(x))



    This latter arrangement can be easily generated programmatically:

    for z in range(10):
    ... =(lambda x=z: do_stuff(x))

    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, Feb 14, 2007
    #7
  8. Andy Dingley

    Beej Guest

    On Feb 14, 9:04 am, "Andy Dingley" <> wrote:
    > I still don't understand what a lambda is _for_ in Python.


    Python supports functional programming to a certain extent, and
    lambdas are part of this.

    http://linuxgazette.net/109/pramode.html

    > I know what
    > they are, I know what the alternatives are, but I still haven't found
    > an instance where it permits something novel to be done that couldn't
    > be done otherwise (if maybe not so neatly).


    Strictly speaking, you can live your whole life without using them.
    There's always a procedural way of doing things, as well.

    -Beej
     
    Beej, Feb 14, 2007
    #8
  9. Andy Dingley

    Rob Wolfe Guest

    "Andy Dingley" <> writes:

    > I'm trying to write rot13, but to do it in a better and more Pythonic
    > style than I'm currrently using. What would you reckon to the
    > following pretty ugly thing? How would you improve it? In
    > particular, I don't like the way a three-way selection is done by
    > nesting two binary selections. Also I dislike stating the same
    > algorithm twice, but can't see how to parameterise them neatly.


    It looks to me like a good place to use closure and dictionaries.
    I would write it this way:

    def rot(step):
    import string
    rot_char = lambda a,c,step=step: chr((((ord(c) - ord(a)) + step) % 26) + ord(a))
    make_dict = lambda a,s: dict([(x, rot_char(a, x)) for x in s])
    d = make_dict('a', string.ascii_lowercase)
    d.update(make_dict('A', string.ascii_uppercase))
    def f(s):
    return "".join([d.get(c) or c for c in s])
    return f

    >>> rot13 = rot(13)
    >>> rot13('Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt')

    'Florix Grabundae, Splundig vur thrigg'
    >>> rot_13 = rot(-13)
    >>> rot_13('Florix Grabundae, Splundig vur thrigg')

    'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'

    --
    HTH,
    Rob
     
    Rob Wolfe, Feb 14, 2007
    #9
  10. Andy Dingley

    Paul Rubin Guest

    "Andy Dingley" <> writes:
    > I'm trying to write rot13, but to do it in a better and more Pythonic
    > style than I'm currrently using. What would you reckon to the
    > following pretty ugly thing? How would you improve it? In
    > particular, I don't like the way a three-way selection is done by
    > nesting two binary selections. Also I dislike stating the same
    > algorithm twice, but can't see how to parameterise them neatly.


    I'm having a hard time understanding what you're getting at. Why
    don't you describe the actual problem instead of the rot13 analogy.
     
    Paul Rubin, Feb 14, 2007
    #10
  11. Andy Dingley

    Guest

    Martin P. Hellwig
    > for me (personal) being Pythonic means that I should
    > separate the logic and variables, etc...


    Well, for me me Pythonic means using built-in functionalities as much
    as possible (like using encode("rot13") or translate), and to write
    less code, (avoiding overgeneralizations from the start too). It means
    other things too.

    Bye,
    bearophile
     
    , Feb 14, 2007
    #11
  12. Andy Dingley

    Paul Rubin Guest

    "Andy Dingley" <> writes:
    > c_rot13 = lambdaf c : (((c, uc_rot13(c)) [c in
    > 'ABCDEFGHIJKLMNOPQRSTUVWXYZ']), lc_rot13(c) )[c in
    > 'abcdefghijklmnopqrstuvwxyz']


    Oh, I see what you mean, you have separate upper and lower case maps
    and you're asking how to select one in an expression. Pythonistas
    seem to prefer using multiple statements:

    def c_rot13(c):
    if c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': return uc_rot13(c)
    elif c in 'abcdefghijklmnopqrstuvwxyz': return lc_rot13(c)
    return c

    You could use the new ternary expression though:

    c_rot13 = lambda c: \
    uc_rot13(c) if c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' else \
    (lc_rot13(c) if c in 'abcdefghijklmnopqrstuvwxyz' else \
    c)

    if I have that right.
     
    Paul Rubin, Feb 14, 2007
    #12
  13. wrote:
    > Martin P. Hellwig
    >> for me (personal) being Pythonic means that I should
    >> separate the logic and variables, etc...

    >
    > Well, for me me Pythonic means using built-in functionalities as much
    > as possible (like using encode("rot13") or translate), and to write
    > less code, (avoiding overgeneralizations from the start too). It means
    > other things too.
    >
    > Bye,
    > bearophile
    >

    Yup, but I have a sever case of "NIH" especially if the question asked
    is something more general then the example given :)
    However you are very much right, I reimplemented rot13 and translate in
    a dull way here :)

    --
    mph
     
    Martin P. Hellwig, Feb 14, 2007
    #13
  14. Andy Dingley

    Andy Dingley Guest

    On 14 Feb, 21:59, Paul Rubin <http://> wrote:

    > Why don't you describe the actual problem instead of the rot13 analogy.


    I don't know what the actual problem is! I need to perform a complex
    mapping between "old style" structured identifiers and "new style"
    structured identifers. As the original specification was never thought
    through or written down anywhere, I'm now having to try and reverse-
    engineer from 5 years of collected inconsistent practice. So far I
    have about four pages of BNF to describe things and I'm still not sure
    what's accurate, what's inaccurate spec and what's merely an error in
    practice. Hopefully there's a neat little structure underlying it all
    and a few typos I can merely ignore, but probably it really is just an
    inconsistent structure that needs a lot of explicit tests around the
    corner-cases to make sense of.

    rot13 isn't the issue here, and I already know how to use .translate()
    What I'm after is a tutorial of my Python coding style for an example
    that's quite similar to the rot13 case. Your previous posting was
    very helpful here.
     
    Andy Dingley, Feb 15, 2007
    #14
  15. Andy Dingley

    Guest

    On Feb 14, 11:46 am, "Gabriel Genellina" <>
    wrote:
    > En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <>
    > escribió:
    >
    > > I still don't understand what a lambda is _for_ in Python. I know what
    > > they are, I know what the alternatives are, but I still haven't found
    > > an instance where it permits something novel to be done that couldn't
    > > be done otherwise (if maybe not so neatly).

    >
    > A lambda is a shorthand for a simple anonymous function. Any lambda can be
    > written as a function:
    >
    > lambda args: expression
    >
    > is the same as:
    >
    > def __anonymous(args): return expression
    >
    > (but the inverse is not true; lambda only allows a single expression in
    > the function body).
    >
    > Except for easy event binding in some GUIs, deferred argument evaluation,
    > and maybe some other case, the're not used much anyway. Prior common usage
    > with map and filter can be replaced by list comprehensions (a lot more
    > clear, and perhaps as fast - any benchmark?)
    >
    > --
    > Gabriel Genellina


    They are still useful for reduce(), which has no listcomp equivalent
    that I know of.
     
    , Feb 15, 2007
    #15
  16. On 15 Feb 2007 03:29:45 -0800, "Andy Dingley" <>
    declaimed the following in comp.lang.python:

    >
    > I don't know what the actual problem is! I need to perform a complex
    > mapping between "old style" structured identifiers and "new style"
    > structured identifers. As the original specification was never thought
    > through or written down anywhere, I'm now having to try and reverse-
    > engineer from 5 years of collected inconsistent practice. So far I
    > have about four pages of BNF to describe things and I'm still not sure
    > what's accurate, what's inaccurate spec and what's merely an error in
    > practice. Hopefully there's a neat little structure underlying it all
    > and a few typos I can merely ignore, but probably it really is just an
    > inconsistent structure that needs a lot of explicit tests around the
    > corner-cases to make sense of.
    >

    Sounds more like a case for a parser/lexer wherein the emitted "code
    tokens" are the "new style" identifiers...
    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, Feb 15, 2007
    #16
  17. Andy Dingley

    Andy Dingley Guest

    On 15 Feb, 17:55, Dennis Lee Bieber <> wrote:

    > Sounds more like a case for a parser/lexer wherein the emitted "code
    > tokens" are the "new style" identifiers...


    8-( I'm trying not to think about that....

    Fortunately I don't think it's _quite_ that bad.
     
    Andy Dingley, Feb 15, 2007
    #17
  18. On 15 Feb 2007 11:10:53 -0800, "Andy Dingley" <>
    declaimed the following in comp.lang.python:

    >
    > Fortunately I don't think it's _quite_ that bad.


    Possibly not, but that description of the problem would likely have
    gotten more applicable help than a debate on the merits of
    reimplementing translate().
    --
    Wulfraed Dennis Lee Bieber KD6MOG

    HTTP://wlfraed.home.netcom.com/
    (Bestiaria Support Staff: )
    HTTP://www.bestiaria.com/
     
    Dennis Lee Bieber, Feb 16, 2007
    #18
  19. On Fri, 16 Feb 2007 04:53:23 +0000, Dennis Lee Bieber wrote:

    > On 15 Feb 2007 11:10:53 -0800, "Andy Dingley" <>
    > declaimed the following in comp.lang.python:
    >
    >>
    >> Fortunately I don't think it's _quite_ that bad.

    >
    > Possibly not, but that description of the problem would likely have
    > gotten more applicable help than a debate on the merits of
    > reimplementing translate().



    The Original Poster did say in his first post that he knew about translate
    and encode and he wasn't looking for those solutions:

     
    Steven D'Aprano, Feb 16, 2007
    #19
  20. Andy Dingley

    Andy Dingley Guest

    On 14 Feb, 20:06, "Beej" <> wrote:

    > http://linuxgazette.net/109/pramode.html


    Thanks, that's a _really_ interesting link (Oh, I need to learn
    Scheme!)

    My code now looks like this, which I'm starting to feel much happier
    about in a functional sense.


    c_rot = lambda c, chars : (chr((ord(c) - ord(chars[0]) +
    (len(chars) // 2)) % len(chars) + ord(chars[0])))

    c_rot13 = lambda c : (((c, \
    c_rot(c, string.ascii_uppercase)) [c in string.ascii_uppercase]),
    \
    c_rot(c, string.ascii_lowercase)) [c in string.ascii_lowercase]

    rot13 = lambda s : string.join([ c_rot13(c) for c in s ],'')



    I also considered this, but don't trust it as it relies on the two
    sets being mutually disjoint between their inputs and outputs.

    qc_rot = lambda c, chars : (c, c_rot(c, chars)) [c in chars]
    c_rot13 = lambda c : (qc_rot( qc_rot(c, string.ascii_lowercase),
    string.ascii_uppercase))
     
    Andy Dingley, Feb 16, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eirik

    Why does this work? (rot13 function)

    Eirik, Dec 16, 2003, in forum: C Programming
    Replies:
    15
    Views:
    834
    Randy Howard
    Dec 18, 2003
  2. Carl J. Van Arsdall
    Replies:
    4
    Views:
    519
    Bruno Desthuilliers
    Feb 7, 2006
  3. metaperl
    Replies:
    2
    Views:
    260
    bayerj
    Dec 14, 2006
  4. thor
    Replies:
    3
    Views:
    363
    Daniel Pitts
    May 29, 2008
  5. Agent Spikes

    Shorter Rot13 Pure-C Implementation

    Agent Spikes, Mar 7, 2010, in forum: C Programming
    Replies:
    19
    Views:
    960
    Michael Foukarakis
    Mar 17, 2010
Loading...

Share This Page