rot13 in a more Pythonic style?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Andy Dingley

    #1

    rot13 in a more Pythonic style?

    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
    'ABCDEFGHIJKLMN OPQRSTUVWXYZ']), lc_rot13(c) )[c in
    'abcdefghijklmn opqrstuvwxyz']

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


    print rot13( 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt' )

  • Rune Strand

    #2
    Re: rot13 in a more Pythonic style?

    You could try "some_string".e ncode('rot_13')

    Comment

    • Neil Cerutti

      #3
      Re: rot13 in a more Pythonic style?

      On 2007-02-14, Andy Dingley <dingbat@codesm iths.comwrote:
      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.maketran s(
      'abcdefghijklmn opqrstuvwxyzABC DEFGHIJKLMNOPQR STUVWXYZ',
      'nopqrstuvwxyza bcdefghijklmNOP QRSTUVWXYZABCDE FGHIJKLM')

      print 'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'.transla te(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

      Comment

      • Martin P. Hellwig

        #4
        Re: rot13 in a more Pythonic style?

        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
        'ABCDEFGHIJKLMN OPQRSTUVWXYZ']), lc_rot13(c) )[c in
        'abcdefghijklmn opqrstuvwxyz']
        >
        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,a mount = 13):
        self.__alpha = 'abcdefghijklmn opqrstuvwxyz'
        self.__amount = amount
        self.__index_st ring = dict()
        self.__crypt_in dex_string = dict()
        self.__string_i ndex = dict()
        self.__crypt_st ring_index = dict()
        self.__position = 0

        self.__create_d icts()


        def __cypher(self,n umber):
        alpha_len = len(self.__alph a)
        rotation_overfl ow = alpha_len - self.__amount
        new_number = None

        if number rotation_overfl ow:
        new_number = number - self.__amount

        else:
        new_number = self.__position + self.__amount

        return(new_numb er)


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

        self.__index_st ring[self.__position] = letter
        self.__crypt_in dex_string[self.__cypher(s elf.__position)] =
        letter

        self.__string_i ndex[letter] = self.__position
        self.__crypt_st ring_index[letter] =
        self.__cypher(s elf.__position)


        def encrypt(self,te xt):
        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.appen d(letter)

        else:
        position_plain = self.__string_i ndex[letter]
        letter_crypt = self.__crypt_in dex_string[position_plain]

        if letter_capital:
        letter_crypt = letter_crypt.up per()

        text_list.appen d(letter_crypt)

        return("".join( text_list))


        def decrypt(self,te xt):
        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.appen d(letter)

        else:
        position_crypt = self.__crypt_st ring_index[letter]
        letter_plain = self.__index_st ring[position_crypt]

        if letter_capital:
        letter_plain = letter_plain.up per()

        text_list.appen d(letter_plain)

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

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

        --
        mph

        Comment

        • Andy Dingley

          #5
          Re: rot13 in a more Pythonic style?

          On 14 Feb, 16:23, Neil Cerutti <horp...@yahoo. comwrote:
          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).

          Comment

          • Gabriel Genellina

            #6
            Re: rot13 in a more Pythonic style?

            En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <dingbat@codesm iths.com>
            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(arg s): 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

            Comment

            • Beej

              #7
              Re: rot13 in a more Pythonic style?

              On Feb 14, 9:04 am, "Andy Dingley" <ding...@codesm iths.comwrote:
              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.


              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

              Comment

              • Rob Wolfe

                #8
                Re: rot13 in a more Pythonic style?

                "Andy Dingley" <dingbat@codesm iths.comwrites:
                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_lo wercase)
                d.update(make_d ict('A', string.ascii_up percase))
                def f(s):
                return "".join([d.get(c) or c for c in s])
                return f
                >>rot13 = rot(13)
                >>rot13('Sybe vk Tenohaqnr, Fcyhaqvt ihe guevtt')
                'Florix Grabundae, Splundig vur thrigg'
                >>rot_13 = rot(-13)
                >>rot_13('Flori x Grabundae, Splundig vur thrigg')
                'Sybevk Tenohaqnr, Fcyhaqvt ihe guevtt'

                --
                HTH,
                Rob

                Comment

                • Paul Rubin

                  #9
                  Re: rot13 in a more Pythonic style?

                  "Andy Dingley" <dingbat@codesm iths.comwrites:
                  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.

                  Comment

                  • bearophileHUGS@lycos.com

                    #10
                    Re: rot13 in a more Pythonic style?

                    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 overgeneralizat ions from the start too). It means
                    other things too.

                    Bye,
                    bearophile

                    Comment

                    • Paul Rubin

                      #11
                      Re: rot13 in a more Pythonic style?

                      "Andy Dingley" <dingbat@codesm iths.comwrites:
                      c_rot13 = lambdaf c : (((c, uc_rot13(c)) [c in
                      'ABCDEFGHIJKLMN OPQRSTUVWXYZ']), lc_rot13(c) )[c in
                      'abcdefghijklmn opqrstuvwxyz']
                      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 'ABCDEFGHIJKLMN OPQRSTUVWXYZ': return uc_rot13(c)
                      elif c in 'abcdefghijklmn opqrstuvwxyz': return lc_rot13(c)
                      return c

                      You could use the new ternary expression though:

                      c_rot13 = lambda c: \
                      uc_rot13(c) if c in 'ABCDEFGHIJKLMN OPQRSTUVWXYZ' else \
                      (lc_rot13(c) if c in 'abcdefghijklmn opqrstuvwxyz' else \
                      c)

                      if I have that right.

                      Comment

                      • Martin P. Hellwig

                        #12
                        Re: rot13 in a more Pythonic style?

                        bearophileHUGS@ lycos.com 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 overgeneralizat ions 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

                        Comment

                        • Andy Dingley

                          #13
                          Re: rot13 in a more Pythonic style?

                          On 14 Feb, 21:59, Paul Rubin <http://phr...@NOSPAM.i nvalidwrote:
                          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.

                          Comment

                          • tomtheisen@tomtheisen.com

                            #14
                            Re: rot13 in a more Pythonic style?

                            On Feb 14, 11:46 am, "Gabriel Genellina" <gagsl...@yahoo .com.ar>
                            wrote:
                            En Wed, 14 Feb 2007 14:04:17 -0300, Andy Dingley <ding...@codesm iths.com>
                            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(arg s): 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.

                            Comment

                            • Andy Dingley

                              #15
                              Re: rot13 in a more Pythonic style?

                              On 15 Feb, 17:55, Dennis Lee Bieber <wlfr...@ix.net com.comwrote:
                              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.

                              Comment

                              Working...