Hi Noufal, Thanks for responding and helping me explaining these. I see lots of my doubts are clear, except last (c). My explanations are inline.
> A simple implementation of this is: > > > > class SimpleMapping: > > def __init__(self, items): > > self._items = items > > > > def __getitems__(self, subitem): > > print('*' * 20) > > for item in self._items: > > if subitem in item: > > return True > > return False > > This is broken in two ways > 1. The magic method is __getitem__ (not __getitems__). I'm assuming it's > a typo otherwise, the rest of your code will not work even as you've > mentioned. > Yes. Indeed it should be __getitem__. It was typo while manually typing in gmail. > 2. A mapping object is similar to a dictionary. It should > return the actual object if you try to access it. Not a boolean True > or False. > Agree with you. Ideally it should have returned object and I can test by `if obj` or `if not obj`. Lets assume for now I want to continue with this. > > The mapping objects given are specifications of the locals and globals > in which you will evaluate your string. Consult help("eval") for more > information. > > eval(source[, globals[, locals]]) -> value > Makes sense. So essentially I'm trying to evaluate and expression ('foo' or 'foo and bar') against a local mapping. Not fully confident but I can see the use of locals & globals here. > Look at my comment above. Your Mapping object is flawed and all these > responses are quite wrong. > Yes. Sorry for the typo. Without typo these will be the expected answers. > > > > >>>> eval('5.6', {}, mapping) > > 5.6 > > I'm not sure how this will work. In my case, I see this. > > >>> mapping = SimpleMapping(set(['aaa', 'bbb', 'ccc'])) > >>> eval('5.6', {}, mapping) > Traceback (most recent call last): > File "<stdin>", line 1, in <module> > TypeError: locals must be a mapping > >>> > > That is strange, I'm still getting 5.6 as result. I tried on different python versions as well. > > >>>> eval('aa.a', {}, mapping) > > AttributeError: 'bool' object has no attribute 'a' > > > > > My doubts are: > > a. Why it didn't run for numeric 5.6? Also why is dot separated '5.6' any > > different to 'aa.a'? I looked around on eval documentation and examples > but > > couldn't find use of eval with a mapping. > > 5.6 is not an attribute access. 5.6 is is a floating point number. aa.a > is an attribute access. It will first return False for `aa` since there > is no such key and your code returns False and then try to access `a` in > the Boolean which, predictably, fails. > > Big thanks for this. Let me explain what, I understood here. Lets say statement we want to evaluate is `eval(expression)`. Python starts checking 'expression' against each datatype starting from int -> float -> str. For all native datatypes, it will return corresponding result. Finally if it doesn't matches any of native types, tries to access against mapping(or any other object in local or global scope). Which is the reason, >> type(eval('5.6')) is float >> type(eval("'5.6'") is str (expression is under double quotes). For the case of eval('aa.a'), it first tries to match 'aa'. This is not any native type so goes to check in mapping and finds it True. Then tries to find attribute 'a' of returned type (a boolean). Hence boolean object has no attribute 'a'. > > b. I see many blogs suggesting to refrain from using eval unless > > absolutely needed. Is this one use case we must use it? Do we have any > > better way to evaluate this? > > I'm not sure what exactly you want to do. Can you explain again? > I came across blog posts suggesting not to use eval mostly as it can lead to un-secure code. So wanted to check should I put efforts in solving this with 'eval' or not. Not an option now. I will explain my problem in next question. > > > c. If indeed, I have to evaluate a string containing dots, how to do > > in the above scenario? > > The object whose attribute you're trying to access should be there in > the locals or globals and then should have an attribute with the given > name. It will work then. > [...] > yes. If my above observation is correct, this is clear to me. I will try to explain my problem: I have a list of strings ( say ['aaa', 'bbb', '4.5-'] ) and I want to check if an expression (say 'aa') is a substring of any of this item. Simply: all([ item for item in ['aaa', 'bbb', '4.5-'] if 'aa' in item]) ==> gives True as 'aa' is a substring of 'aaa'. But my expression can be a logical expression like 'aa or bb', 'aa and bbb', 'aaa and 4.5' etc. This works in my above implementation. If we assume mapping object from above. Writing it again here for ease. > class SimpleMapping: > def __init__(self, items): > self._items = items > > def __getitem__(self, subitem): > for item in self._items: > if subitem in item: > return True > return False >>> mapping = SimpleMapping(set(['aaa', 'bbb', '4.5-'])) >>> eval('aa and bb', {}, mapping) True # since both are substring >>> eval('aa and bbb', {}, mapping) True # again since both are substring >>> eval('aa and bbbb', {}, mapping) False # 'bbbb' fails. So till now it works fine for my case. But in case if I want to check for '4.5' in this. >>> eval('aaaa or bbbb or 4.5') 4.5 # Fails for 'aaaa', fails for 'bbbb' but evaluates '4.5' as 4.5. Something I don't want. It should be checking 4.5 against mapping and I want a boolean True here. If I am unclear, I will repeat my problem again. Problem: How can I evaluate a logical expression, in python where expression contains a dot ('.'). Analysis: First thing strike in my mind is to use eval but that fails on expression with a dot. My tries are: *Try A:* I was thinking something like, transform '.' to '#' (or anything else). For eg. 'aaaa or bbbb or 4.5' becomes 'aaaa or bbbb or 4#5'. Now if eval('4#5') goes to check inside our mapping we are good. We can transform back and evaluate. But sadly eval('4#5') gives 4. Tried with many characters, any hits here? *Try B:* Other option is extracting operators out of string ( by list comprehension or using regular expression) and operator on these string components. Is there any direct way to get logical operators from string. I found (c for c in s if c in '+-/*()_') to get mathematical operators. I will try this option tonight. Sorry for long reply and redundant answer but I wanted to be clear. If I was able to explain properly can you suggest anything here? Thanks & Regard Alok _______________________________________________ BangPypers mailing list BangPypers@python.org https://mail.python.org/mailman/listinfo/bangpypers