in reply to Re: Nesting Functions
in thread Nesting Functions

Local and enclosing are lexical my
Python doesn't have lexicals. All variables are rather some equivalent of package variables, where each function counts as a package that can't access variables of other function. So a variable can be used as long as it as been defined sometime before in the function, regardless of scope:
>>> def scope(): ... for x in range(1,10): ... if x > 3: ... print(a) ... else: ... a=x ... >>> scope() 3 3 3 3 3 3 >>> print(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'a' is not defined
I had some difficulty understanding the meaning and use of with statements, until I realized it was just a mechanism to simulate lexical scope (with the possibility to do some clean up on a variable at the end of a defined scope). You might find some example when looking for variable declaration in python, but actually the (new) feature is just type enforcing, there is no equivalent to my in python.

That's the thing I dislike the most about python, just above the lack of explicit block-ending tokens (curly brackets :P).

Replies are listed 'Best First'.
Re^3: Nesting Functions
by LanX (Saint) on Jul 19, 2019 at 12:46 UTC
    > All variables are rather some equivalent of package variables, where each function counts as a package that can't access variables of other function.

    That's more or less how lexicals are realized in Perl.

    A Pad° is a hash like structure ("namespace") like a package. (with the difference that it doesn't have globs)

    Every scope has it's own pad, nesting scopes results in a chain of pads to be investigated.

    You may want to play a bit with PadWalker

    > Python doesn't have lexicals.

    Python has closures, closures require lexicals.

    > there is no equivalent to my in python.

    Implementation of semantic matters not syntax or naming.

    update

    the first assignment in a "scope" is an implicit declaration in Python.

    Sometimes it's a my sometimes an our .

    The mess starts because you can't use something like strict* to catch typos and Py3 needed to introduce nonlocal to mark assignments which are not declarations.

    "Explicit is better than implicit" ... LOL

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

    °) Pad: = short for perlguts#Scratchpads

    *) which JS successfully copied because it has var and even let now.

      Implementation of semantic matters not syntax or naming.
      I'm not sure I understand what you mean. Are you saying the names of elements in a language must match their implementation and not their behaviour? I really don't agree with that, you shouldn't have to know which interpreter you are using to call things, if their behaviour is well defined.

      If you do call python's function variables lexical, I surely wouldn't call them "lexical my", as you can't limit a variable to a scope except function (so a variable in a loop can be used outside of that loop). And the condition for using a variable in perl is that it has been declared before lexically, while in python it must have been defined before chronologically. Also in perl one distinction is that non lexicals can be accessed by name (symref or symbols table) while lexicals can't. Python doesn't have that distinction.

      Python has closures, closures require lexicals.
      I'm tempted to argue that it could also be that Python has a different definition of closure, but I think that's a fair point. But Python variables behave so differently than lexicals from other languages (at least the ones I know), that I'd rather avoid calling them lexicals, and focus on the fact that closures keep a hold of variables beyond their expected lifespan, rather than talking about lexical scope.

      Edit: (after yours):

      the first assignment in a "scope" is an implicit declaration in Python.
      I'd rather consider that all possible variables are implicitly declared. Otherwise that would mean that you can access a variable above it's (implicit) declaration like in my example. This would also imply conditional declaration when I'd rather consider only the definition/initialization can be conditional. Although, after checking, exec (the equivalent of perl's eval) only sees globals by default. So that's a point for lexicals.

        > while in python it must have been defined before chronologically.

        not sure what you mean. Example?

        > Also in perl one distinction is that non lexicals can be accessed by name (symref or symbols table) while lexicals can't. Python doesn't have that distinction.

        AFAIK does Python have namespaces - well classes - like __BUILTINS__ or globals()['var'] to access such non-lexicals.

        > Are you saying the names of elements in a language must match their implementation and not their behaviour?

        I'm saying it has to match the semantic of the definition. From what I know have "lexical vars" been invented in lambda calculus.

        I suppose they where first implemented in lisp.

        > as you can't limit a variable to a scope except function (so a variable in a loop can be used outside of that loop)

        Scoping rules are different, but please keep in mind that you need an extra "form" in lisp to build a lexical scope. (at least in elisp). So scopes are language depended.

        But what matters here is the visibility of lexicals (or rather non-visibility outside a scope)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      > The mess starts because you can't use something like strict* to catch typos and Py3 needed to introduce nonlocal to mark assignments which are not declarations.

      Another disturbing thing is that Python does hoisting like JS.

      if it encounters a (implicit) declaration of a var somewhere at the end of a function, it will bind all var to the same private storage.

      see demo of the mess in fun2()

      >>> a=666 # global >>> def fun1(): ... print a # global ... >>> def fun2(): ... print a # privat ... a = 33 # declaration ... >>> fun1() 666 >>> fun2() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in fun2 UnboundLocalError: local variable 'a' referenced before assignment >>>

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice