8

The empty string ('') is a pertectly valid key for a dictionary, but I can not reference it using the Format String Syntax

data = { 'a' : 'hello' , '' : 'bye' }
print '{a:<14s}'.format(**data)
print '{:<14s}'.format(**data)

Which outputs:

hello         
Traceback (most recent call last):
  File "xxx.py", line 3, in <module>
    print '{:<14s}'.format(**data)
IndexError: tuple index out of range

Is there any way of referencing that key ... as a dictionary key! I can not convert the data to tuples; a bit of background: I am doing some auto-formatting based on a generic format spec which gets converted to Format String Syntax using dicts as data for the formatting. That is, I can not do this:

print '{0:<14s}'.format(data[''])

The data must always be passed to format as **data (basically, because I am doing a generic .format(**data) in my formatter class)

2 Answers 2

7

You can't use an empty string. The format strictly limits keys to valid Python identifiers, which means they have to have at least 1 letter or underscore at the start.

From the grammar in the Format String Syntax documentation:

replacement_field ::=  "{" [field_name] ["!" conversion] [":" format_spec] "}"
field_name        ::=  arg_name ("." attribute_name | "[" element_index "]")*
arg_name          ::=  [identifier | integer]

So the field_name is either an integer or a valid Python identifier.

Note that empty strings are not the only stings that are not valid identifiers; you cannot use strings with spaces in it either, or strings that start with a digit. Such strings can be used in a dictionary, just not as keyword arguments in Python code nor as field names in string formats.

Sign up to request clarification or add additional context in comments.

2 Comments

Is there any standard way of "sanitizing" dictionary keys so that they are valid python identifiers? A kind of "default transformation" that converts spaces to underscores, and other trickery so that from an arbitrary dictionary key we get a (similar) valid python identifier? Something like: '' -> '_', '0' -> '_0', 'key with spaces' -> 'key_with_spaces'. I understand this is very specific and probably impossible to get foolproof (collissions are to be expected), but I am probably not the first facing this problem, so maybe a half-backed solution is already out there?
@jeckyll2hide: Not that I am aware of, but it's not that hard: Prefix with a _ if the first character is a digit, replace everything that's not a letter, digit or underscore with something that is a letter, digit or underscore. Optional: append digits to make the value unique.
1

An 'arg_name' can be an identifier, so you can assign the empty string to a variable and use it as a key in a dictionary. This example assumes that the RETURN key is pressed to produce the empty string for a comparison:

empty = ''

test = {
    "notso" : "You pressed some other key",
    empty: "You pressed the RETURN key"
    }

char = input("Press the RETURN key: ")
print(test[empty]) if char == empty else print(test["notso"])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.