I think what you are looking for is a pointer on how to write Python in a functional way that avoids use of global state as much as possible and, in particular, something that will make it "reactive" in the way that Erlang is inherently.
Is it possible to generally avoid global state in Python? Yes, for the most part. Some things are going to simply be global because they represent real-world resources, though, and you're not going to escape from that (but that's what using queue to sequentialize communication is all about). That doesn't mean that you have to have two concurrent threads writing to the same socket, of course. It does mean, however, that you can have threads spawned or processes forked without having much visibility over global state, and write them in a way where they develop their own state internally (which is the normal thing to do anyway).
Is is possible to make Python work in a "reactive" sort of way? Sure. There are a few "reactive" frameworks for Python, and many coders (myself included) find Python to be most maintainable and understandable when written in a functional style that makes limited (or no) use of the class
keyword. Put the two together and you can probably hit somewhat close to your goal. I've never used it, but ReactiveX for Python seems aimed in this direction. There is also an answer here on SO that might give you some food for thought.
So doable? Yes. But desirable? That depends entirely on the actual problem you are trying to solve, which you have not expressed. That could easily mean this is an X-Y problem, and you'll need to solve for X before you can move ahead in a sane way.
Beware paradigms that are an ill fit for a language. I personally do not believe that Python's strengths lie in this area, nor do I find Python's (lack of) error recovery strategy to be conducive to concurrent network programming. There are many big, scary monsters in the concurrent programming closet and shared data is only one of them -- scheduling, access, resource control, queue overflow management, sequencing, sequenced bottlenecks, etc. will all rear their head at some point.
There is a reason Python has a GIL and there is a reason that the best solution people have found to massive concurrency in most single-threaded languages like Python is to use OS threads combined with something like Docker to force arbitrary system partitioning, have some sort of recovery approach, and defer scheduling and resource management back down to the underlying host OS (even if these effects are largely unconscious achievements to most of the folks in the Docker community).
Those are super hard problems and you don't want to have to write solutions to those super hard problems into every project you develop.
It just turns out that the Erlang runtime already provides all of this as a matter of course because these are the exact problems it was designed to solve. The differences here are much deeper than OOP vs FP coding paradigms and really touch on the underlying runtime and resource management paradigm (which is somehow mysteriously omitted from discussions of this nature in the normal case). If a need for reactive, massive concurrency is your problem, I would recommend using Erlang for your project -- but maybe Python for the parts that are better expressed in Python (especially if there are already Python libs that do whatever heavy lifting you need).