views:

131

answers:

2

I have a dict of configuration variables that looks something like this:

self.config = {
    "foo": "abcdef",
    "bar": 42,
    "xyz": True
}

I want to be able to update these variables from user input (which, in this case, will always be in the form of a string). The problem I'm facing is obvious, and my first solution seemed good enough to me:

def updateconfig(self, key, value):
    if key in self.config:
        self.config[key] = type(self.config[key])(value)

However, #python in Freenode almost seemed offended that I would suggest such a solution. Could someone tell me why this is bad practice?

+5  A: 

Not all types support the idiom "call the type with a string to make a new instance of that type". However, if you ensure you only have such types in your config dict (with a sanity check at init time maybe), and put suitable try/except protection around your conversion attempt (to deal with user errors such as typos in a far better way than dying with a stack trace would be;-), there's nothing "inherently wrong" in using that functionality for the types that do support it.

Alex Martelli
+1 discouraging use of language features seems too prevalent in python. It's like people want a weaker language.
aaronasterling
`bool("False") -> True` is a type where this doesn't quite work.
THC4k
@THCk, `type(True)(False) -> False` which is closer to the use case.
aaronasterling
@THC4K, yep, good example. Among the 27 non-exception built-in types, the "really good ones" (where `repr(type(x)(repr(x)) == repr(x)`) are just float, long, int, complex -- str will be OK for the OP's case too (since it's not really `repr` that he's using, but an arbitrary string;-), unicode will be only with limitations (ASCII chars only!). Worst will be ones line bool, tuple, set, list, which _look_ like they'll work in that they'll raise no exception... but will perform weirdly (unless, in the containers' case, you **do** want containers with single-char items only;-).
Alex Martelli
@aaron (2nd cmt), **what**?! The OP **does** say that the input "is always in the form of a string" -- your "closer to the use case" example is therefore not close at all! (1st cmt) there are features , such as sufficiently-deep introspection, that are there solely to ease writing (e.g.) thorough tests / debuggers / IDEs in Python itself, and **should** be discouraged for use in **production** code. `type(x)(y)` (for the right, small set of types, able to "properly" build instances from a string: numbers and strings). The right string can be non-obvious (`''` is *the* way to say `False`!-).
Alex Martelli
A: 

Not to mention, that there is config module in Python, here is how I would deal with config, with example of integer value "bar". +1 for alex as '' for the way to say False, see value "xyz"!

config = {
    "foo": "abcdef",
    "bar": "42",
    "xyz": "True" ## or 'Yes' or anything not False, "" for False
}

bar = ''
while not bar:
    barinput = raw_input('Enter property  bar, integer (1..99): ')
    try:
        if 0 < int(barinput) < 100:
            pass
        else:
            raise ValueError("%s is not integer in range 1..99" % barinput)
    except ValueError as e:
        print(str(e)+"\nWrong input, try again")
    else:
        print("Saving correct value")
        bar = config["bar"] = barinput
print('New value of "bar" in config: %i' % int(config["bar"]))

The value could be saved as int in config also, but we have not need for type as we know that we are inputing integer.

Tony Veijalainen