How to parse boolean with config parser - python

Using python's builtin configparser, I want to parse boolean values in my conf file.
Example:
[SECTION]
foo = False
However, when accessing the variable I notice that it is processed as a string.
>>> config['SECTION']['foo']
'False'
Furthermore, when I attempt to correct this behavior and reassign key foo to it's proper boolean representative, I get this error
>>> if config['SECTION']['foo'] == 'True':
... config['SECTION']['foo'] = True
... elif config['SECTION']['foo'] == 'False':
... config['SECTION']['foo'] = False
... else:
... Exception("foo must be bool")
TypeError: option values must be strings
Unfortunately, this behavior leads to problematic situations where the following performs unexpectedly
print(config['SECTION']['foo']) # 'False'
if config['SECTION']['foo']:
print('do things when foo is True') # this runs, but foo actually
# represents false, but in string form
How am I supposed to deal with booleans when parsing with configparser with the least amount of overhead as possible?

You want to use getboolean, a function on the section object.
For example
>>> config['SECTION'].getboolean('foo')
False
Documentation

Related

Redefine `False` in Python2? How to assign a function call to a variable name?

There isn't any reason in particular that I wish to do this, I just wanted to see False be True every once in a while.
import random
def dice():
return random.randint(1,3)==2
False = dice()
This will not give me what I want--I imagine False being initialized to some value as dice() is called, and thus remaining as that value thereon. How can I make it so that each time I check the value of False, it is as if I have called dice()?
If anyone has a better way to phrase this please feel free to provide an edit. Thanks.
To do this, you need more control over the name lookup procedure than Python ordinarily gives you. You need to execute the code in a namespace that uses name lookup rules you control, which means you have to use exec:
import random
class WeirdLocals(dict):
def __getitem__(self, index):
if index == 'False':
return random.choice([True, False])
return super(WeirdLocals, self).__getitem__(index)
exec '''
print False # Might print True
print False # Might print True
print False # Might print True
''' in globals(), WeirdLocals()
Note that functions defined inside an exec will ignore the provided locals for name lookup, and even if you try to provide a global dict with a weird __getitem__ override, they might bypass it anyway.
You cannot do that in either Python 2 or 3. You can assign a value to False in Python 2, but what you can't do is make it so that just reading the value of a plain variable (False or anything else) calls a function.
You can do it if the thing you're reading is not a bare-name variable but some kind of expression (like an attribute access). That is, you can make it so that something like a.b evaluates to a different value every time, but not so that just plain a evaluates to a different value every time.
If you can tolerate having to use . in your variable name, the #property decorator can give you want you want.
Example:
import random
class Foo:
def __init__(self):
pass
#property
def True(self):
return random.choice([True,False,True])
And then if you do
F=Foo()
print(F.True) #will return True 66% of the time and False 33% of
the time.
You can't do that with just False; if you're calling a function, you need to use the function syntax. You could do
False = dice
...
if my_value == False():
... action

Python "if" statement - if xpath is true

im trying to code in python (very new to it) and need to check if an xpath is there then variable = the xpath but if not variable = string.
An example is below
if tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()') = true
$value = tree.xpath('//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()')
else
$value = ''
You should really start by doing the whole official tutorial before anything else, as it will anwser your question.
First point : Python objects all have a 'truth' value in a boolean context, which is defined by the object's type and actual value. For builtin types, all empty containers (lists, dicts, sets etc), the empty string, all numerical zeros and the None object are false, everything else is true. For non builtin types you'll have to check the package's documentation.
The builtin type bool will also tell you the boolean value of a given object, so all of the below tests are equivalent:
if myobj:
xxx
if bool(myobj):
xxx
if bool(myobj) == True:
xxx
BUT keep in mind that it doesn't imply that bool(myobj) is the same as myobj - the first one is the boolean value of your object, so the following is NOT equivalent (unless myobj is one of True, 1 or 1.0):
if myobj == True:
xxx
Now wrt/ your actual code snippet: it's not valid Python (bad indentation, invalid identifier $value, invalid use of the assignment operator =, missing : after the if and else statements, wrong capitalization for True...)
Assuming you meant:
# let's make this at least readable:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
if tree.xpath(path) == True:
value = tree.xpath(path)
else:
value = ''
The obvious error is the explicit test against True (tree.xpath() doesn't return a boolean). You either have to explicitely cast the return of tree.xpath() to a boolean (which is quite verbose, totally useless and definitly unpythonic) or just let Python do the right thing by removing the == True part of your test.
As a side note: calling tree.xpath twice in a row with the same argument is a waste of processor cycle (both calls will return the same value), so use a variable instead - it will also make your code much more readable and maintainable. The Pythonic version of your code would look something like:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
found = tree.xpath(path)
value = found if found else ''
or even more simply:
path = '//*#id="page"]/div[1]/div/main/div/article/div/div[1]/section[2]/p[1]/span/text()'
value = tree.xpath(path) or ''
since the or operator will not yield a boolean value but either the first of it's operand that has a true value or the last operand if none has a true value.
#No need to test == if value is bool. and you not check, you assign value with one =
if anything:
#Then do this
else:
#Do this

Compare two Python strings with hyphen/dash

I am trying to compare to strings in Python and noticed that when a dash/hyphen is present in the string it will not equate identical strings. For example:
>>>teststring = 'newstring'
>>>teststring is 'newstring'
True
Then, if I add a dash
>>>teststring = 'new-string'
>>>teststring is 'new-string'
False
Why is that the case, and what would be the best way to compare strings with dashes?
you should never use is to compare equality anyway. is tests for identity. Use ==.
Frankly I don't know why 'newstring' is 'newstring'. I'm sure it varies based on your Python implementation as it seems like a memory-saving cache to re-use short strings.
However:
teststring = 'newstring'
teststring == 'newstring' # True
nextstring = 'new-string'
nextstring == 'new-string' # True
basically all is does is test ids to make sure they're identical.
id('new-string') # 48441808
id('new-string') # 48435352
# These change
id('newstring') # 48441728
id('newstring') # 48441728
# These don't, and I don't know why.
You should not use is for string comparison. Is checks if both objects are same. You should use equality operator == here. That compares the values of objects, rather than ids of objects.
In this case, looks like Python is doing some object optimizations for string objects and hence the behavior.
>>> teststring = 'newstring'
>>> id(teststring)
4329009776
>>> id('newstring')
4329009776
>>> teststring = 'new-string'
>>> id(teststring)
4329009840
>>> id('new-string')
4329009776
>>> teststring == 'new-string'
True
>>> teststring is 'new-string'
False

Python string function isidentifier()

I'm working through a Python 3 book and came across the string function isidentifier(). The text description is "s.isidentifier() : Returns True if s is non empty and is a valid identifier". I tested it in the Python Shell like this:
>>> s = 'test'
>>> s.isidentifier()
True
>>> 'blah'.isidentifier()
True
I would expect the 2nd statement to return false since 'blah' is not held in a variable. Can anyone explain this? Thanks.
Returns True if s is non empty and is a valid identifier.
What they mean is that s could be valid as an identifier. It doesn't imply that it is an identifier that's in use.
Your first example is showing the same thing: 'test' (what isidentifier is actually checking) is not the name of a variable either. I think you meant
>>> 's'.isidentifier()
True
"isidentifier" doesn't say anything about the "variable" the string being tested is referenced by. So
'blah'.isidentifier()
is identical to
s = 'blah'
s.isidentifier()
In Python, it's never (or rarely) about the "variable" (Python doesn't have variables), it's about the object. In this case, strings.
Python doesn't have "variables". It is more helpful to think in terms of objects.
'blah' definitely exists at the time 'blah'.isidentifier() is called (after all it means that "call isidentifier() method of the string object 'blah'").
So if your understanding were correct, isidentifier() method of string objects should always return True, because at the time of the call, the object definitely exists.
What isidentifier() does is to check that the string object can be used as a valid identifier. Try these two lines in your Python session for example:
>>> a = "$"
>>> "$".isidentifier()
Even though "$" is assigned to the name a, the isidentifier() call returns False since $ is not a valid identifier in Python.
isidentifier is a Python function that simply tests whether a string contains only certain characters (underscore, digits, and alphas) and starts with an alpha or an underscore, so the string can be used for a valid Python identifier. Other functions that test for character classes are isalpha, isalnum, isdigit, and others.
ss = (
'varABC123',
'123ABCvar',
'_123ABCvar',
'var_ABC_123',
'var-ABC-123',
'var.ABC.123',
# check your own strings
)
fmt = '%-15s%-10s%-10s%-10s%-10s'
print(fmt % ('', 'isalpha', 'isalnum', 'isdigit', 'isidentifier'))
for s in ss:
print(fmt % (s, s.isalpha(), s.isalnum(), s.isdigit(), s.isidentifier()))
Result:
isalpha isalnum isdigit isidentifier
varABC123 False True False True
123ABCvar False True False False
_123ABCvar False False False True
var_ABC_123 False False False True
var-ABC-123 False False False False
var.ABC.123 False False False False

Why does assigning to True/False not work as I expect?

As part of answering another question, I wrote the following code whose behaviour seems bizarre at first glance:
print True # outputs true
True = False; print True # outputs false
True = True; print True # outputs false
True = not True; print True # outputs true
Can anyone explain this strange behaviour? I think it has something to do with Python's object model but I'm not sure.
It's version 2.5.2 under Cygwin.
Python has these two (among others) builtin objects. They are just objects; in the beginning, they don't have any names yet, but to know what we refer to, let's call them 0x600D and 0xBAD.
Before starting to execute a Python (2.x) script, the name True gets bound to the object 0x600D, and the name False gets bound to the object 0xBAD, so when the program refers to True, it looks at 0x600D.
Because 0x600D and 0xBAD know that they are usually used by the names True and False, that's what they output when they get printed, i.e. the __str__ method of 0x600D returns 'True' and so on.
True = False
now binds the name True to a different object. From now on, both names True and False refer to the same object 0xBAD, which, when printed, outputs False.
True = True
doesn't really do anything: It takes the object referred to by the name True, and binds the new (and old) name True to this object. Since (because of the previous step) True refers to 0xBAD before this, it still refers to 0xBAD after this. Hence, printing still outputs False.
True = not True
first takes the object that the name True is bound to, which is 0xBAD. It gives this object to the not operator. not doesn't care (or know) what name is used here to refer to 0xBAD, it just knows that when given 0xBAD it should return 0x600D. This return value is then given to the assignment operator =, binding the name True to this object.
Since the name True now once more refers to the object 0x600D, calling print True outputs True, and the world is good again.
Imagine this instead:
A = True
B = False
print A # true
A = B; print A # false
A = A; print A # false, because A is still false from before
A = not A; print A # true, because A was false, so not A is true
The exact same thing is going on, but in your version it's confusing, because you don't expect that you can redefine True and False.
In 2.x, True and False are not keywords so it's possible to shadow the built-ins in this manner.
You can check whether True/False is a keyword:
>>> import keyword
>>> keyword.iskeyword('True')
False
Since it's not (in my version), assigning True=False just means "True" is another "variable" name.
You could easily restore the original values using simple Boolean comparisons:
True = 1==1
False = 1==0
Or by converting integer literals to bools:
True = bool(1) # actually every number except 0 works
False = bool(0)

Categories

Resources