DunkeyKing
DunkeyKing

Reputation: 43

How to pass a function or expression as an argument?

I am trying to make a complete function, that takes in an expression:

def graph(formula):
    fig = plt.figure()
    ax = fig.gca(projection='3d')

    X = np.arange(-50, 50, 0.5)
    X = X[X != 0]
    Y = np.arange(-50, 50, 0.5)
    Y = Y[Y != 0]
    X, Y = np.meshgrid(X, Y)

    Z=[[0],[0]]
    expression = "Z=" + formula
    exec(expression)

Now I want to do graph("X+Y"), and then it should do Z = X + Y. It doesn't do that. I have tried doing the same with eval instead of exec, but no luck.

Upvotes: 1

Views: 171

Answers (2)

theQuantumMechanic
theQuantumMechanic

Reputation: 82

I assume you mean to pass to your function like so (to calculate Z),

def graph(formula)
    ...
graph(X+Y)
...

If so, why not just pass to separate values (or arrays of values)? Such as,

def graph(x, y):
    ...
graph(4, 5)
...

or,

mypoints = [[1, 3], [4, 8], [8, 1], [10, 3]] # 2-D array
def graph(XY):
    for point in XY:
        x = point[0]
        y = point[1]
.... # everything else

graph(mypoints )
...

For a full example of this, check out Method: Stats.linregress( ) in this article (scroll down a bit).

Otherwise, you could:

  • pass the data as an array (a table of X, Y values if you will).
  • if it is a super complex formula that will have a bunch of attributes and methods attached to it (such as including complex numbers), perhaps creating a Formula class.

You could also write a function using the lambda syntax. This would give you the freedom of having an object (like I suggested above) as well as a "function" (of course they are practically synonymous). Read more in the docs.

Upvotes: 0

Blckknght
Blckknght

Reputation: 104792

It sounds like you want to pass a "formula" that computes Z from X and Y. Rather than using exec or eval and running into issues with namespaces, a better way to do that is to pass in a function. As user s3cur3 commented, an easy way to do that is with a lambda expression:

def graph(func):
    # set up X and Y up here

    Z = func(X, Y)

    # do stuff with Z after computing it?

graph(lambda X, Y: X+Y)

If you need more complicated logic that you can fit in a lambda, you can write out a full function if you need to:

def my_func(x, y):  # this could be done in a lambda too, but lets pretend it couldn't
    if random.random() < 0.5: 
        return x + y
    return x - y

graph(my_func)

Upvotes: 3

Related Questions