I thought python was supposed to be easy. Yea, don't laugh.

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
For starters I'm a C, C++ programmer mostly, 35 years in it.
For the most part python is fairly easy to use.
I recently posted this up on on github. It's single threaded but performs ok. It's a lot slower than the C++ version I created and vastly slower than the multi-threaded version.
So I wanted to add multiprocessing to it. Multi-proccessing not multi-threading. There is a difference and those of you who know enough about the GIL know why that is.
I figured well shit how hard can it be its easy enough in C and C++.
It's actually more of a pain in the ass in python. It doesn't help some child decided to use terms like pickling and dill instead of terms like package and serialize. Just kidding about the child part. haha. But seriously it doesn't help.

You can find countless tutorials and explanations for handling a simple method. Most of which don't show any arguments passed to the method.
Try and find one that shows an array containing classes which you need to update via a member function.
C, C++ are quite a bit easier. Hell even on windows back 20+ years ago it was easier than this.

The class I am trying to do this with is posted below.
The method is that needs to be ran is the update method that is a member of it.
There is an array of these objects that needs to be done.
You don't have permission to view the spoiler content. Log in or register now.

Even python's own documentation doesn't cover it. There are some that get close but fail to cover passing variables to the function or packaging them with it.
I'll probably stick this up on stack exchange as well.

I was seriously not expecting it to be this hard to do when it came to python. Yea, I knew multithreading would be a waste but ouch.

If you wonder if it works well I attached the performance profile.
See it for yourself.
The nested loops only makes a difference of 6 microseconds. Microseconds not milliseconds.
The greatest amount of time isn't even in areas I can control. It's in the pygame "blit" function.

If you want you can replace the code at the bottom of game.py with the following and profile it yourself.
Not like you need to take my word on it.
Python:
#if __name__ == "__main__":
#    main()

import cProfile
cProfile.run('main()',"output.dat")

import pstats
from pstats import SortKey

with open("output_time.txt","w") as f:
    p = pstats.Stats("output.dat",stream=f)
    p.sort_stats("time").print_stats()

with open("output_calls.txt","w") as f:
    p = pstats.Stats("output.dat",stream=f)
    p.sort_stats("calls").print_stats()
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,391
15,307
I recently posted this up on on github. It's single threaded but performs ok. It's a lot slower than the C++ version I created and vastly slower than the multi-threaded version.
It would be less slower if the code was not a total mess. How the fuck someone supposedly with 35 years of experience can write something like your ?
Python:
def event_handler(cls):
    for event in pygame.event.get():
        def quit(cls):
            [...]
        def resize(cls):
            [...]
        def key_down(cls):
            [...]
        def key_up(cls):
            [...]

        switch = {pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
        r = switch.get(event.type)
        if r:
            r(cls)
Even took from a compiled language point of view, so assuming a cost free function creation, there's still an obvious logical flaw. By itself this single error make your code three time slower than it should. It's not even about knowing Python or not, it's the algorithm that is wrong and illogical, this whatever the language.
Then, with a full optimization it would be four time faster than actually. It would obviously never be as fast as a compiled version, but it would still be an improvement.


It's actually more of a pain in the ass in python. It doesn't help some child decided to use terms like pickling and dill instead of terms like package and serialize. Just kidding about the child part. haha. But seriously it doesn't help.
Except that "pickle" and "serialization" aren't exactly synonymous.
Python have more than one serializer, and pickle is just the native method. Therefore, when people say to pickle something, they aren't simply telling you to serialize your data, but pointing you to the most adapted method to do it ; this whatever if you'll then use the native implementation or Tim Peters's cPickle. It's the same difference than saying to use a "pickup", in place of telling your to use a "car".
As for "dill", it's an extension to the pickle method. Therefore, once again it don't just mean that you have to serialize your data, but that a standard serialization will probably not be enough for what you want to do.


Try and find one that shows an array containing classes which you need to update via a member function.
C, C++ are quite a bit easier. Hell even on windows back 20+ years ago it was easier than this.
Python:
for c in whatever:
    c.whatever()
I'm sure that someone with your experience will have no problem to figure the solution starting there.


I was seriously not expecting it to be this hard to do when it came to python.
Python is used in almost all computer science colleges and universities to teach programing to people who don't know how to code... It's a strict, rigid and slow language, but not a difficult language.
 

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
It would be less slower if the code was not a total mess. How the fuck someone supposedly with 35 years of experience can write something like your ?
Python:
def event_handler(cls):
    for event in pygame.event.get():
        def quit(cls):
            [...]
        def resize(cls):
            [...]
        def key_down(cls):
            [...]
        def key_up(cls):
            [...]

        switch = {pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
        r = switch.get(event.type)
        if r:
            r(cls)
Even took from a compiled language point of view, so assuming a cost free function creation, there's still an obvious logical flaw. By itself this single error make your code three time slower than it should. It's not even about knowing Python or not, it's the algorithm that is wrong and illogical, this whatever the language.
Then, with a full optimization it would be four time faster than actually. It would obviously never be as fast as a compiled version, but it would still be an improvement.
What error what issue?
Nested functions. I tested it.
Maybe you are going on about the get statement again.

How about you instead of just claiming there is an error tell everyone what it is!

While you are at it feel free to post your much faster performing code.

I posted the performance profiles on the Original Post.
Funny, how something so broken works so well.
Maybe, you should have tried running it first. Or ran a profile.
You know done something other than run your mouth!
 
Last edited:

Radnor

Member
Game Developer
Nov 9, 2021
365
943
The method is that needs to be ran is the update method that is a member of it.
There is an array of these objects that needs to be done.
Eh, i hope i'm just missing something, but what is wrong with:
Code:
balls=[]
## add balls to list here
for ball in balls:
  ball.update(screen_w,screen_h,game.time)
And in case you may change balls list during iteration:
Code:
for ball in balls[:]:
 

Radnor

Member
Game Developer
Nov 9, 2021
365
943
As for eventhandler, it is really good idea to avoid nested functions and dict creation inside loop. In any programming language.
Can see what python will compile it to like this:
Code:
import dis
dis.dis(event_handler)
As you will see it's far from being free. Plus sometimes nested functions may create unwanted closures and leak memory.

P.S.: Would write something like:
Code:
def quit(e):
  pass
def resize(e):
  pass
handlers={"quit":quit,"resize":resize}

def process_events():
  for event in event_source.get():
    handler=handlers.get(event.type)
    if callable(handler):
      handler(event)
 

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
event_handler(), update(), and renderer() are all technically members functions of the game class
All 3 get ran each cycle of the main_loop(). which is located in the body of the game class.

I posted the profile data at on the original post. I also posted the code to run the profile using cProfile.
So no one needs to take my word on it.

To test the code with it un-nested. I create a variable in the game class and set it after the event call.
then replaced used it in the internal switch for keys.

Nested functions get different performance hits depending on how variables are passed to them.
They also have a flag set that shows they are nested. You can technically turn the flag off.
Interesting discussion on it.

I'm not getting the 10% performance hit the one guy talks about.

I think most developers have a lot more to worry about than 6 microseconds in their code.
BTW that's about 2% per function call. If it means that much by all means move it out.
That's just on that type of function. The nested functions also exist in update() and renderer() They don't equate to 1/10th of a percent there.

Anyway the reason it is setup that way is this is the closest thing python has to a switch case statement in both appearance and performance.
 

Radnor

Member
Game Developer
Nov 9, 2021
365
943
I'm just saying creating same thing inside loop is bad practice in any programming language/system.
Another thing i mentioned about nested functions is unwanted/unplanned closures, which can leak memory, seen such happening even in python std lib. Your link answer mentions it .
This is why i personally think such code is problematic.

Anyway, your code is just anti-python, reinventing switch etc. If you try to write C/C++ in Python you will end hating it.

My another attempt to make something related to your code, different approach. Just to show how such things could be done.
Code:
screen_w=1920
screen_h=1080
game_time=12.345

class Event(object):
  id=None

class UpdateEvent(Event):
  id="update"
  def __init__(self):
    self.w=screen_w
    self.h=screen_h
    self.t=game_time

class EventProcessorMixin(object):
  def process_event(self,event):
    handler=getattr(self,"on_"+event.id,None)
    if callable(handler):
      handler(event)

class Ball(EventProcessorMixin):
  def on_update(self,event):
    print(self,"on_update")

ball=Ball()
ball.process_event(UpdateEvent())
Either way, hope you got your problem solved, good luck.
 
  • Like
Reactions: anne O'nymous

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
I'm just saying creating same thing inside loop is bad practice in any programming language/system.
Another thing i mentioned about nested functions is unwanted/unplanned closures, which can leak memory, seen such happening even in python std lib. Your link answer mentions it .
This is why i personally think such code is problematic.

Anyway, your code is just anti-python, reinventing switch etc. If you try to write C/C++ in Python you will end hating it.

My another attempt to make something related to your code, different approach. Just to show how such things could be done.
Code:
screen_w=1920
screen_h=1080
game_time=12.345

class Event(object):
  id=None

class UpdateEvent(Event):
  id="update"
  def __init__(self):
    self.w=screen_w
    self.h=screen_h
    self.t=game_time

class EventProcessorMixin(object):
  def process_event(self,event):
    handler=getattr(self,"on_"+event.id,None)
    if callable(handler):
      handler(event)

class Ball(EventProcessorMixin):
  def on_update(self,event):
    print(self,"on_update")

ball=Ball()
ball.process_event(UpdateEvent())
Either way, hope you got your problem solved, good luck.
The event handler works for the game class in my system not the ball. The ball is just an object. The same would be done for NPCs or anything else that should go through an update cycle.
The event system is designed so that it takes it away from individual objects otherwise it would get called thousands of times more every event cycle.

In this case it gets call 1 time during and event cycle for all the objects no matter how many there are.

That said I moved the code if no other reason so I don't have to hear complaints about it.
That in itself is peace of mind.
I also went ahead and added in the profile code for those wanting to see what how good or bad it is they can comment out the profile could and uncomment the initializing part above it if they don't want to run the profile.

BTW thanks for being respectful unlike Annie up there.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,391
15,307
What error what issue?
Nested functions. I tested it.
Maybe you are going on about the get statement again.
Are you fucking kidding or are you just pretending when you claim to have 35 years of experience in the field ? Every fucking people who attended algorithm 101 can see the flaw in your code !

Even if they are cost free with a compiled language, and atomic (a pointer-like assignation) with an interpreted language, who would thing that putting the sub/function declaration inside a loop can be something to do ?
Same for the switch creation, that will be redone every single time the loop is proceeded, while its value is constant for every loops.

There's three ways to optimize your code:
  • Use a correct algorithm (1.7 time faster):
    Code:
    def event_handler(cls):
    def quit(cls):
    [...]
    def resize(cls):
    [...]
    def key_down(cls):
    [...]
    def key_up(cls):
    [...]
    
    switch = {pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
    
    for event in pygame.event.get():
    r = switch.get(event.type)
    if r:
    r(cls)
  • Remember that Python is duck type compliant (1.9 time faster):
    Code:
    import pygame
    
    class Event_handler(object):
    def __init__( self ):
    self.switch = { pygame.QUIT:self.quit,pygame.VIDEORESIZE:self.resize,pygame.KEYDOWN:self.key_down,pygame.KEYUP:self.key_up}
    
    def __call__( self, cls ):
    for event in pygame.event.get():
    r = self.switch.get(event.type)
    if r:
    r( cls )
    
    def quit(self, cls):
    [...]
    def resize(self, cls):
    [...]
    def key_down(self, cls):
    [...]
    def key_up(self, cls):
    [...]
    
    event_handler = Event_handler()
  • Remember that Python is fully object (2.0 time faster):
    Code:
    def event_handler(cls):
    global event_handler
    
    for event in pygame.event.get():
    r = event_handler.switch.get(event.type)
    if r:
    r(cls)
    
    def quit(cls):
    [...]
    def resize(cls):
    [...]
    def key_down(cls):
    [...]
    def key_up(cls):
    [...]
    
    setattr( handler, "switch", { pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
All have strictly the same behavior, you have absolutely nothing to change in the rest of your code for those three variations to works.
This said, will it's a bit faster, the last approach force you to keep the exact same name for the function when you import it, and therefore is not the most effective one.



Edit: By the way, forgot to say it, because it's a little off topic, but a code relying on if/elif would be the fastest one here, being 2.8 times faster (optimized code behind, no need to pass through a hashage, no need to perform a search).
 
Last edited:

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
I'm just saying creating same thing inside loop is bad practice in any programming language/system.
Another thing i mentioned about nested functions is unwanted/unplanned closures, which can leak memory, seen such happening even in python std lib. Your link answer mentions it .
This is why i personally think such code is problematic.

Anyway, your code is just anti-python, reinventing switch etc. If you try to write C/C++ in Python you will end hating it.

My another attempt to make something related to your code, different approach. Just to show how such things could be done.
Code:
screen_w=1920
screen_h=1080
game_time=12.345

class Event(object):
  id=None

class UpdateEvent(Event):
  id="update"
  def __init__(self):
    self.w=screen_w
    self.h=screen_h
    self.t=game_time

class EventProcessorMixin(object):
  def process_event(self,event):
    handler=getattr(self,"on_"+event.id,None)
    if callable(handler):
      handler(event)

class Ball(EventProcessorMixin):
  def on_update(self,event):
    print(self,"on_update")

ball=Ball()
ball.process_event(UpdateEvent())
Either way, hope you got your problem solved, good luck.
I get now part of the issue everyone was complaining about.
The way you declare "class variables" are the way all other programming languages declare instance variables.
Instance variables in C, C++, Java are variables declared in side a function/method. They exist for the term of the function.
If you want something shared across instances of a class you declare the variable static. Which will cause that class to become a singleton and you can only have one of it. Every instance of it actually is just a pointer back to the same one regardless what it is called.
This code below is the way C++,C#,JAVA,PHP, Javascript all do it for the most part.
Java:
class ball{
    private:                //Just means only this class's functions can access it
        std::string address;//This a standard declaration
        static int number;    //This would be see across all instances making this a singleton.
    public:                    //Stuff under this anyone can access
        int notprotected;    //An un protected data type
        std::string lookup(){        //A public function
            return address;
        }
};
I found this out when someone pointed out @classmethod and I looked that up.

To add to the confusion python developers use the same terms other programmers do to refer to different stuff.
Now I get why so many friends I know in other languages hate python. I don't but I sure as hell understand the confusion they had and why now.

It also explains why the GIL exists seeing that.
 

Radnor

Member
Game Developer
Nov 9, 2021
365
943
To add to the confusion python developers use the same terms other programmers do to refer to different stuff.
Now I get why so many friends I know in other languages hate python. I don't but I sure as hell understand the confusion they had and why now.
Python just different. I had my share of experience with native compiled languages, so can compare.
Once you understand basic concepts it actually start to make sense. After that you (at i was) will feel quite restricted using "normal" languages. I don't mean memory management or lack of {}/begin-end or missing private methods/attributes.

As for somewhat blurred difference between instance/class, it's actually one of features i really love in python. If you know what you doing you can do something so much easier than in C/Java, some things are just plain impossible to do. Duck typing and metaprogramming approaches for example.

Python is different language. It has good sides and bad sides. I personally love good sides more than i hate bad sides. But love require understanding :D At least core concepts.

P.S.: GIL is not a python language problem, it's problem of idiotic questionable implementation of CPython. Some wrong design choices growing from "evolution of scripting language implementation".

P.P.S: Also python is not really about performance, but rather writing small, easy to read/change code. Talking about performance, my old tests showed general code can be 100-300 times slower than similar C code. Tested integer manipulations, i guess big part of problem is long integers as base type in python. If you write stuff like "s=s.replace("abc","def")" it will be much faster as it is generally call to native function. Same about most of builtins functions/base classes.
So when writing python i usually skip non-trivial performance microoptimizations and just focus on writing small and readable code i (and others) can easily maintain.
 
Last edited:

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
Are you fucking kidding or are you just pretending when you claim to have 35 years of experience in the field ? Every fucking people who attended algorithm 101 can see the flaw in your code !

Even if they are cost free with a compiled language, and atomic (a pointer-like assignation) with an interpreted language, who would thing that putting the sub/function declaration inside a loop can be something to do ?
Same for the switch creation, that will be redone every single time the loop is proceeded, while its value is constant for every loops.

There's three ways to optimize your code:
  • Use a correct algorithm (1.7 time faster):
    Code:
    def event_handler(cls):
    def quit(cls):
    [...]
    def resize(cls):
    [...]
    def key_down(cls):
    [...]
    def key_up(cls):
    [...]
    
    switch = {pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
    
    for event in pygame.event.get():
    r = switch.get(event.type)
    if r:
    r(cls)
  • Remember that Python is duck type compliant (1.9 time faster):
    Code:
    import pygame
    
    class Event_handler(object):
    def __init__( self ):
    self.switch = { pygame.QUIT:self.quit,pygame.VIDEORESIZE:self.resize,pygame.KEYDOWN:self.key_down,pygame.KEYUP:self.key_up}
    
    def __call__( self, cls ):
    for event in pygame.event.get():
    r = self.switch.get(event.type)
    if r:
    r( cls )
    
    def quit(self, cls):
    [...]
    def resize(self, cls):
    [...]
    def key_down(self, cls):
    [...]
    def key_up(self, cls):
    [...]
    
    event_handler = Event_handler()
  • Remember that Python is fully object (2.0 time faster):
    Code:
    def event_handler(cls):
    global event_handler
    
    for event in pygame.event.get():
    r = event_handler.switch.get(event.type)
    if r:
    r(cls)
    
    def quit(cls):
    [...]
    def resize(cls):
    [...]
    def key_down(cls):
    [...]
    def key_up(cls):
    [...]
    
    setattr( handler, "switch", { pygame.QUIT:quit,pygame.VIDEORESIZE:resize,pygame.KEYDOWN:key_down,pygame.KEYUP:key_up}
All have strictly the same behavior, you have absolutely nothing to change in the rest of your code for those three variations to works.
This said, will it's a bit faster, the last approach force you to keep the exact same name for the function when you import it, and therefore is not the most effective one.

Edit: By the way, forgot to say it, because it's a little off topic, but a code relying on if/elif would be the fastest one here, being 2.8 times faster (optimized code behind, no need to pass through a hashage, no need to perform a search).
First, off. Sorry for acting like an ass to you but you did start it with your initial comments tone.
I have 35 years in C, C++.
Not in python.

I started coding in python recently and only on occasion. That said its taken me longer to understand python than any other language because they use the same terms and stuff other languages do for different things.
C and C++ doesn't declare variables and stuff like they do in python. See my post just before this one.

Also, python doesn't always rebuild everything just because it is nested. It can and will but it depends on a number of factors.

I like the object based version you showed better. Globals are generally a bad idea in large projects.
Prior to seeing your post I already changed stuff around several times.

I went ahead and moved it out side. That way it doesn't trigger everyone who is uncomfortable with it.

Between finding out python has class variables and instance variables (different from C++ and other languages) and what you and other suggested there was a performance improvement in event handling.

If you run the demo hit F1 and just let it run for 30 seconds or so then F1 again and immediately close it.
You will see with the way it is written it doesn't use 1% of total CPU cycles.
The reason is it does 1 check while in there and jumps back out.
Depending on how you setup the if statements it can do several
The most checks mine does is 2 when handling any event. There are no checks in the get()s its purely a pointer assignment.
If we add more complexity to the demo such as AI and some minor physics outside of just bounding balls off walls.
It would take up a lot less of a percentile.

The bottle neck currently in the game is the blit() function from pygame.
It also turns out the screen fill to black is a smaller issue.
So went to replace fill with just putting an image in its place and that actually slowed stuff down because transform had to be called. So removed transform and sure enough the 20% performance I just lost came back. However, I did notice chattering.
Were objects look like they stop for a fraction of a second.

Turns out there are a few issue. Pygame is using its own transform method outside of the one built into SDLs its a lot slower than simply letting SDL handle it.
Additionally they appear to be using their own fill method.
I did however notice pygame supposedly made all those accessible but can't find any tutorials on them and the little bit of info doesn't show they were done the same way we can use them in C++.
It also looks like pygame is using the SDL Surface rather than the SDL Texture as the default for sprites.

Seems though they do give you access to the SDL features if you want.
I've got some research to do.
 

Tompte

Member
Dec 22, 2017
216
155
I think the lesson we can take away from this is that you should be careful to not bring false assumptions with you when jumping from a familiar environment into a new one, and being an expert in one field doesn't make you an expert in all fields, even if they seem related. It's a very common fallacy.

I also have decades of experience with C++ but I still had to study up when my company moved to Unity and C#. I've encountered similar issues where my game would hitch and lag while doing apparently trivial things, due to the many hidden layers of abstractions, the GC, but also because I didn't fully understand the system I was working with and I was doing the wrong thing in that context. I was able to make it fast, but only after learning the idiosyncrasies of the new environment.

That said, it's only natural to bring in assumptions. It's what you know. But I wouldn't be so quick to blame the system for not giving you the results you expected.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,391
15,307
First, off. Sorry for acting like an ass to you but you did start it with your initial comments tone.
I have 35 years in C, C++.
Not in python.
And ? It was an algorithm flaw, this have nothing to do with the language. Even in C/C++ this is nothing near to a logical code.
As for my tone, when half of the threads started by someone are talking about optimization, you expect his code to be somehow optimized, not looking like something so few efficient that it wouldn't make you pass first year in college.


I started coding in python recently and only on occasion.
And ? Before I started modding for Ren'Py, four years ago, I never had wrote a single line of code in Python. And I only use this language when I'm dealing with Ren'Py, so only on my free time and not always. But I'm able to write efficient code in this language because of my experience,even if sometimes it's unorthodox one.
But once again the problem was absolutely not related to the language. That you don't know specific tricks, like the use of setattr, is one thing. But that you don't know that putting sub/function declaration, and even more constant-like declaration, inside a loop body, is the opposite of optimized code, that is something totally different ; especially coming from someone with such experience, and who pass his time claiming that everyone is dumb because they write non optimized codes. Even in C/C++ your initial code was not efficient, and therefore even less optimized.


That said its taken me longer to understand python than any other language because they use the same terms and stuff other languages do for different things.
C and C++ doesn't declare variables and stuff like they do in python. See my post just before this one.
You're just trying to talk your way out of this, nothing more.
Firstly C/C++ conventions (therefore one of the first thing you learned) are to declare the variables you'll use at the start of the main bloc where they'll be used. Therefore in C/C++ no one would put the switch "declaration" here.
Secondly since there's no associated keyword, this isn't a declaration but an assignation. And they (globally) works the same whatever the language. The "declaration at use" is not something generalized, even in interpreted languages, but the "no associated keyword mean assignation" is obvious when you come from C/C++.
Said otherwise, your 35 years of experience give you two reasons to not put this line inside the body loop. Because it's something you never did before, and because it feel totally weird to do it. Yet, you did it...


Also, python doesn't always rebuild everything just because it is nested. It can and will but it depends on a number of factors.
Could it be the reason why I never used the word "rebuild" ? I said it, the sub/function declaration is atomic, because limited to a pointer-like assignation. This explicitly exclude the idea of a rebuilding from the discussion.
Once again you're just trying to talk your way out of this.


I like the object based version you showed better.
Yet despite your long use of C++, and knowing that Python is an object oriented language, you didn't had the idea to use it...


Globals are generally a bad idea in large projects.
The global is half coming out of habit, half for explicit coding. Since it's not an assignation, Python will automatically search it in the globals if it don't find it in the locals.
But, more important, and like you obviously noticed, it's not a true use of a global variable. It's just that unlike others object oriented languages, like JavaScript by example, Python don't have an implicit way to address yourself. Therefore you've to get the pointer-like from the global in place of using self like one would do in JavaScript.
If, for some reason, the value of the variable have changed, you will never be in the code using it, since this value point to the said code. What remove main the reason why globals are a bad idea.
 

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
I think the lesson we can take away from this is that you should be careful to not bring false assumptions with you when jumping from a familiar environment into a new one, and being an expert in one field doesn't make you an expert in all fields, even if they seem related. It's a very common fallacy.

I also have decades of experience with C++ but I still had to study up when my company moved to Unity and C#. I've encountered similar issues where my game would hitch and lag while doing apparently trivial things, due to the many hidden layers of abstractions, the GC, but also because I didn't fully understand the system I was working with and I was doing the wrong thing in that context. I was able to make it fast, but only after learning the idiosyncrasies of the new environment.

That said, it's only natural to bring in assumptions. It's what you know. But I wouldn't be so quick to blame the system for not giving you the results you expected.
Yep, I certainly made some false assumption about python.
I made the assumption bad assumption they were doing things similar in assigning data like most other languages just without a data type.

So I just learned something else.
I could have fixed those issues another way.
A single dash in front of the variables makes them protected data members
A double dash in front makes them private data members
That was the real point of making it a class to start with.
 

Radnor

Member
Game Developer
Nov 9, 2021
365
943
A single dash in front of the variables makes them protected data members
A double dash in front makes them private data members
Not really. It's just naming convention, with some mangling. There is no protected/private things in python. You can access and often change pretty much anything in another object. It's bad thing if you think in C++, but once you start thinking python it's actually useful and make sense.

If you just want to update balls/units positions, it may even be better to drop class completely and store balls as list of lists or dicts.
 

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
And ? It was an algorithm flaw, this have nothing to do with the language. Even in C/C++ this is nothing near to a logical code.
As for my tone, when half of the threads started by someone are talking about optimization, you expect his code to be somehow optimized, not looking like something so few efficient that it wouldn't make you pass first year in college.
That project there is the most lines of code I've written in python. Add the posts you see on this site and about 200 lines more I did for some idiot at work and another 20 when my son's teacher gave him a project using it. That's about the sum total of all the lines of code I written in python.
I write more about 10 times more lines of code in C and C++ in a day single day.
You said you've been doing it 4 years.
Another factor is I've spent more time in the workings of the python compiler than I have writing code in python. 2 reasons behind it. I looked at how it was made up when working on my own interpreter. Also people asking for help related to making modules and such. That probably makes me some weird oddity.

And ? Before I started modding for Ren'Py, four years ago, I never had wrote a single line of code in Python. And I only use this language when I'm dealing with Ren'Py, so only on my free time and not always. But I'm able to write efficient code in this language because of my experience,even if sometimes it's unorthodox one.
But once again the problem was absolutely not related to the language. That you don't know specific tricks, like the use of setattr, is one thing. But that you don't know that putting sub/function declaration, and even more constant-like declaration, inside a loop body, is the opposite of optimized code, that is something totally different ; especially coming from someone with such experience, and who pass his time claiming that everyone is dumb because they write non optimized codes. Even in C/C++ your initial code was not efficient, and therefore even less optimized.
I spent 45 minutes or so the other typing that in and getting it working. I've spent more time talking and chatting with you all.
What would you want to bet you have several thousand more hours in programming python than I do. Even if you include the little mod I made for lab rats 2. I may have handful of hours programming time in python. Think about it everything I learned was on the fly. I didn't use any real resources. If I had maybe I would have read the python manual on the site and then seen the difference between class variables and instance variables. I looked at it and did it.

Yep, I looked at some code made a number of false assumptions and yet I still managed to get that up and working to that level.

You're just trying to talk your way out of this, nothing more.
Firstly C/C++ conventions (therefore one of the first thing you learned) are to declare the variables you'll use at the start of the main bloc where they'll be used. Therefore in C/C++ no one would put the switch "declaration" here.
Secondly since there's no associated keyword, this isn't a declaration but an assignation. And they (globally) works the same whatever the language. The "declaration at use" is not something generalized, even in interpreted languages, but the "no associated keyword mean assignation" is obvious when you come from C/C++.
Said otherwise, your 35 years of experience give you two reasons to not put this line inside the body loop. Because it's something you never did before, and because it feel totally weird to do it. Yet, you did it...
Putting code at the top of the main block is done for variables used through out the block.
In C and C++ a switch does not use a dictionary. Which is why it can be declared at the top.
In C and C++ you can't reference or use something unless it is instantiated.
That's different from being declared. Instantiated means it has something assigned to it.
It also can't come before whatever it references.
What that means if you declare a function and then want to make a pointer to it. The pointer has to be instantiated after the function is made.

I know that from all the state machines and AI systems and observer classes and countless other shit I wrote over the years.
You can look up what I said.

You will also see issues were they make a declaration before one class that contains another class that references back to it.
C:
class b;    //This is calle a forward declaration
            //Because it isn't instantiated you can't use a reference
            //You can only use a pointer

class a{
    b *ptr; //Because b is below it in the order the compiler sees it
};            //it needs the forward declaration you see above.

class b{
    a *ptr;//This doesn't require a forward declaration because a class a is above it
}

/**********************************************/
void start(){
    void (*fptr[])()={func1,func2};//Not legal because it comes before the functions
}
void func1(){
    return;
}
void func2(){
    return;
}
void run(){
    void (*fptr[])()={func1,func2}; //This is legal because it comes after the functions
                                    //That are declared.
}

Could it be the reason why I never used the word "rebuild" ? I said it, the sub/function declaration is atomic, because limited to a pointer-like assignation. This explicitly exclude the idea of a rebuilding from the discussion.
Once again you're just trying to talk your way out of this.
You are correct you didn't say it you implied it with this line here, "Even took from a compiled language point of view, so assuming a cost free function creation". You being that compiled languages don't rebuild and that interpreted languages can.

Yet despite your long use of C++, and knowing that Python is an object oriented language, you didn't had the idea to use it...
Actually, I made the assumption that a standard declaration was of the OOP type not of the shared type.
python more resemble C in that anyone can access the default variable but difference in the making those variable shared much like a static variable in C or C++. Most OOP languages treat member variables as private as the default. One of the primary purposes of OOP is data protection and encapsulation. Python goes a good bit against that aspect. You have to put a underscore to get protected and a double underscore to get private. That breaks the norm in two ways. First, it leaves the data unprotected as the default and it shares it. If we created a spectrum on the data protection restriction you would go C ,C++, Java and C# But before C you would put Python some place as doing next to the opposite as a default.

The global is half coming out of habit, half for explicit coding. Since it's not an assignation, Python will automatically search it in the globals if it don't find it in the locals.
But, more important, and like you obviously noticed, it's not a true use of a global variable. It's just that unlike others object oriented languages, like JavaScript by example, Python don't have an implicit way to address yourself. Therefore you've to get the pointer-like from the global in place of using self like one would do in JavaScript.
If, for some reason, the value of the variable have changed, you will never be in the code using it, since this value point to the said code. What remove main the reason why globals are a bad idea.
Globals are simply bad because any function can access them and modify them. They are simply considered a defunct and out of date method in most the rest of the programming world.
For a while people were using singletons to encapsulate them. Then that has gotten even pushed out.
The only real use for a singleton to day is to ensure that only one of a specific class is created. An example would be a driver to some hardware or access point. Were you don't want 20 different things trying to gain access to it.
Globals are far worse than using singletons in code security issues they create.
 

Diconica

Well-Known Member
Apr 25, 2020
1,101
1,150
Not really. It's just naming convention, with some mangling. There is no protected/private things in python. You can access and often change pretty much anything in another object. It's bad thing if you think in C++, but once you start thinking python it's actually useful and make sense.

If you just want to update balls/units positions, it may even be better to drop class completely and store balls as list of lists or dicts.
That's good to know.
So Python has no real data encapsulation or protection. Two of the main factors in OOP its missing.
It also means I can never use it for industrial purposes legally.
I can see that in court can you tell us how this variable changed well someone wrote this additional code here and it access that variable and modified it. What you didn't have any protection on that?
I know what you are thinking they would go after the person who made the change.
Some times that's the case. But if someone hacks in a system and you don't have it protected from changes like that legally your fucked.
 

xj47

Member
Nov 4, 2017
240
399
It also means I can never use it for industrial purposes legally.
I find that statement kind of odd.
In a language like C++ it's much harder to change stuff you aren't supposed to but there isn't much in the way of actual security around it.
If you know how a class is laid out in memory you can still modify whatever you want. And if you know the address of a function as well as it's header you can replace it with your own.

My understanding of access modifiers like "private" is not that it makes your code more secure, but that it creates a strong incentive for other programmers to not access it directly. If I see a "private" field in a C++ project I'm 99% sure it doesn't get modified in a weird way. But if a bad actor wanted to modify it, they can still do that.
Idk, maybe I'm misunderstanding what you meant by that.
 
  • Like
Reactions: Radnor

Radnor

Member
Game Developer
Nov 9, 2021
365
943
So Python has no real data encapsulation or protection. Two of the main factors in OOP its missing.
It also means I can never use it for industrial purposes legally.
In C i can write to nullptr or divide by zero, does it make C unsuitable for industrial proposes? Why not use java or rust or whatever safe thing is popular today?
Main reason to use python is speed of development, ease of maintenance and support for most common programming paradigms.
If your goals is safety or performance then python is probably not good choice for you. It's not bad language, but it's not one-size-fit-all.

As for protection, here is something funny/horrible for you :D
Code:
import sys
import ctypes

def change_value_of_int(n,new_value):
  obj=ctypes.cast(id(n),ctypes.POINTER(ctypes.c_int))
  if sys.version_info.major==2:
    obj[2]=new_value
  else:
    obj[3]=new_value

x=42
print("42:",x)
change_value_of_int(42,69)
print("42+1:",x+1)
x=40
print("40, 40+2:",x,x+2)