Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>By the time your decorator gets the function object <code>f</code>, it's already been compiled -- specifically, it's been compiled with the knowledge that <code>x</code> is local (because it's assigned with the <code>+=</code> assignment), the normal optimization (in <code>2.*</code> you can defeat the optimization, at a staggering price in performance, by starting <code>f</code> with <code>exec ''</code>; in <code>2.*</code>, you cannot defeat the optimization). Essentially, to use the syntax you crave, you have to recompile <code>f</code> (by recovering its sources, if you know they'll be available at runtime, or, much harder, by bytecode hacks) with somehow-modified sources -- once you've decided to go that way, the simplest approach is probably to change <code>x</code> into <code>f.x</code> throughout the body of <code>f</code>.</p> <p>Personally, if and when I find myself fighting so hard against the language (or other technology) that I'm trying to bend to my will to impose my desires, I acknowledge that I'm either using the wrong language (or other technology), if those desires are absolutely crucial, and then the solution must be to change technology; or, if those desires are not that crucial, give up on them.</p> <p>Either way, I give up trying to distort the language too far away from its obvious design intentions: even if I did come up with some hacky, fragile kludge, it would no doubt be unmaintainable. In this case, Python's desire intentions are very clear: barenames that get re-bound within a functions are locals of that function unless explicitly designated as globals -- period. So, your attempt to make barenames (that get re-bound within a function) mean something completely different than "locals" is exactly this kind of fight.</p> <p><strong>Edit</strong>: If you're willing to give up on the insistence on using <strong>barenames</strong> for your "statics", then suddenly you're not fighting against Python any more, but rather "going with the grain" of the language (despite the design glitch of <code>global</code> [and <code>nonlocal</code>], but, that's a separate rant;-). So, for example:</p> <pre><code>class _StaticStuff(object): _static_stack = [] def push(self, d): self._static_stack.append(d) def pop(self): self._static_stack.pop() def __getattr__(self, n): return self._static_stack[-1][n] def __setattr__(self, n, v): self._static_stack[-1][n] = v import __builtin__ __builtin__.static = _StaticStuff() def with_static(**variables): def dowrap(f): def wrapper(*a, **k): static.push(variables) try: return f(*a, **k) finally: static.pop() return wrapper return dowrap @with_static(x=0) def f(): static.x += 1 print static.x f() f() </code></pre> <p>This works just like you desire, printing 1 and then 2. (I'm using <code>__builtin__</code> to make it simplest to use <code>with_static</code> to decorate functions living in any module whatsoever, of course). You could have several different implementations, but the key point of any <strong>good</strong> implementation is that "static variables" will be <strong>qualified</strong> names, <strong>not</strong> barenames -- making it explicit that they're not local variables, playing with the grain of the language, and so forth. (Similar built-in containers, and qualified names based on them, <em>should</em> have been used in Python's design, instead of the <code>global</code> and <code>nonlocal</code> design glitches, to indicate other kinds of variables that aren't local ones and therefore should not be using barenames... ah well, you can implement yourself a <code>globvar</code> special container on the same lines of the above <code>static</code> ones, without even needing decoration, though I'm not so sure that is entirely feasible for the <code>nonlocal</code> case [perhaps <em>with</em> some decoration and the tiniest amount of black magic...;=)]).</p> <p><strong>Edit</strong>: a comments points out that the code as given doesn't work when you only decorate a function that returns a closure (instead of decorating the closure itself). That's right: of course, you have to decorate the specific function that uses the <code>static</code> (and there can be only one, by definition of function-<code>static</code> variables!), not a random function that doesn't in fact use the <code>static</code> but rather just happens to be in some lexical connection with the one that <em>does</em>. For example:</p> <pre><code>def f(): @with_static(x=0) def g(): static.x += 1 print static.x return g x = f() x() x() </code></pre> <p>this works, while moving the decorator to <code>f</code> instead of <code>g</code> doesn't (and couldn't possibly).</p> <p>If the actual desiderata are not about static variables (visible and usable only within a single function) but some hybrid thing that's usable throughout a certain peculiar bundle of functions, that needs to be specified very precisely (and no doubt implemented very differently, depending on what the actual specs <strong>are</strong>) -- and ideally that needs to happen in a new and separate SO questions, because this one (which is specifically about <em>static</em> instead), and this answer to this specific question, are already plenty big enough.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COI agree, but my hope is that this kludge/hack wouldn't be necessary indefinitely. My aim was to either demonstrate that this is or isn't possible. I'd like to someday use this question as either an initial implementation or the counter-example for a PEP. I'm not sure I agree with your evaluation of design intentions, since "nonlocal" variables are in python3. nonlocal is tantalizingly similar, yet disappointingly not very usable as C-style static variables. (python.org/dev/peps/pep-3104) Maybe someone can meet the challenge by using python3.0? ...I can't seem to insert paragraphs.
      singulars
    2. CO@buzkor, I know the design intentions pretty well as I was one of the parties debating them as they were formed (though the final decision is Guido's). `nonlocal` is just one more variant of `global` (I don't like either, I think they sit athwart most of Python's otherwise pretty-consistent design, and using a special keyword from which to make qualified names would have been much better -- but clearly I lost that debate in terms of Guido's final decisions). I may edit my answer to show how that would work.
      singulars
    3. CO@buzkor, edited my answer to show how everything becomes smooth and solid as soon as you give up on the craving for barenames meaning things other than local variables -- a really unreasonable demand, no matter the design glitches of global and nonlocal. Namespaces are one honking great idea, let's do more of those: using qualified names means I _am_ doing one more namespace, rather than striving to shoehorn into an existing namespace (the one used for local variables, i.e. barenames) stuff that doesn't _belong_ there. No downside, all upside, all Pythonic, smooth, and sweet.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload