1

I am writing a sample greeting program. I have a random list of greeting message with template string as name.

My code is as below

from random import  randint

random_greeting = [
    "Hello {name}, Hope you are doing well",
    "Hello {name}, Hope you are having a great day",
    "Hello {name}, Nice to meet you"
    ]

class Greetings(object):

    global random_greeting

    def read_input(self):
        return input("What is your name? ")

    def print_greeting_rand(self, name):
        greet_length = len(random_greeting)
        random_int = randint(0, greet_length-1)
        message = random_greeting[random_int]
        print(f"{message}") # Here {name} not coming into scope

if __name__ == "__main__":
    greet = Greetings()
    name = greet.read_input()
    greet.print_greeting_rand(name)

So random_greeting have list of messages with name as template string {name}. In the function print_greeting_rand I am fetching greeting message based on random index and printing using Python F-Strings, {name} is not interpreting as expected.

Any suggestions please ?

Raja G
  • 5,973
  • 14
  • 49
  • 82
  • 2
    I don't think you can do that with f strings (except possibly with some nasty `eval` hack). You can just do `message.format(name=name)` – alani Jul 18 '20 at 18:58
  • @alaniwi, yes, can you add more information about `eval` hack. Please. Thank you. – Raja G Jul 18 '20 at 19:18
  • @wjandrea, Yes I think I can use that method. – Raja G Jul 18 '20 at 19:20
  • @rɑːdʒɑ re `eval`, someone has posted an answer to that effect on the page that wjandrea linked. But it is not to be recommended. – alani Jul 18 '20 at 19:20
  • @alaniwi: Well, you can, albeit not with f-strings alone. – Jan Jul 18 '20 at 19:23
  • 1
    @Jan My point is that getting variables by name at run-time is inevitably going to be hacky. Hence no doubt the reason why you used a `kwargs` dictionary in your answer instead. – alani Jul 18 '20 at 19:32
  • @alaniwi: True indeed. Python is not lisp ;-) – Jan Jul 18 '20 at 19:33

3 Answers3

2

You may leverage a simple regular expression and **kwargs:

import random, re

class Greetings(object):
    greetings = [
        "Hello {name}, Hope you are doing well {when}",
        "Hello {name}, Hope you are having a great day",
        "Hello {name}, Nice to meet you"
    ]
    rx = re.compile(r'{([^{}]+)}')
    vars = {}

    def read_input(self):
        return input("What is your name? ")

    def print_greeting_rand(self, **kwargs):
        self.vars = kwargs
        tmpl = self.rx.sub(self.__replace__, random.choice(self.greetings))
        print(tmpl)

    def __replace__(self, m):
        var = m.group(1)
        if var in self.vars:
            return self.vars[var]
        return m.group(0)


if __name__ == "__main__":
    greet = Greetings()
    greet.print_greeting_rand(name=greet.read_input(), when="today")

Explanation:

This scans the string for any variable of the form { + variable_name + } and substitutes it when it finds it within the **kwargs parameter. If it is not found, it simply returns {variable_name}, that is leaving it untouched.

See a demo for the expression on regex101.com.

Jan
  • 42,290
  • 8
  • 54
  • 79
1

Unfortunately with f-strings you can't do this as they are evaluated immediately and so what you can do instead is use:

from random import choice

random_greeting = [
    "Hello {name}, Hope you are doing well",
    "Hello {name}, Hope you are having a great day",
    "Hello {name}, Nice to meet you"
    ]

def print_greeting_rand(self, name):
    message = choice(random_greeting)
    print(message.format(name=name))
Harben
  • 1,802
  • 1
  • 11
  • 16
  • The first of these is no longer recommended in new code. – alani Jul 18 '20 at 19:02
  • 2
    I would recommend completely removing the old-style formatting recommendation, and just keep `.format`. The [Python official docs](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting) recommend against old-style formatting. – SethMMorton Jul 18 '20 at 19:03
  • @alaniwi I am just giving options – Harben Jul 18 '20 at 19:03
  • 1
    @Harben Options are fine when the options are good. In this case, the first option is not good. – SethMMorton Jul 18 '20 at 19:04
1

You want

print(message.format(name=name))

The same holds true with an f-string as well.

print(f'{message}'.format(name=name))
Balaji Ambresh
  • 4,977
  • 2
  • 5
  • 17