0

I'm trying to pull data from a dictionary ('data') in which several series are provided:

For instance, equity is extracted with:

data['Financials']['Balance_Sheet']['equity']

As I'm having several functions each calling one different series (e.g. equity, debt, goodwill, etc...), I would like to be able to define the "access" for each of those by defining a string such as:

Goodwill -> data['Financials']['Balance_Sheet']['Goodwill']
Equity->data['Financials']['Balance_Sheet']['Equity']

My idea is to do something like that:

Data_pulled= ACCESS('data['Financials']['Balance_Sheet']['Goodwill']')

What is the ACCESS function required to transform the string into a acccess function?

Hope this is clear! Thanks a lot for your help guys - much appreciated! :)

Max

rafaelc
  • 57,686
  • 15
  • 58
  • 82
Maxime
  • 13
  • 2
  • What you want to do is `eval()` – rafaelc Jul 12 '18 at 20:26
  • you can use `eval()` to achieve this. You can refer this answer (https://stackoverflow.com/questions/9383740/what-does-pythons-eval-do) – Sheshnath Jul 12 '18 at 20:34
  • Don't use `eval()`. `eval()` is not safe programming. – VoNWooDSoN Jul 12 '18 at 20:38
  • Note that you can't embed a single-quoted string into another single-quoted one. Therefore your proposed syntx should be rewritten as: `Data_pulled= ACCESS("data['Financials']['Balance_Sheet']['Goodwill'"')` – davidedb Jul 12 '18 at 20:39

1 Answers1

0

I question what you're trying to accomplish here. A better answer is probably to write a accessor function that can safely get the field you want without having to type the whole thing out every time. Consider the following code:

def ACCESS(*strings):
    def ACCESS_LAMBDA(dic):
        result = dic
        for key in strings:
            result = result[key]
        return result
    return ACCESS_LAMBDA

dic = { 'aa': { 'bb': { 'cc': 42 } } }

ABC_ACCESS = ACCESS('aa','bb','cc')
print ABC_ACCESS(dic)

This is called a closure, where you can define a function at runtime. Here you'd create pull_goodwill = ACCESS('Financials','Balance_Sheet','Goodwill') then get the value with Data_pulled = pull_goodwill(data)

This doesn't exactly answer your question, and the star-arguments and Lambda-returned-function are pretty advanced things. But, don't just "call eval()" that's a pretty insecure coding habit to get into. eval() has its uses... But, think about what you're trying to do, and see if there is a simple abstraction that you can program to access the data you want, rather than relying on the python parser to fetch a value from a dict.

edit: Link to information about closures in python

edit2: In order to not have to pass a dictionary to the returned lambda-function, you can pass it into the function constructor. Here's what that would look like, note the change to ACCESS's definition now includes dic and that the ACCESS_LAMBDA definition now takes no arguments.

def ACCESS(dic, *strings):
    def ACCESS_LAMBDA():
        result = dic
        for key in strings:
            result = result[key]
        return result
    return ACCESS_LAMBDA

dic = { 'a': { 'b': { 'c': 42 } } }

ABC_ACCESS = ACCESS(dic, 'a','b','c')
print ABC_ACCESS()

(Note here, that if dict is modified, then the ABC_ACCESS value will change. this is because python passes by reference, if you want a constant value you'd need to make a copy of dic.)

VoNWooDSoN
  • 1,173
  • 9
  • 13
  • Thanks a lot for your help VoNWoodSoN, much appreciated. I just wanted to know if there was a simpler way to do it. I understand the security issue of eval() so will like to avoid using it. As the values I'm trying to pull will always be in the "data" variable, would there be a way to use "data" + specific_root, where root could be "['Financials']['Balance_Sheet']['Goodwill']" or ['Financials']['Balance_Sheet']['Equity']? Thanks a lot, very much appreciate! – Maxime Jul 13 '18 at 05:41
  • See edit2. Now, I'm not trying to force closures on you, but they "close around" free variables, so if the base is always the same, then you can use this same paradigm to do what you're looking for, by passing the root into the function as well. – VoNWooDSoN Jul 13 '18 at 13:29
  • Thanks for the follow-up VoNWooDSoN. I think I understand what you are suggesting to do. I've taking your code but it returns me .ACCESS_LAMBDA()> Am I doing something wrong? Thanks a lot! – Maxime Jul 13 '18 at 16:25
  • so the value returned from calling `ACCESS` is a function that must be evaluated. check out the print statement `print ABC_ACCESS()` and notice the `()`. Because it's a function, you need to call it to get the value out. – VoNWooDSoN Jul 13 '18 at 17:35
  • Yeah. I get that .ACCESS_LAMBDA()> when I execute "ACCESS(dic,'a','b','c')". When executing "print ABC_ACCESS()", I get File "", line 19 print ABC_ACCESS() ^ SyntaxError: invalid syntax – Maxime Jul 13 '18 at 18:36
  • I'm using python 2.7 try `print(ABC_ACCESS())` – VoNWooDSoN Jul 19 '18 at 21:03