I've been trying to clean up my code for a neural network evolution simulator I'm working on, because it's grown to over 1000 lines and it's very difficult to read. Part of that process involves moving blocks of code from the main loop into their own functions (event handling, drawing to the screen, etc) or their own modules. However, I'm having trouble figuring out how to deal with the global variables.
As an example, I have a variable called "selected" that keeps track of a particular neural network creature selected by the user. I want to change the value of this variable in the event handling function when the user clicks on a new creature; I also want to change its value when the creature dies, which happens in a different block of code in its own function.
I understand that I can use the "global" keyword to do this, but my impression is that it's generally poor practice to do so. I also know that I can store these variables in a separate module and import them, but when I'm dealing with 30+ variables, typing "module_name.variable_name" every time I want to modify them seems unnecessarily tedious. I was also considering storing all of these values in a global dictionary so I can modify them from within functions, but again, typing "dict_name['var_name']" each time seems unnecessary.
So essentially my question is, what would be the best practice in this situation? Is it one of these solutions, or is there a cleaner approach? I'd like to make sure I'm on the right track before I spend hours overhauling my code. Thank you for your help!
30 global variables is just a big no-no. At some point you'll forget the global statement, and you'll create a local variable and will spend hours to debug your code.
you could build a singleton object instead
instead of:
a = 12
b = 33
c = "foo"
def run():
global a
if a == 34:
# do something
a += 1
you could create a big wrapping class with all variables as members:
class Program:
def __init__(self):
self.a = 12
self.b = 33
self.c = "foo"
now you can access all your variables with the self prefix. It may be tedious but at least it's short, and most good IDEs (pycharm, pyscripter, eclipse) propose completion (much better than a dictionary, where you cannot have completion)
# let's say it's the main method
def run(self):
if self.a == 34:
# do something
self.a += 1
now:
o = Program()
o.run()
print(o.a) # without __ prefix, your data is visible from the outside
So using an object not for inheritance, polymorphism or such, but just to define the "global" context and work inside the instance, with self. prefix, and say goodbye to global variables.
Related
So I know this could be considered quite a broad quesiton, for which I am sorry, but I'm having problems understanding the whole importing and __init__ and self. things and all that... I've tried reading through the Python documentation and a few other tutorials, but this is my first language, and I'm a little (a lot) confused.
So far through my first semester at university I have learnt the very basics of Python, functions, numeric types, sequence types, basic logic stuff. But it's moving slower than I would like, so I took it upon myself to try learn a bit more and create a basic text based, strategy, resource management sorta game inspired by Ogame.
First problem I ran into was how to define each building, for example each mine, which produces resources. I did some research and found classes were useful, so I have something like this for each building:
class metal_mine:
level = 1
base_production = 15
cost_metal = 40
cost_crystal = 10
power_use = 10
def calc_production():
metal_mine.production = A formula goes here
def calc_cost_metal():
etc, same for crystal
def calc_power_use():
metal_mine.power_use = blah blah
def upgrade():
various things
solar_plant.calc_available_power()
It's kinda long, I left a lot out. Anyway, so the kinda important bit is that last bit, you see when I upgrade the mine, to determine if it has enough power to run, I calculate the power output of the solar plant which is in its own class (solar_plant.calc_output()), which contains many similar things to the metal mine class. If I throw everything in the same module, this all works fantastically, however with many buildings and research levels and the likes, it gets very long and I get lost in it.
So I tried to split it into different modules, so one for mines, one for storage buildings, one for research levels, etc. This makes everything very tidy, however I still need a way to call the functions in classes which are now part of a different module. My initial solution was to put, for example, from power import *, which for the most part, made the solar_plant class available in the metal_mine class. I say for the most part, because depending on the order in which I try to do things, sometimes it seems this doesn't work. The solar_plant class itself calls on variables from the metal_mine class, now I know this is getting very spagetti-ish..but I don't know of any better conventions to follow yet.
Anyway, sometimes when I call the solar_plant class, and it in turn tries to call the metal_mine class, it says that metal_mine is not defined, which leads me to think somehow the modules or classes need to be initialized? There seems to be a bit of looping between things in the code. And depending on the order in which I try and 'play the game', sometimes I am unintentionally doing this, sometimes I'm not. I haven't yet been taught the conventions and details of importing and reloading and all that..so I have no idea if I am taking the right approach or anything.
Provided everything I just said made sense, could I get some input on how I would properly go about making the contents of these various modules freely available and modifiable to others? Am I perhaps trying to split things into different modules which you wouldn't normally do, and I should just deal with the large module? Or am I importing things wrong? Or...?
And on a side note, in most tutorials and places I look for help on this, I see classes or functions full of self.something and the init function..can I get a explanation of this? Or a link to a simple first-time-programmer's tutorial?
==================UPDATE=================
Ok so too broad, like I thought it might be. Based on the help I got, I think I can narrow it down.
I sorted out what I think need to be the class variables, those which don't change - name, base_cost_metal, and base_cost_crystal, all the rest would depend on the players currently selected building of that type (supposing they could have multiple settlements).
To take a snippet of what I have now:
class metal_mine:
name = 'Metal Mine'
base_cost_metal = 60
base_cost_crystal = 15
def __init__(self):
self.level = 0
self.production = 30
self.cost_metal = 60
self.cost_crystal = 15
self.power_use = 0
self.efficiency = 1
def calc_production(self):
self.production = int(30 + (self.efficiency * int(30 * self.level * 1.1 * self.level)))
def calc_cost_metal(self):
self.cost_metal = int(metal_mine.base_cost_metal * 1.5 ** self.level)
So to my understanding, this is now a more correctly defined class? I define the instance variables with their starting values, which are then changed as the user plays.
In my main function where I begin the game, I would create an instance of each mine, say, player_metal_mine = metal_mine(), and then I call all the functions and variables with the likes of
>>> player_metal_mine.level
0
>>> player_metal_mine.upgrade()
>>> player_metal_mine.level
1
So if this is correctly defined, do I now just import each of my modules with these new templates for each building? and once they are imported, and an instance created, are all the new instances and their variables contained within the scope(right terminology?) of the main module, meaning no need for new importing or reloading?
Provided the answer to that is yes, I do just need to import, what method should I use? I understand there is just import mines for example, but that means I would have to use mines.player_metal_mine.upgrade() to use it, which is a tiny bit more typing thanusing the likes of from mines import *, or more particularly, from mines import metal_mine, though that last options means I need to individually import every building from every module. So like I said, provided, yes, I am just importing it, what method is best?
==================UPDATE 2================= (You can probably skip the wall of text and just read this)
So I went through everything, corrected all my classes, everything seems to be importing correctly using from module import *, but I am having issues with the scope of my variables representing the resource levels.
If everything was in 1 module, right at the top I would declare each variable and give it the beginning value, e.g. metal = 1000. Then, in any method of my classes which alters this, such as upgrading a building, costing resources, or in any function which alters this, like the one which periodically adds all the production to the current resource levels, I put global metal, for example, at the top. Then, within the function, I can call and alter the value of metal no problem.
However now that I am importing these classes and functions from various modules all into 1 module, functions cant find these variables. What I thought would happen was that in the process of importing I would basically be saying, take everything in this module, and pretend its now in this one, and work with it. But apparently that's not what is happening.
In my main module, I import all my modules using from mines import * for example and define the value of say, metal, to be 1000. Now I create an instance of a metal mine, `metal_mine_one = metal_mine(), and I can call its methods and variables, e.g.
>>> metal_mine_one.production
30
But when I try call a method like metal_mine_one.upgrade(), which contains global metal, and then metal -= self.cost_metal, it give me an error saying metal is not defined. Like I said, if this is all in 1 module, this problem doesn't happen, but if I try to import things, it does.
So how can I import these modules in a way which doesn't cause this problem, and makes variables in the global scope of my main module available to all functions and methods within all imported modules?
First a little background on object oriented programming. i.e. classes. You should think of a class like a blueprint, it shows how to make something. When you make a class it describes how to make an object to the program. a simple class in python might look like this.
class foo:
def __init__(self, bars_starting_value):
self.bar = bars_starting_value
def print_bar(self):
print(self.bar)
This tells python how to make a foo object. The init function is called a constructor. It is called when you make a new foo. The self is a way of referencing the foo that is running the function. In this case every foo has its own bar which can be accessed from within a foo by using self.bar. Note that you have to put a self as the first argument of the function definition this makes it so those functions belong to a single foo and not all of them.
One might use this class like this:
my_foo = foo(15)
my_other_foo = foo(100)
foo.print_bar()
foo.bar = 20
print(foo.bar)
my_other_foo.print_bar()
This would output
15
20
100
As far as imports go. They take all things that are defined in one file and move them to be defined in another. This is useful if you put the a class definition in a file you can import it into your main program file and make objects from there.
As far as making variables available to others, you could pass the power that has been generated from all the generators to the mine's function to determine if it has enough power.
Hope this helps.
A lot of things to cover here.. init is a builtin method that is automatically called when an instance of a class is created. In the code you provided you've created a class, now you need to create an instance of that class. A simpler example:
class Test:
def __init__(self):
print "this is called when you create an instance of this class"
def a_method(self):
return True
class_instance = Test()
>>> "this is called when you create an instance of this class"
class_instance.a_method()
>>> True
The first argument in a class method is *always itself. By convention we just call that argument 'self'. Your methods did not accept any arguments, make sure they accept self (or have the decorator #staticmethod above them). Also, make sure you refer to attributes (in you case methods) by self.a_method or class_instance.a_method
I'm quite new to programming and I keep reading everywhere "using methods to change global variables is not good coding. Use very little global variables and definitely don't change them". I can't seem to find a good explanation of why or what should be done.
Lets say I want to have some sort of a game. And it has variable health=100. Now I figured this should be a global variable and not inside a class/object, but that would also mean I would need to adjust it and so on by doing something like:
def minushealth():
global health
health -= 20
I can't really seem to figure this out and maybe there is just something simple I don't know here.
You could make health an explicit argument to and return value from the function:
def minus_health(health):
return health - 20
then assign the return value when you call it:
health = minus_health(health)
Even better, get rid of the "magic number" with an optional second argument:
def minus_health(health, amount=20):
return health - amount
Note that you can now test minus_health like:
assert minus_health(100) == 80
whereas if you implemented with global, you would have to do:
health = 100
minus_health()
assert health == 80
It might not seem like a huge problem in this simple example, but as your program gets more complex you have much more setup and tear-down to do, whereas a well-isolated function will still be effectively testable in one line.
jonrsharpe's answer is on point.
But for a game type answer you'd be better off using the class/attribute solution which would look like:
player_object.minus_health()
Where minus_health would look like:
class Player(object):
def __init__(self):
__health = 100
def minus_health(self):
self.__health -= 20
Of course this doesn't take into account if the health goes below 0, etc. But you should get the idea. This way allows all "Players" to have separate health attributes.
The Player class shown in another answer is probably going to be where you end up, but just an explanation of arguments to a function, you can only modify arguments that are mutable. In your specify case, an approach similar to the Player class, but simpler, is to manage your state in a dict and then pass that dict into the function to modify an attribute:
def minus_health(entity, amount=-20):
entity['health']+=amount
# Use like so
player = dict(name='John', health=100)
minus_health(player)
lists and objects are also mutable and will work in a similar way, i.e. their contents can be modified inside the function.
I often have the following code which either leads to variable shadowing or to a multiplication of local variables
def whenadult(age):
return 18 - age
age = 5
needtowait = whenadult(age)
age has the same logical role both when passed to the function as in the main code so I would like to avoid creating something like l_age in whenadult.
What is the pythonic way to solve the "shadowing vs. variable multiplication" dilemma?
UPDATE: following up on some comments I want to make it clear that I was looking for a Python best practice (as opposed to local vs. global variables scope)
The fact that the local variable (and function parameter) age happens to have the same name as a variable somewhere else in your program is irrelevant. The whole point of local variables is that they only live within the local scope of the function they're defined in.
The fact that the local variable has the same name as the variable used elsewhere as an argument is especially not a problem. In fact, it's very common in real-life code. For example, picking a random stdlib module, the 3.3 version of cmd, the Cmd.onecmd method has a variable named line, and it passes it as an argument to the self.default method, which binds it to a parameter that's also named line.
The fact that the variable used for the argument happens to be a global variable that you could have accessed, if you didn't have a local variable of the same name, is not a problem unless you actually wanted to access that global variable. Which you didn't want to in your existing code, and almost never should want to. In this case, and in most real-world cases, it's simply a coincidence that means nothing and affects nothing, not a problem you have to solve.
The problem you're having is that PyCharm can't guess whether you wanted the global age to be accessible in whenadult. Is it possible (if not in this trivial case, maybe in more complex cases) that a human might be similarly confused, slowing down his comprehension of your code? Or that you'll one day have to write code in some environment where your code reviewers or teacher or whatever will reject your code because it doesn't pass some linter with no warnings? Maybe.
But really, in any such environment, they'd probably complain about you using global variables in the first place. And you really don't need to here. The only reason age is a global is that it has to be accessible to the top-level code. If you move that code into a function, age can become a local in that function. For example:
def whenadult(age):
return 18 - age
def main():
age = 5
needtowait = whenadult(age)
main() # possibly with an if __name__ == '__main__' guard
This will make PyCharm happy, and any linter tools, and any easily-confused or rigidly-minded human readers. It'll even make your code a tiny bit faster. On the other hand, it's more code to read—only three lines and one indent, but then the whole program is only eight lines long. So, it's a tradeoff that you can make on a case-by-case basis.
Whenever I got the warning of shadowing variable in PyCharm. I would try to rename the local variable to use the underscore prefix as the convention. That's another way to consider in addition to wrap global variables into a main() function.
def whenadult(_age):
return 18 - _age
age = 5
needtowait = whenadult(age)
PyCharm is going out of its way to prevent you from accidentally accessing(usually due to typos) a variable from the outer scope because doing so can create really nasty bugs.
Short Answer:
Most executables don't need to access the global state, so follow this structure that makes main a python function:
def helper_function():
# a function that will be used by main()
.
.
.
def main():
# make MAIN a function.
helper_function()
if __name__ == '__main__':
main()
# DONT define any variables here in this GLOBAL scope
I'm relatively new to thinking of python in terms of object-oriented programming, and it's coming relatively slowly to me.
Is it possible to pass global variables between classes with multiple functions in them? I've read extensively about them here and in other sources, but I'm still a bit confused.
My ultimate goal is to define a variable globally, assign it a value in a function of one class, and then USE it in another class's function. Is that possible? I'm building a pythonaddin for ArcMap, which requires a class for each button. I want to have a button to assign a value to a variable, and then use that variable in another class in the script.
(Before I get the flak, I know it's relatively bad form to use global variables in the first place, I'm trying to learn)
For instance, as a highly simplified example:
x = []
class A():
def func_1(self):
#populate the x variable
global x
x = 1
class B():
def func_2(self):
global x
#do stuff with x
Is this acceptable (even if not pythonic)?
Yes, it can work. Here is the modified code:
x = []
class A:
def func_1(self):
#populate the x variable
global x
x.append(1)
class B:
def func_2(self):
global x
print x
a = A()
a.func_1()
b = B()
b.func_2()
It can print the list x correctly. When it's possible, you should try to avoid global variables. You can use many other ways to pass variables between classes more safely and efficiently.
PS: Notice the parameters in the functions.
A more Pythonic solution would be to have the button objects (in their method that handles the "press" event) set an attribute or call a method of whatever object needs the information.
Yes, it is possible. Your code is almost right, just missing a couple of parenthesis in the function definitions. Other than that, it works.
Now, is that acceptable? In 99% of cases, no, it's not. There're many ways of passing variables and sharing data between classes, and using global variables is one of the worse ones, if not the worst.
sorry if this is an obvious question, but I am relatively new to python and am completely stumped at the moment. I am having difficulty getting my variables to work the way I want them too in a program I am working on.
Here is an example I quickly made to showcase my problem:
life = 200
def example(dudeHP):
dudeHP = dudeHP - 75
print (dudeHP)
example(life)
print (life) #output is 200, but I want it to be 125
As you can see, I am trying to get the value of the global variable "life" to change inside the def example codeblock with dudeHP (which would be a local variable if I am not mistaken?)
Is this viable? Is there a better way to accomplish this? Or am I doing it all wrong? Thankyou in advance :)
Well, first of all, you'll probably want to write an class or something to organize all this at some point. Modifying global variables from within functions or methods is usually considered a bad idea.
What you might want to try is this:
life = 200
def example(x):
return x - 75
life = example(life)
Of course in this case the operation of subtraction is so trivial that you don't need to encapsulate it in a function.
BTW, the question is not Python3 specific unless a newcomer gets stumped by the title. It is a general Python language question.
You have to understand the scope and the nature of the variables in Python. Variables are just names to hold certain values and their life is within the scope of the block they are defined it, although the inner scope variable can access the variable from the outer scope. The function you have defined has its own scope and it's own stack to maintain and you are passing a copy of the variable to that function.
The best way to deal with this is return value from the function as pointed out in another answer.
Having said that, if you really want to access variable in a global manner, you could do like this.
a = 200
def example(b):
global a
a = a - 25
example(a)
print a
But this is frowned upon and not a good style. There is also a trick which you are use, but that goes beyond the beginner level and it goes like this.
a = [200]
def example(a):
a[0] = a[0] - 25
example(a)
print a[0]
You can easily make mistakes you if adopt this way,
But the correct way to go about this is still:
a = 200
def example(b):
return b - 25
print example(a)
Further to Ned Batchelders and Kristoff's hints and suggestions to use a class, this is a way you could do that:
class Dude:
def __init__(self, hp=200):
self.hp = hp
def eat(self):
self.hp = self.hp + 25
def example(dude):
dude.hp -= 75
hero = Dude()
example(hero)
hero.eat()
print(hero.hp) # 150
Unless you have a good reason why example should be a stand-alone function, you should make it a method of Dude like eat, since example clearly acts on and in a sense belongs to an object of the class Dude.
In your function, the name dudeHP is local to the function. When you change it, you are only changing the local name, you cannot affect the value of the name passed in.
You can either make the integer be an element of a container that you pass in, so that you can change the container, or you can return the value from the function.
Since dudehp is having local scope in that function it doesn't have life outside that function. So, using dudehp to update life is illegal you can do this by using a global keyword or returing the value as others have mentioned... hope this explanation is useful and any corrections to this will be accepted.