Monthly Archives: March 2017

Python tip: Inspect function signature at runtime

Problem:

I have a list of functions with different signatures. There is some set of possible parameters, and I want to call all these functions with the “appropriate” argument for each parameter.

This is a little hand-wavy, let’s look at an example:


def half(a):
    return a / 2

def twice(a):
    return 2 * a

def addition(a, b):
    return a + b

def subtraction(a, b):
    return a - b

functions = [half, twice, addition, subtraction]
a = get_a()
b = get_b()

Desired outcome:

[half(a), twice(a), addition(a,b), subtraction(a, b)]

And we want to do this without making our function definitions too ugly.

Solution 1:

One option is to `get_b()` within the functions that need them. This is not ideal, suppose `get_b` is not a pure function (e.g. a network call), we would want to pass `b` into scope instead of getting it from elsewhere every time it’s needed.

Solution 2:

We could change the signature to accept arbitrary kwargs and then pass a dict of args, for example:

def half(**kwargs):
    return kwargs['a'] / 2

def twice(**kwargs):
    return 2 * kwargs['a']

def addition(**kwargs):
    return kwargs['a'] + kwargs['b']

def subtraction(**kwargs):
    return kwargs['a'] - kwargs['b']

functions = [half, twice, addition, subtraction]
payload = {'a': get_a(), 'b': get_b()}
results = [f(**payload) for f in functions]

This works, but makes each of our function definitions uglier.

Solution 3:

Allow each function to have a different signature, inspect the signature at runtime and pass what is needed.
(Adapted from http://stackoverflow.com/a/2677263/3393459)


import inspect

def half(a):
    return a / 2

def twice(a):
    return 2 * a

def addition(a, b):
    return a + b

def subtraction(a, b):
    return a - b

# Wrapper which:
# * accepts a dict of all possible kwargs and their names
# * inspects the signature of the function
# * calls that function with the correct args
def call_func_with_correct_args(f, possible_args):
    func_args = inspect.getargspec(f).args
    args_to_pass = {k: possible_args[k] for k in func_args}
    return f(**args_to_pass)

functions = [half, twice, addition, subtraction]
a = get_a()
b = get_b()
full_payload = {'a': a, 'b': b}

results = [call_func_with_correct_args(f, full_payload) for f in functions]

So this is nice and clever, but we need to be careful that our function parameters are named correctly and consistently. Essentially we are passing the burden to the function definitions.

Conclusion

I don’t know what a great solution to this might look like. Is there a better way to do this? If all the parameters are different types, Python3’s type hinting might provide another option. What does this look like in other languages?

Book Review | Earthseed Series | Octavia Butler

Parable of the Sower and Parable of the Talents by Octavia Butler

I first heard about Octavia Butler in early 2014 on Twitter, I think originally from Danilo and/or Holly. I saw allusions to something called Earthseed, to humanity’s destiny in the stars, to the idea that “God Is Change”.

Two years later, with fascism on the rise and afrofuturism enjoying a moment of popularity, I went to a Fusion-backed symposium about Butler’s work. ((I learned about this from Alexis Madrigal’s newsletter Five Intriguing things which I’ve previously pluggedAlexis, formerly at the Atlantic and now Editor in Chief at Fusion, is one of the most interesting writers I follow.))  At this event, I was delighted by the idea that all progressives, all activists, are engaged in acts of science fiction; they imagine alternate worlds that could branch off from this one in a plausible way, societies like ours except governed by different principles of the physical or psychological universe.

Sower and Talents, published in 1993 and 1998 respectively, look more prescient by the day. Butler saw the future with great clarity and with a sense of resignation to the hate, destruction and degradation our world would suffer. In the Parable series, environmental catastrophe and economic inequality have created a desperate underclass driven to violence and drugs, whose life is of no value to a police force interested in protecting the property of the rich. In this fertile ground a white supremacist Christian paramilitary organization flourishes with the winking support of Presidential candidate Andrew Steele Jarrett, whose ascendance tears apart the vanishing middle class between liberal values and a frantic need to protect their families and communities from the predations of those even a little less fortunate. Kashmir Hill has already written about the uncanny similarity of this campaign to Trump’s. By the late 80s our future was not murky  to a thinker of Butler’s diagnostic precision.

The series follows Lauren Oya Olamina, a teenage girl who shows us the imagination and empathy and ambition that we will need to survive this bleak world. As a teenager in a middle-class enclave in southern California, Olamina begins to develop a practice called Earthseed, rooted in strong communities, individual self-sufficiency and an embrace of the universe’s ever-changing nature. Earthseed demands resilience and adaptability, with a sort of scientific and moral pragmatism, and points humanity towards the stars for its own survival. As she develops her philosophy it is eventually collected into The Book of the Living, which is “excerpted” heavily in the two books.

In these two books we don’t see anyone leave Earth — we are not given the pleasure of Butler articulating what it would be like for a whole society to live by these principles. We see small communities struggle to adopt these practices. We see them try to integrate new members who are grateful for food and shelter and company but skeptical of any indoctrination. We see major setbacks and minor accomplishments.

When we are defeated by Moloch our devastation is global and absolute and permanent. Our victories are usually are messy and local and temporary, a momentary respite from an ancient foe that is only getting stronger. If we are to survive, we must connect our small patches of humanity into a resilient and adaptable network. Our power is weak and our time is short, but our destiny is in the stars.