Friday, 15 June 2012

python - Is it "bad" to define closures at the top level, only to be called inside a function? If so: alternatives? -



python - Is it "bad" to define closures at the top level, only to be called inside a function? If so: alternatives? -

i'm tagging 1 "language-agnostic" because i'm asking seems general principle, i'm using r , python examples.

i've written r script along lines of mwe:

## not work: plus_i <- function(x) x + times_i <- function(x) x * loop_i <- function(x) { for(i in 1:2) { x <- plus_i(x) x <- times_i(x) } x } loop_i(3)

but fails error in plus_i(x) : object 'i' not found because of r's lexical scoping. couldn't hack way around eval.

the python equivalent fails:

## not work: def plus_i(x): homecoming x + def times_i(x): homecoming x * def loop_i(x): # mutable objects beware in [1, 2]: x = plus_i(x) x = times_i(x) homecoming x loop_i(3)

in understanding, these programs work in dynamically scoped language, r , python both statically/lexically scoped. if that's case, somehow anti-paradigmatic or otherwise "bad" write r , python code this? matter of "explicit improve implicit", or go deeper?

edit: seems that, indeed, goes deeper. apparently lexical scoping inherent feature of closures. question still applies.

note plus_i , times_i not used outside of loop_i in program. don't want define plus_i , times_i within loop_i, because think hurts readability of code (which not simple in example). don't want create i explicit function argument, because there several such i's , 1 time again seems create code less readable , much more hard debug (by having maintain track of defined locally , passed in).

another alternative create new environment, define plus_i , times_i within it, , pass loop_i. still feels off-label utilize of environments. edit: or, reassign environment(plus_i) <- environment()

if read through hadley's guide on functions, you'll understand there 4 environments maintain in mind every function:

the defining environment - function's code stored. the calling environment - environment function called from. the parent environment - function looks symbols if closure. the local scope - advertisement hoc environment created every time execute function, parent environment described above.

in case, defining plus_i , times_i outside of loop, parent environment global environment -- additional symbols (like i), , not find them. nudge functions along, forcefulness matter telling them look.

plus_i <- function(x) x + times_i <- function(x) x * loop_i <- function(x) { environment(plus_i) <- environment() # "here", in local scope environment(times_i) <- environment() # of loop_i, i! for(i in 1:2) { x <- plus_i(x) x <- times_i(x) } x } loop_i(3) # [1] 12

note not inadvertently alter parent environment of either function, because r implicitly creating re-create of each function within loop_i due assignment.

in general, however, not specifying i argument bad idea: if provide function "incomplete" referencing symbols cannot find in argument list or default parent environment, much harder others use. imagine if plus_i several dozen lines of code 1 utilize of i snuck in somewhere; how know function depends on i? little scripts may ok not development hygiene long-term.

python r language-agnostic scope

No comments:

Post a Comment