String handling and the percent operator

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Tom Plunket

    #1

    String handling and the percent operator

    I have some code to autogenerate some boilerplate code so that I don't
    need to do the tedious setup stuff when I want to create a new module.

    So, my script prompts the user for the module name, then opens two
    files and those files each get the contents of one of these functions:

    def GetPyContents(m odule):
    boilerplate = \
    """
    class %s:
    pass

    if __name__ == '__main__':
    import unittest
    unittest.main(' %s_t')
    """

    return boilerplate % ((module,) * 2)

    def GetTestContents (module):
    boilerplate = \
    """from %s import *
    import unittest

    class Test%s(unittest .TestCase):
    def testConstructio n(self):
    self.failUnless (%s())

    def testWriteMoreTe sts(self):
    self.fail('This test should fail.')

    if __name__ == '__main__':
    unittest.main()
    """

    return boilerplate % ((module,) * 3)

    My question is, I don't like hardcoding the number of times that the
    module name should be repeated in the two return functions. Is there
    an straight forward (inline-appropriate) way to count the number of
    '%s'es in the 'boilerplate' strings? ...or maybe a different and more
    Pythonic way to do this? (Maybe I could somehow use generators?)

    thx.
    -tom!
  • Simon Forman

    #2
    Re: String handling and the percent operator

    Tom Plunket wrote:
    I have some code to autogenerate some boilerplate code so that I don't
    need to do the tedious setup stuff when I want to create a new module.
    >
    So, my script prompts the user for the module name, then opens two
    files and those files each get the contents of one of these functions:
    >
    def GetPyContents(m odule):
    boilerplate = \
    """
    class %s:
    pass
    >
    if __name__ == '__main__':
    import unittest
    unittest.main(' %s_t')
    """
    >
    return boilerplate % ((module,) * 2)
    >
    def GetTestContents (module):
    boilerplate = \
    """from %s import *
    import unittest
    >
    class Test%s(unittest .TestCase):
    def testConstructio n(self):
    self.failUnless (%s())
    >
    def testWriteMoreTe sts(self):
    self.fail('This test should fail.')
    >
    if __name__ == '__main__':
    unittest.main()
    """
    >
    return boilerplate % ((module,) * 3)
    >
    My question is, I don't like hardcoding the number of times that the
    module name should be repeated in the two return functions. Is there
    an straight forward (inline-appropriate) way to count the number of
    '%s'es in the 'boilerplate' strings? ...or maybe a different and more
    Pythonic way to do this? (Maybe I could somehow use generators?)
    >
    thx.
    -tom!

    strings have a count() method.

    Since you know that you won't have things like '%%s' in your
    boilerplate, it's perfectly reasonable to use:

    return boilerplate % ((module,) * boilerplate.cou nt('%s'))

    in your code.

    Peace,
    ~Simon

    return boilerplate % ((module,) * 3)

    Comment

    • Tom Plunket

      #3
      Re: String handling and the percent operator

      Simon Forman wrote:
      strings have a count() method.
      thanks!

      For enrichment purposes, is there a way to do this sort of thing with
      a generator? E.g. something like:

      def SentenceGenerat or():
      words = ['I', 'have', 'been', 'to', 'the', 'fair']
      for w in words:
      yield w

      message = "%s %s %s %s"

      print message % SentenceGenerat or()

      (I ask because the above doesn't work)?
      -tom!

      Comment

      • Erik Max Francis

        #4
        Re: String handling and the percent operator

        Tom Plunket wrote:
        For enrichment purposes, is there a way to do this sort of thing with
        a generator? E.g. something like:
        >
        def SentenceGenerat or():
        words = ['I', 'have', 'been', 'to', 'the', 'fair']
        for w in words:
        yield w
        >
        message = "%s %s %s %s"
        >
        print message % SentenceGenerat or()
        >
        (I ask because the above doesn't work)?
        Use tuple(SentenceG enerator()). A generator is just another object, so
        using it with the % operator tries to substitute it at one value. (Even
        with this fix, though, your message didn't have enough formatters.)

        --
        Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
        San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
        Human salvation lies in the hands of the creatively maladjusted.
        -- Dr. Martin Luther King, Jr.

        Comment

        • Justin  Azoff

          #5
          Re: String handling and the percent operator

          Tom Plunket wrote:
          boilerplate = \
          """
          [big string]
          """
          >
          return boilerplate % ((module,) * 3)
          >
          My question is, I don't like hardcoding the number of times that the
          module name should be repeated in the two return functions. Is there
          an straight forward (inline-appropriate) way to count the number of
          '%s'es in the 'boilerplate' strings? ...or maybe a different and more
          Pythonic way to do this? (Maybe I could somehow use generators?)
          >
          thx.
          -tom!
          Of course..
          >>stuff = {'lang': 'python', 'page': 'typesseq-strings.html'}
          >>print """I should read the %(lang)s documentation at
          .... http://docs.%(lang)s.o rg/lib/%(page)s""" % stuff
          I should read the python documentation at



          --
          - Justin

          Comment

          • Brett g Porter

            #6
            Re: String handling and the percent operator

            Justin Azoff wrote:
            Tom Plunket wrote:
            > boilerplate = \
            >"""
            [big string]
            >"""
            >>
            > return boilerplate % ((module,) * 3)
            >>
            [deletia...]
            Of course..
            >
            >>>stuff = {'lang': 'python', 'page': 'typesseq-strings.html'}
            >>>print """I should read the %(lang)s documentation at
            ... http://docs.%(lang)s.o rg/lib/%(page)s""" % stuff
            I should read the python documentation at
            http://docs.python.org/lib/typesseq-strings.html
            ....or perhaps cooler:


            something like:

            from string import Template

            def GetPyContents(m odule):
            boilerplate = Template( \
            """
            class $moduleName:
            pass

            if __name__ == '__main__':
            import unittest
            unittest.main(' ${moduleName}_t ')
            """)

            return boilerplate.sub stitute(moduleN ame=module)

            Comment

            • Simon Forman

              #7
              Re: String handling and the percent operator

              Tom Plunket wrote:
              Simon Forman wrote:
              >
              strings have a count() method.
              >
              thanks!
              >
              For enrichment purposes, is there a way to do this sort of thing with
              a generator? E.g. something like:
              >
              def SentenceGenerat or():
              words = ['I', 'have', 'been', 'to', 'the', 'fair']
              for w in words:
              yield w
              >
              message = "%s %s %s %s"
              >
              print message % SentenceGenerat or()
              >
              (I ask because the above doesn't work)?
              -tom!
              If you're asking if there's some way that the generator can know how
              many formatting fields are in message then the straightforward answer
              is no. At least not without passing the message to the generator for
              it to call count() itself, and then you're better off just doing it
              without the generator.

              (Actually, IIRC, this was discussed quite recently on this list, and
              (again IIRC) I think there is some deep voodoo that can do this, but
              you're much better off without it.)

              FWIW, in your shoes I would use the trick Justin Azoff posted, i.e.:

              boiler = 'foo %(modname)s bar %(modname)s baz'

              message = boiler % {'modname': modname}


              Peace,
              ~Simon

              Comment

              • Bruno Desthuilliers

                #8
                Re: String handling and the percent operator

                Tom Plunket wrote:
                I have some code to autogenerate some boilerplate code so that I don't
                need to do the tedious setup stuff when I want to create a new module.
                >
                So, my script prompts the user for the module name, then opens two
                files and those files each get the contents of one of these functions:
                >
                def GetPyContents(m odule):
                boilerplate = \
                """
                class %s:
                pass
                >
                if __name__ == '__main__':
                import unittest
                unittest.main(' %s_t')
                """
                >
                return boilerplate % ((module,) * 2)
                >
                def GetTestContents (module):
                boilerplate = \
                """from %s import *
                import unittest
                >
                class Test%s(unittest .TestCase):
                def testConstructio n(self):
                self.failUnless (%s())
                >
                def testWriteMoreTe sts(self):
                self.fail('This test should fail.')
                >
                if __name__ == '__main__':
                unittest.main()
                """
                >
                return boilerplate % ((module,) * 3)
                >
                My question is, I don't like hardcoding the number of times that the
                module name should be repeated in the two return functions. Is there
                an straight forward (inline-appropriate) way to count the number of
                '%s'es in the 'boilerplate' strings? ...or maybe a different and more
                Pythonic way to do this? (Maybe I could somehow use generators?)
                Python's string formatting comes in two flavours : positional (the one
                you used in your above example), and keywords:

                tpls = [
                "%(name1)s is %(name1)s and %(name2)s is %(name2)s",
                "what about %(name2)s for %(name1)s ?",
                "Now we only deal with %(name1)s",
                ]

                data = {'name1' : 'parrot', 'name2': 'dead'}

                for tpl in tpls:
                print tpl % data

                As you can see, the keyword flavour doesn't care about positions nor
                repetitions.

                You may also want to look at more featured templating solutions like
                empy, cheetah, etc...

                --
                bruno desthuilliers
                python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                p in 'onurb@xiludom. gro'.split('@')])"

                Comment

                • Tom Plunket

                  #9
                  Re: String handling and the percent operator

                  Justin Azoff wrote:
                  Of course..
                  >
                  I should read the python documentation at
                  http://docs.python.org/lib/typesseq-strings.html
                  Excellent. Thanks. Has this been around long? I "learned" Python in
                  the 1.6 days iirc, but haven't done much except simple scripting with
                  it since...
                  -tom!

                  Comment

                  • Erik Max Francis

                    #10
                    Re: String handling and the percent operator

                    Tom Plunket wrote:
                    Excellent. Thanks. Has this been around long? I "learned" Python in
                    the 1.6 days iirc, but haven't done much except simple scripting with
                    it since...
                    Yep. Been around since at least 1.5.x.

                    --
                    Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
                    San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
                    Sometimes a cigar is just a cigar.
                    -- Sigmund Freud

                    Comment

                    • Tom Plunket

                      #11
                      Re: String handling and the percent operator

                      Erik Max Francis wrote:
                      For enrichment purposes, is there a way to do this sort of thing with
                      a generator? E.g. something like:

                      def SentenceGenerat or():
                      words = ['I', 'have', 'been', 'to', 'the', 'fair']
                      for w in words:
                      yield w

                      message = "%s %s %s %s"

                      print message % SentenceGenerat or()

                      (I ask because the above doesn't work)?
                      >
                      Use tuple(SentenceG enerator()). A generator is just another object, so
                      using it with the % operator tries to substitute it at one value. (Even
                      with this fix, though, your message didn't have enough formatters.)
                      I know that the message didn't have enough formatters, that's why I
                      asked. (Although I would have assumed that the generator would get
                      automatically converted to a sequence that was consumable by the
                      interpolation operator...)

                      When using a generator via .next(), there's no requirement that it is
                      used until it is exhausted. E.g.

                      def NewId():
                      v = 0
                      while 1:
                      yield v
                      v += 1

                      NextId = NewId().next

                      BUTTON_OK = NextId()
                      BUTTON_CANCEL = NextId()
                      BUTTON_YAY = NextId()

                      Hence my question being "something like" rather than "something
                      equivalent to". Alas, little did I know that the answer I was looking
                      for was not even up the same path.

                      -tom!

                      Comment

                      • Erik Max Francis

                        #12
                        Re: String handling and the percent operator

                        Tom Plunket wrote:
                        I know that the message didn't have enough formatters, that's why I
                        asked. (Although I would have assumed that the generator would get
                        automatically converted to a sequence that was consumable by the
                        interpolation operator...)
                        That's because::

                        aFormatString % anObject

                        is a shortcut for::

                        aFormatString % (anObject,)

                        so things like::

                        print "Your birthday is on %s" % date

                        are allowed. So when the object is an iterator, it's just treated as a
                        single value in a 1-tuple, rather than iterated over to get its own tuple.

                        --
                        Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
                        San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
                        Sometimes a cigar is just a cigar.
                        -- Sigmund Freud

                        Comment

                        Working...