[BangPypers] BangPypers Digest, Vol 86, Issue 16

Noufal Ibrahim KV noufal at nibrahim.net.in
Mon Oct 27 16:58:58 CET 2014




On Mon, Oct 27 2014, Okan bhan wrote:

> 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 at python.org
> https://mail.python.org/mailman/listinfo/bangpypers
>

-- 
Cordially,
Noufal
http://nibrahim.net.in


More information about the BangPypers mailing list