Placeholders

Hey ho

    def basic_description_2(self):
        print("The name is: %s, this character's melee capabilities are %s,\
 agility seems to be pretty %s, he uses %s magic, and has %s luck."
              % (self.name, self.melee, self.agility, self.magic, self.luck))

OUTPUT:

The name is: Jim, this character's melee capabilities are high, agility seems to be pretty good, he uses no magic, and has low luck.

Is there any way to make this code aesthetically pleasing without ruining the indents in the output?
If I remove \, add “+” and another "string" the %s get all messed up, because, they work for one string only. It would be good if I could do that I guess. Address the placeholders in more than one string?.. I have also heard that there is a different way to make placeholders and that this method is VERY dated. I looked around actually, I found something with .format() but I can’t get it working. So I am looking for help here.

2 Likes

https://pyformat.info/

Something to consider in using the newer .format() (it was introduced in the later stages of Python 2, I believe) is to use keywords and predefining the string and format as class variables.

basic_descr2_str = "The name is: {name}, this character's melee \
capabilities are {melee}, agility seems to be pretty {agility}, he uses \
{magic} magic, and has {luck} luck."
basic_descr2_format = (
  name = self.name, 
  melee = self.melee, 
  agility = self.agility,
  magic = self.magic,
  luck = self.luck
)
def basic_description_2(self):
  print(basic_descr_2_str.format(*basic_descr2_format)) #unpack argument sequence

The payoff of this approach is good in terms of keeping clutter out of the instance methods.

It is untested and pure speculation at this point, but you get the idea. Perhaps custom objects will be needed. I’ll continue to explore this while you test this code and report back (please).


With this mockup I found a fatal error…

class Player:
    basic_descr2_str = "The name is: {name}, this character's melee \
capabilities are {melee}, agility seems to be pretty {agility}, he uses \
{magic} magic, and has {luck} luck."
    basic_descr2_format = (
        name = self.name,   # syntax error
        melee = self.melee, 
        agility = self.agility,
        magic = self.magic,
        luck = self.luck
    )
    def __init__(self, name, melee, agility, magic, luck):
        self.name = name, 
        self.melee = melee, 
        self.agility = agility,
        self.magic = magic,
        self.luck = luck
        
    def basic_description_2(self):
        print(self.basic_descr_2_str.format(*self.basic_descr2_format))

dorf = Player('dorf', 5, 10, 15, 20)

dorf.basic_description_2()

Reverting somewhat at least gives a result, but I have no explanation as to why it is so weird…

class Player:
    basic_descr2_str = "The name is: {name}. this character's melee \
capabilities are {melee}, agility seems to be pretty {agility}, he uses \
{magic} magic, and has {luck} luck."
    def __init__(self, name, melee, agility, magic, luck):
        self.name = name, 
        self.melee = melee, 
        self.agility = agility,
        self.magic = magic,
        self.luck = luck
        
    def basic_description_2(self):
        print(self.basic_descr2_str.format(
            name=self.name,
            melee=self.melee,
            agility=self.agility,
            magic=self.magic,
            luck=self.luck
        ))

dorf = Player('dorf', 5, 10, 15, 20)

dorf.basic_description_2()
=============== RESTART: D:/cc/discuss/users/kekpop/player.py ===============
The name is: ('dorf',). this character's melee capabilities are (5,), agility seems to be pretty (10,), he uses (15,) magic, and has 20 luck.
>>> 

Invited @appylpye to shed some light on this.

3 Likes

Concatenate first, interpolate after. You got the order of operations wrong that’s all (division/multiplication (modulo) has higher precedence than addition)

Also, while parsing your code, if you have strings next to each other without anything between them then they will get read as the same string:

>>> '%s' '%s' % ('hello', 'world')
'helloworld'

And you can put newlines between them (you should generally prefer parentheses over escaping newline in your code file, that’s a bit extreme!)

my_string = (
    'a'
    'b'
)  # 'ab'

There are also multiline strings, particularly useful for when there’s a LOT of text.

3 Likes

You can neaten it up using the advice of @mtf and @ionatan. There is an open parenthesis associated with the print statement to keep the statement going, as well as whitespace in the form of line breaks that can divide the long string into pieces that get concatenated back together as the expression is evaluated …

class Player:
    def __init__(self, name, melee, agility, magic, luck):
        self.name = name
        self.melee = melee
        self.agility = agility
        self.magic = magic
        self.luck = luck
    def basic_description_2(self):
        print("The name is: %s, "
              "this character's melee capabilities are %s, "
              "agility seems to be pretty %s, "
              "he uses %s magic, "
              "and has %s luck."
              % (self.name, self.melee, self.agility,
                 self.magic, self.luck)
              )

player_jim = Player("Jim", "high", "good", "no", "low")
player_jim.basic_description_2()

… and, yes, consider using other more recent techniques for formatting the string. If you are using the most recent version of Python, see PEP 498: Formatted string literals.

Edited on December 12, 2018 to add this:

    def basic_description_2(self):
        print(f"The name is: {self.name}, "
              f"this character's melee capabilities are {self.melee}, "
              f"agility seems to be pretty {self.agility}, "
              f"he uses {self.magic} magic, "
              f"and has {self.luck} luck."
             )
2 Likes

Okay so I think I get it now, I made this compilation here, 5 ways, I find the fifth way to be the best.

class Abilities(object):
    """A class describing basic abilities of a character, in this case it is a young lad called Jim."""

    def __init__(self, name, melee, agility, magic, luck):
        self.name = name
        self.melee = melee
        self.agility = agility
        self.magic = magic
        self.luck = luck

    def basic_description_1(self):  # very rough and time consuming way but works well, no placeholders used
        print("The name is: " + str(self.name) + ", this character's melee capabilities are " + str(self.melee) +
              ", agility seems to be pretty " + str(self.agility) + ", he uses " + str(self.magic) +
              " magic, and has " + str(self.luck) + " luck.")

    def basic_description_2(self):  # standard placeholders, backslash is used, aesthetically unpleasing  ( ╯°□°)╯ ┻━━┻
        print("The name is: %s, this character's melee capabilities are %s, \
agility seems to be pretty %s, he uses %s magic, and has %s luck."
              % (self.name, self.melee, self.agility, self.magic, self.luck))

    def basic_description_3(self):  # two strings manually concatenated
        print(("The name is: %s, this character's melee capabilities are %s, " +
               "agility seems to be pretty %s, he uses %s magic, and has %s luck.")
              % (self.name, self.melee, self.agility, self.magic, self.luck))

    def basic_description_4(self):  # multi line string, no need for a backslash used, aesthetically unpleasing ٩(`皿´҂)ง
        print("""The name is: %s, this character's melee capabilities are %s, 
agility seems to be pretty %s, he uses %s magic, and has %s luck."""
              % (self.name, self.melee, self.agility, self.magic, self.luck))

    def basic_description_5(self):  # pretty comfy way, you can put each placeholder with its string on its own line
        print("The name is: %s, "
              "this character's melee capabilities are %s, "
              "agility seems to be pretty %s, "
              "he uses %s magic, "
              "and has %s luck."
              % (self.name, self.melee, self.agility, self.magic, self.luck))


Jim = Abilities("Jim", "high", "good", "no", "low")

Jim.basic_description_1()
Jim.basic_description_2()
Jim.basic_description_3()
Jim.basic_description_4()
Jim.basic_description_5()

OUTPUT:

The name is: Jim, this character's melee capabilities are high, agility seems to be pretty good, he uses no magic, and has low luck.
The name is: Jim, this character's melee capabilities are high, agility seems to be pretty good, he uses no magic, and has low luck.
The name is: Jim, this character's melee capabilities are high, agility seems to be pretty good, he uses no magic, and has low luck.
The name is: Jim, this character's melee capabilities are high, 
agility seems to be pretty good, he uses no magic, and has low luck.
The name is: Jim, this character's melee capabilities are high, agility seems to be pretty good, he uses no magic, and has low luck.
2 Likes

Got it working but I put the string directly inside the print argument so I can use the automatic concatenation, makes the input look good and works well. Thank you

class Abilities(object):
    """A class* describing basic abilities of a character, in this case it is a young lad called Jim."""

    def __init__(self, name, melee, agility, magic, luck):
        self.name = name
        self.melee = melee
        self.agility = agility
        self.magic = magic
        self.luck = luck

    def basic_description_special_1(self):
        print("The name is: {name}. this character's melee "
              "capabilities are {melee}, agility seems to be pretty {agility}, he uses "
              "{magic} magic, and has {luck} luck.".format(name=self.name,
                                                           melee=self.melee,
                                                           agility=self.agility,
                                                           magic=self.magic,
                                                           luck=self.luck))


Jim = Abilities("Jim", "high", "good", "no", "low")
Jim.basic_description_special_1()

2 Likes

Can confirm that this gives an error

class Abilities(object):
    """A class describing basic abilities of a character, in this case it is a young lad called Jim."""

    def __init__(self, name, melee, agility, magic, luck):
        self.name = name
        self.melee = melee
        self.agility = agility
        self.magic = magic
        self.luck = luck

    def basic_description_6(self):
        basic_description_6_string = "The name is: {name}, this character's melee capabilities are {melee}, \
                                          agility seems to be pretty {agility}, he uses {magic} magic, and has {luck} luck."
        print(self.basic_description_6_string.format(name=self.name,
                                                     melee=self.melee,
                                                     agility=self.agility,
                                                     magic=self.magic,
                                                     luck=self.luck))

ERROR:

line 77, in basic_description_6
    print(self.basic_description_6_string.format(name=self.name,

AttributeError: 'Abilities' object has no attribute 'basic_description_6_string'

Fixed easily by removing .self from `print(self.basic_description_6_string.format()
The one right after the print argument on the beginning, see example above. I am pretty sure yours doesn’t work but correct me.

1 Like
    def basic_description_special_2(self):
        print(f"The name is: {self.name}, "
              f"this character's melee capabilities are {self.melee}, "
              f"agility seems to be pretty {self.agility}, "
              f"he uses {self.magic} magic, "
              f"and has {self.luck} luck."

Almost forgot to use this option, works the best honestly.

3 Likes