How do you do a python 'eval' only within an object context?

前端 未结 4 2021
慢半拍i
慢半拍i 2021-02-14 14:41

Is it possible to do something like

c = MyObj()
c.eval(\"func1(42)+func2(24)\")

in Python..i.e. have func1() and func2() be evaluated within th

4条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-14 14:44

    The solution proposed above to populate locals works well in most cases, but may be problematic in case of properties (data descriptors). These are evaluated once when the dictionary is populated. This means that multiple references to the same variable name will always return the exact same instance, which may not be expected behavior in case of properties.

    This problem can be solved by noting that eval expects a locals argument that behaves like a dict (as opposed to globals, which must be a dict). In other words, we can override __getitem__ in your instance to resolve variable names on the fly in the context of the instance and pass it directly as locals attribute to eval. Your example can thus be implemented as:

    class Formula(object):
        def __getitem__(self, key):
            if key not in dir(self) or key.startswith('__'):
                raise KeyError(key)
            return getattr(self, key)
    
        def LEFT(self, s, n):
            return s[:n]
    
        def RIGHT(self, s, n):
            return s[0-n:]
    
        def CONCAT(self, *args, **kwargs):
            return ''.join([arg for arg in args])
    
    
    def main():
        evalString = "CONCAT(LEFT('Hello', 2), RIGHT('World', 3))"
        print eval(evalString, {}, Formula())
    
    if __name__ == "__main__":
        main()
    

    This trick should work with inheritance, static methods, class methods and properties. Finally, using dir and getattr avoids the need to interact directly with __dict__ or __mro__, though the results of dir may not always be complete.

提交回复
热议问题