简体   繁体   中英

Using expression as a keyword argument for String Template identifiers (Python)

I am using standard library string template . From the template, I make a list that contains all the identifiers. For example:

list_of_identifiers = ['id', 'username', 'url']

I want to iterate this list to substitute the template identifier.

xml = string.Template(xml_template)
for i in range(len(list_of_identifiers)):
    xml.substitute(list_of_identifiers[i] = somevalue)

But I am getting a syntax error SyntaxError: keyword can't be an expression . I want to use the string literal in the list_of_identifiers[i] as a keyword. Is it possible?


Edit

What I am basically doing here is reading a csv file with the values of identifiers and then substituting the values into the xml template. But the csv file can include other fields than just the identifiers. In other words the csv file could read:

id, username, orientation, eye, expression, url
1, admin, left, sunglasses, sad, http://google.com

However the identifiers that I want to substitute are [id, username, url] only. So I generate two lists:

list_of_identifiers = ['id', 'username', 'url']
col_index = ['0','1','5']

As you might tell, col_index is the the indexes of the identifiers in the csv row . So I iterate both of the lists:

with open(dataFile, 'rb') as csvFile_obj:
    reader = csv.reader(csvFile_obj)
    for row in reader:
        #
        #some code to filter out first line of csv file
        #
        xml = string.Template(xml_template)
        for i in range(len(list_of_identifiers)):
            xml.substitute(list_of_identifiers[i]= row[col_index[i]])

As mentioned elsewhere, substitute doesn't do what you think it does - you need to substitute all the variables at once. Using DictReader makes things slightly easier for you too:

columns = ['id', 'username', 'url']

with open(dataFile, 'rb') as csvFile_obj:
    reader = csv.DictReader(csvFile_obj)
    for row in reader:
        xml = string.Template(xml_template).substitute({
            col: row[ident]
            for col in columns
        })

What you're trying to do isn't directly possible. Keywords in function calls have to be identifiers, not expressions. More importantly, however, keywords are static things--the identifier itself is the keyword, not the current value of some variable with that name.

If you want to dynamically pass keywords to a function call, you can use dict unpacking. For example, the following are equivalent:

spam(name=value)
spam(**{'name': value})

So, in your case:

xml.substitute{**{list_of_identifiers[i]: somevalue})

However, you're probably overcomplicating the code. Notice that substitute can just take a mapping as a (non-keyword) argument, so there's no need to unpack one into separate keyword arguments. Plus, instead of looping and substituting each one separately, why not just substitute them all at once?


A couple of side notes:

  • If you want to loop over all elements of a list, just do for identifier in list_of_identifiers: .
  • substitute doesn't do what you think it does. It returns a string with the template variables substituted for their arguments; it doesn't modify the template in-place, partially substituting.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM