Skip to content

Instantly share code, notes, and snippets.

@RyanMarcus
Created June 26, 2017 22:15
Show Gist options
  • Save RyanMarcus/0c4a37a67e91eabbd1373725ff50c992 to your computer and use it in GitHub Desktop.
Save RyanMarcus/0c4a37a67e91eabbd1373725ff50c992 to your computer and use it in GitHub Desktop.

In the pursuit of some nice-looking, functional-feeling Python code, I'm wondering how to bind a set of names to the result of applying a function to their currently bound values. Consider this code:

# preamble
a = [4]
b = [5]
c = [6]

# code
a = len(a)
b = len(b)
c = len(c)

print(a, b, c)

However, typing x = len(x) for each of the three variables must surely be redundant, right?

Attempt at in-line solution...

I can reassign the names like this instead:

a, b, c = (len(x) for x in (a, b, c))

... but this also carries some redundancy, because I had to list a, b, c twice!

Attempt using inspect...

We can use inspect to make things a bit better:

import inspect

def apply_in_scope(f, v):
  parent = inspect.stack()[1].frame.f_globals
  for i in v:
    parent[i] = f(parent[i])

a = [5]
b = [7, 9]
c = [9, 10, 11, 12]

apply_in_scope(len, ("a", "b", "c"))

print(a, b, c)

... but now I have to put the names of my variables in quotes, instead of using them directly. The problem is that when you call a function in Python, the function gets passed a new reference.

A quadratic solution that "works"

Changing the code slightly, we can do a quadratic search for arguments that match the given parameters, which is very slow, but I believe works:

import inspect

def apply_in_scope(f, values):
  parent = inspect.stack()[1].frame.f_globals
  names = [k for k, v in parent.items() if any(v is x for x in values)]

  for name in names:
    parent[name] = f(parent[name])

a = [5]
b = [7, 9]
c = [9, 10, 11, 12]

apply_in_scope(len, (a, b, c))

print(a, b, c)

... but I can't help thinking there must be a better way, or that I'm missing something simple. This would be reasonably easy in LISP, which makes me think it shouldn't require so much gymnastics in Python.

(warning: the above solution will apply the function multiple times if more than one variable is the same value!)

Edit: this question is distinct from how to make a variable number of variables because that question (1) applies to the global scope and not the local function scope and (2) does not solve the basic meta-programming question asked here of reassigning and applying a function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment