On 27 May 2021, at 18:15, Steven D'Aprano <steve@pearwood.info> wrote:

On Thu, May 27, 2021 at 04:53:17PM +0200, Ronald Oussoren via Python-ideas wrote:

Statics are still hidden global state

How are they *global* state when they are specific to an individual
function?

We can already get the basic behaviour of statics right now, only with
an ugly hack that pollutes the function parameter list and is
inconvenient to use.


   static = [0]

   def spam(arg, static=[0]):
       static[0] += arg
       return static[0]

   def eggs(arg, static=[0]):
       static[0] -= arg
       return static[0]


Is it your argument that all three `static` variables are using shared
global state? If not, then I have no idea what you mean by insisting
that statics are "hidden global state". They are hidden state, but not
global. Just like closures and instance attributes.

I honestly don’t see the difference between:

def spam(arg, static=[0]): …

and

_static = 0
def spam(arg): global _static; …

The difference is where the state is stored. State in the latter example is less tightly coupled to the function and is easier to access externally, but for both cases there is a documented way to access them (spam.__defaults__[’static’] for the first example).  In both cases there’s effectively a singleton object that stores data, which makes testing harder because it is harder to ensure the right preconditions for testing (e.g. some other code might have called the function and affected the function state in an unexpected way).




and those can be problematic regardless of being function local or
module global. Having global state like this affects testability and
can affect threading as well.

It sounds like your problem is with *mutable state* in general. Global
variables, instance attributes, class attributes, they all have exactly
the same issues.

So don't use mutable state. Nobody is forcing you to use this feature if
you prefer to write in a functional style with no mutable state.


I don’t think anyone has accused me of advocating functional programming before ;-)

I don’t have a problem with mutable state in general, just with singletons. That includes globals and class attributes, but not necessarily instance variables or other data structures.


The factory function doesn’t need to be part of the public API of a
module, I’ve used a pattern like this to create APIs with some hidden
state:

```
def make_api():
   state = ...

   def api1(…): …
   def ap2(…): …

   return api1, api2
api1, api2 = make_api()
```

Congratulations, you've just used static local variables. You just used
closures for the implementation.



I’m not saying that this is a particularly good way to structure code,
in general just using a private module global is better (assuming the
design calls for some kind of global state).

You: "Global state is bad! Don't use global state!"

Also you: "Don't use local state (closures)! Use global state, it's
better!"

No, I wrote that *if* you want to use global state there are already multiple ways to do this.

I’m just as flawed as anyone and do use global state when that’s convenient.  But this has a tendency of causing problems later on, especially in larger projects.


*wink*

Slightly more seriously, I also wrote that the OP hasn’t provided a better reason for adding this feature than “other languages have this”. 

Ronald


Twitter / micro.blog: @ronaldoussoren
Blog: https://blog.ronaldoussoren.net/