0

I have a bunch of functions that I am storing in a dictionary used to gather data from a more "cryptic" source (I have written functions to access this data).

In my code, I want to create "visibility" of what functions / parameters are loading variables used in the rest of the class. So, I would like to have a class where, upon init, a dictionary of functions stands up that can be used by further functions in the class. The issue I am running into is that I want these functions to be called only when they are retrieved from the dictionary by a later function. I do not want the functions evaluated upon init.

Problem: Some of the functions I am passing into the dictionary are "incomplete" as I would like to pass in additional parameters allowed via partial. The issue is that it appears init of the class evaluates all the functions in the dictionary rather than storing them as functions. I get an error from partial telling me that the first argument must be callable.

Here is an example of what I am doing (age works, month does not):

from functools import partial as part

class A:

    def __init__(self):

        self.rawInput={
                        'age':lu.source('personalInfo', 'age', asArray=1)                           
                        ,'month':lu.source('employInfo', 'months_employed')
                        }

        self.outputDict={}

        self.resultsDict={}

    class output(object):

        def age(self):            

            age = A().rawInput['age']
            return len(age)

        def month(self):            

            stuff=[]

            for x in range(0,1):
                month = part(A().rawInput['month'], x=x)
                stuff.append(month)

            return stuff

SOLUTION

Ah, looks like the posted summary from 7stud works. I just now just place the values / functions into the dict as partials with standard parameters and then pass additional ones as needed in the function call

from functools import partial as part

def source(name, attrib, none=None):

    if none!=None:
        print 'ham'
    else:
        print 'eggs'


class A:

    def __init__(self):

        self.rawInput={
                        'age':part(source,'personalInfo', 'age')                          
                        ,'month':part(source,'employInfo', 'months_employed')
                        }

        self.outputDict={}

        self.resultsDict={}

    class output:

        def age(self):            

            A().rawInput['age']()


        def month(self):            
            x = 1
            A().rawInput['month'](x)

c = A.output()
c.age()
c.month()

eggs
ham
m3m5rr
  • 125
  • 1
  • 1
  • 7
  • Why do you use `rawInput['age'],` in `month()`? – Mike Müller Dec 22 '15 at 23:55
  • Oh, that's a typo. I'll fix that. Also, added a few pieces to month() just to add more clarity. – m3m5rr Dec 23 '15 at 00:08
  • I wouldn't abbreviate `partial` to `part`. Your code will be much clearer if you use `partial`, which is a *term of art* from other languages, and it conveys meaning. – 7stud Dec 23 '15 at 01:15

1 Answers1

2

The issue is that it appears init of the class evaluates all the functions in the dictionary rather than storing them as functions.

() is the function execution operator. So, when you write:

'age':lu.source('personalInfo', 'age', asArray=1) 

the function lu.source is executed immediately, and the result is assigned to the "age" key in the dictionary.

Here's an example using partial:

from functools import partial

def myadd(x, y):
    return x+y

def mysubtract(x, y):
    return x-y


funcs = {}

funcs["add_3"] = partial(myadd, 3)
funcs["subtr_from_10"] = partial(mysubtract, 10)


print(
    funcs["add_3"](2)  #Note the function execution operator
)

print(
    funcs["subtr_from_10"](3)  #Note the function execution operator
)

--output:--
5
7

Note that in the line:

funcs["add_3"] = partial(myadd, 3)

the () is used with partial. So why does that work? It works because partial returns a function-like thing, so you end up with something like this:

funcs["add_3"] = some_func

Here is sort of how partial works:

def mypartial(func, x):

    def newfunc(val):
        return x + val

    return newfunc

add_3 = mypartial(myadd, 3)  #equivalent to add_3 = newfunc
print(add_3(2))  #=>5

Response to comment:

Okay, you could do this:

def myadd(x, y, z):
    return x+y+z

funcs = {}

funcs["add"] = {
    "func": myadd,
    "args": (3, 4)
}


func = funcs["add"]["func"]
args = funcs["add"]["args"]
result = func(*args, z=2)

print(result)  #=> 9

But that makes calling the function much more tortuous. If you are going to call the function with the arguments anyway, then why not imbed the arguments in the function using partial?

7stud
  • 46,922
  • 14
  • 101
  • 127