FAQ
I've got this string in which I need to sub in the same word several
times; i.e:
"%s - %s - %s" % ("test","test","test")
'test - test - test'
>>>

But I want to use the * to make life easier to read, so I tried:
("test",)*3
('test', 'test', 'test')
"%s - %s - %s" % ("test",)*3
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: not enough arguments for format string
>>>

Which seemed like a good idea, but after some playing around I found
that:
eval(str(("test",)*3))
('test', 'test', 'test')
"%s - %s - %s" % eval(str(("test",)*3))
'test - test - test'
>>>

Did work. Odd because:
type(("test",)*3)
<type 'tuple'>
type(eval(str(("test",)*3)))
<type 'tuple'>
>>>

Any idea why the tuple to str to tuple works and not the tuple straight?

Mike

Search Discussions

  • Jeff Epler at Aug 19, 2003 at 9:30 pm

    try this:
    "%s - %s - %s" % (("test",)*3)
    why else would
    3 % 1 * 2
    print 0 instead of 1?

    Jeff
  • Fredrik Lundh at Aug 19, 2003 at 9:36 pm

    Michael C. Neel wrote:

    But I want to use the * to make life easier to read, so I tried:
    ("test",)*3
    ('test', 'test', 'test')
    "%s - %s - %s" % ("test",)*3
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: not enough arguments for format string
    "%s - %s - %s" % ("test",)*3
    is the same thing as
    ( "%s - %s - %s" % ("test",) ) * 3
    but you really want
    "%s - %s - %s" % ( ("test",)*3 )
    (your eval/str construct is just a really inefficient way to add
    parentheses to an expression...)

    </F>
  • Oren Tirosh at Aug 19, 2003 at 9:37 pm

    On Tue, Aug 19, 2003 at 05:25:19PM -0400, Michael C. Neel wrote:
    I've got this string in which I need to sub in the same word several
    times; i.e:
    "%s - %s - %s" % ("test","test","test")
    'test - test - test'
    But I want to use the * to make life easier to read, so I tried:
    ("test",)*3
    ('test', 'test', 'test')
    "%s - %s - %s" % ("test",)*3
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: not enough arguments for format string
    It's just an issie of evaluation order. Try adding parentheses:
    "%s - %s - %s" % (("test",)*3)
    'test - test - test'

    Oren
  • Skip Montanaro at Aug 19, 2003 at 9:41 pm
    Michael> But I want to use the * to make life easier to read, so I tried:
    ("test",)*3
    Michael> ('test', 'test', 'test')
    "%s - %s - %s" % ("test",)*3
    Michael> Traceback (most recent call last):
    Michael> File "<stdin>", line 1, in ?
    Michael> TypeError: not enough arguments for format string
    >>>>

    That's because the % and * operators have the same precendence and group
    left-to-right. The above expression is equivalent to

    ("%s - %s - %s" % ("test",))*3

    To force the * operation to be evaluated first you need to add some parens:

    ("%s - %s - %s" % (("test",))*3)

    which works as expected:
    "%s - %s - %s" % (("test",)*3)
    'test - test - test'

    If you're worried about readability of large format operations, I suggest
    you consider using dictionary expansion, e.g.:
    "%(var)s - %(var)s - %(var)s" % {"var": "test"}
    'test - test - test'

    or more commonly:
    var = "test"
    "%(var)s - %(var)s - %(var)s" % locals()
    'test - test - test'

    Skip
  • Skip Montanaro at Aug 19, 2003 at 9:45 pm
    Skip> To force the * operation to be evaluated first you need to add some parens:

    Skip> ("%s - %s - %s" % (("test",))*3)

    Ack! Should have been what I entered at the >>> prompt:

    "%s - %s - %s" % (("test",)*3)

    (Stupid copy-n-paste!)

    Skip
  • Michael C. Neel at Aug 19, 2003 at 9:43 pm

    try this:
    "%s - %s - %s" % (("test",)*3)
    why else would
    3 % 1 * 2
    print 0 instead of 1?

    Jeff
    Hmmm, can't say I like what this implies. In one case % is shorthand
    for a sprintf function, the other it's a mathematical expression at the
    same level of precedence of * and /. But the sprintf version is
    "granted" the precedence of the mathematical version? What's the logic
    behind that?

    Oh well,
    Mike
  • Fredrik Lundh at Aug 19, 2003 at 9:57 pm

    Michael C. Neel wrote:

    Hmmm, can't say I like what this implies. In one case % is shorthand
    for a sprintf function, the other it's a mathematical expression at the
    same level of precedence of * and /. But the sprintf version is
    "granted" the precedence of the mathematical version? What's the
    logic behind that?
    it's the same "%", and the same "*".

    consider the expression "a % b * c".

    using your logic, do you really expect the evaluation order to vary
    depending on the actual types of the objects a, b, and c?

    </F>
  • Cliff Wells at Aug 19, 2003 at 9:54 pm

    On Tue, 2003-08-19 at 14:25, Michael C. Neel wrote:
    I've got this string in which I need to sub in the same word several
    times; i.e:
    "%s - %s - %s" % ("test","test","test")
    'test - test - test'
    But I want to use the * to make life easier to read, so I tried:
    ("test",)*3
    ('test', 'test', 'test')
    "%s - %s - %s" % ("test",)*3
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    TypeError: not enough arguments for format string
    Any idea why the tuple to str to tuple works and not the tuple straight?
    Because % has higher precedence than * (or rather they have equal
    precedence and the expression is evaluated left to right) so the
    expression becomes

    ("%s - %s - %s" % ("test",)) * 3

    when what you meant was

    "%s - %s - %s" % (("test",) * 3)

    Here's another approach:
    def fjoin(sep, s, n):
    ... return sep.join(["%s"] * n) % ((s,) * n)
    ...
    fjoin(' - ', "test", 3)
    'test - test - test'


    Regards,

    --
    Cliff Wells, Software Engineer
    Logiplex Corporation (www.logiplex.net)
    (503) 978-6726 (800) 735-0555
  • Erik Max Francis at Aug 19, 2003 at 10:56 pm

    "Michael C. Neel" wrote:

    Hmmm, can't say I like what this implies. In one case % is shorthand
    for a sprintf function, the other it's a mathematical expression at
    the
    same level of precedence of * and /. But the sprintf version is
    "granted" the precedence of the mathematical version? What's the
    logic
    behind that?
    Very, very good logic. Consider the following expression:

    left % middle * right

    If we are to take your suggestion, and % is to have different precedence
    based on whether or not it is being used as a string formatting
    operation or as module division, then the precedence will be

    left % (middle * right)

    or

    (left % middle) * right

    depending on the type of `left'. That means that the precedence changes
    based on the types of the arguments. That is disastrous in a dynamic
    language like Python for both processing and readability, because now it
    means the same expression can have widely different semantic meanings
    based on their arguments. Having the same operator have different
    precedence based on its operands would be disastrous.

    --
    Erik Max Francis && max at alcyone.com && http://www.alcyone.com/max/
    __ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
    / \ A wise man never loses anything if he have himself.
    \__/ Montaigne
  • Michael C. Neel at Aug 19, 2003 at 11:16 pm
    Maybe I should phrase the question a bit differently, more to the real
    issue (I guess, it's all academic from here), why is the % operator used
    both for string formatting and remainders?

    To me:
    "%d" % 2 * 3
    "222"

    Is not what I expected nor wanted. I could however be alone in that
    opinion. I'm selfish; as a programmer I don't really care about the
    internals of the parser, I care about ease to code - that's what I like
    about python, I don't spend time debugging syntax, but working on the
    logic of the program.

    It's probably not hard to guess I don't like ', '.join(list) either ;-)


    thanks for all the replies though!
    Mike
  • Amit Patel at Aug 19, 2003 at 11:34 pm

    "Michael C. Neel" <neel at mediapulse.com> writes:

    try this:
    "%s - %s - %s" % (("test",)*3)
    why else would
    3 % 1 * 2
    print 0 instead of 1?

    Jeff
    Hmmm, can't say I like what this implies. In one case % is shorthand
    for a sprintf function, the other it's a mathematical expression at the
    same level of precedence of * and /. But the sprintf version is
    "granted" the precedence of the mathematical version? What's the logic
    behind that?
    I think the logic behind that is that the operator precedence is
    assigned before we know what the types of the operands are. You could
    argue that since we can see it's a string, we should change the
    precedence. But then we'd get weird situations like

    print "..." % (x,)*3

    not being the same as

    s = "..."
    print s % (x,)*3

    You could argue that a flow analyzer could figure out that s is a
    string, etc., but that's going down a dangerous path -- the semantics
    start depending on how sophisticated your Python compiler is. Aieee! :)

    Some of the 'cute' syntax features of Python (% for strings, `` for
    repr) have bitten me more than once. :(

    - Amit

    --
    Amit J Patel, Computer Science Department, Stanford University
    http://www-cs-students.stanford.edu/~amitp/
    ``Parkinson's Other Law: Perfection is achieved only
    at the point of collapse.''
  • Ben Finney at Aug 20, 2003 at 12:04 am

    On Tue, 19 Aug 2003 19:16:27 -0400, Michael C. Neel wrote:
    why is the % operator used both for string formatting and remainders?
    Historical. Neither operation has an obvious character on the keyboard,
    and the '%' did not already have an obvious application as an operator
    for either strings nor numbers.

    For numbers, I believe the '%' for modulus has been around at least as
    early as C, probably in much earlier languages. Its visual similarity
    to the division operator, which is strongly related to modulus, probably
    helped the decision.

    For strings, the C printf formatting codes use '%' as a format marker
    within the string, so when Python adopted the same convention, it was a
    good choice when Python needed to choose a character for the operator.
    "%d" % 2 * 3
    "222"

    Is not what I expected nor wanted. I could however be alone in that
    opinion.
    No, you're not alone in that -- I'd certainly expect the "2 * 3" to have
    a tighter binding than, and to be evaluated before, the string
    formatting.

    I think it's even potentially a bug that the "2 * 3" is interpreted as a
    string operation, since its arguments are clearly numeric.

    However, this does reinforce a principle I learned from somewhere (maybe
    Scott Meyers, maybe Steve McConnell, maybe someone else) with regard to
    remembering operator precedence in different languages:

    Addition and subtraction are equal precedence. Multiplication and
    division are equal precedence. Use parentheses to make explicit any
    other precedence assumptions.

    Using that rule, your example becomes:
    "%d" % ( 2 * 3 )
    '6'

    No problem.

    It's probably not hard to guess I don't like ', '.join(list) either
    ;-)
    Nor I. But I am finding the reminder of the immutability of the list to
    be useful.

    --
    \ "What if the Hokey Pokey IS what it's all about?" -- Anonymous |
    `\ |
    _o__) |
    Ben Finney <http://bignose.squidly.org/>
  • Erik Max Francis at Aug 20, 2003 at 12:16 am

    "Michael C. Neel" wrote:

    Maybe I should phrase the question a bit differently, more to the real
    issue (I guess, it's all academic from here), why is the % operator
    used
    both for string formatting and remainders?
    It's got a lot of precedent behind it, so it's too late to change now.
    At some point, someone decided it made sense, so it was done.
    To me:
    "%d" % 2 * 3
    "222"

    Is not what I expected nor wanted. I could however be alone in that
    opinion.
    The real question is: How likely is this issue going to be a real
    problem? Why not just learn to use parentheses when you're doing
    something tricky with the right argument to the string formatting
    operator, and be done with it, problem solved?

    --
    Erik Max Francis && max at alcyone.com && http://www.alcyone.com/max/
    __ San Jose, CA, USA && 37 20 N 121 53 W && &tSftDotIotE
    / \ Human salvation lies in the hands of the creatively maladjusted.
    \__/ Dr. Martin Luther King, Jr.
  • Duncan Booth at Aug 20, 2003 at 8:17 am
    Skip Montanaro <skip at pobox.com> wrote in
    news:mailman.1061329351.3443.python-list at python.org:
    If you're worried about readability of large format operations, I suggest
    you consider using dictionary expansion, e.g.:
    "%(var)s - %(var)s - %(var)s" % {"var": "test"}
    'test - test - test'

    or more commonly:
    var = "test"
    "%(var)s - %(var)s - %(var)s" % locals()
    'test - test - test'
    I'm not sure about that last one being more common. I don't think I have
    ever had a desire to pass more variables to the string format than the ones
    I know I really want there.

    If you've upgraded to Python 2.3, then another way to write this would be:
    "%(var)s - %(var)s - %(var)s" % dict(var="test")
    --
    Duncan Booth duncan at rcp.co.uk
    int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
    "\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
  • Anders J. Munch at Aug 20, 2003 at 1:31 pm

    "Cliff Wells" wrote:
    Here's another approach:
    def fjoin(sep, s, n):
    ... return sep.join(["%s"] * n) % ((s,) * n)
    Better this:

    def fjoin(sep, s, n):
    return sep.join((s,)*n)

    Works even if sep contains a % character.
    fjoin(' % ', "test", 3)
    'test % test % test'

    - Anders

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedAug 19, '03 at 9:25p
activeAug 20, '03 at 1:31p
posts16
users11
websitepython.org

People

Translate

site design / logo © 2022 Grokbase