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.
Related
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.
Let us say I have a module myfunctions with two functions:
def functionA():
return'Function A chosen.'
def functionB():
return 'Function B chosen.'
Then, I have a module silly which does something with these functions:
def sillyprinter():
print chosen_function
print chosen_function()
Then, In my main script, I have:
import myfunctions
import silly
class FunctionChooser():
def __init__(function_choice="A"):
self.choose_function_given_choice(function_choice)
def do_something_many_times(self):
for i in range(1000):
silly.sillyprinter()
The idea of FunctionChooser is that it is initialized with some user given information regarding which function (A or B) I want to use from myfunctions. Then, after this choice is made, the user can call do_something_many_times, which makes use of yet another module, which will use the chosen function from myfunctions many times.
In order to be efficient, I'd like to avoid the following:
1) Choosing which function to use again and again -- so I'd like to make the choice once (during initialization), and then have it "saved" somehow. This requirement disqualifies designs like:
def sillyprinter(chosen_function):
print chosen_function
print chosen_function()
# =================================
class FunctionChooser():
def __init__(function_choice="A"):
self.function_choice = function_choice
def choose_function_given_choice(self):
if self.function_choice == "A":
return myfunctions.functionA
elif self.function_choice == "B":
return myfunctions.functionB
def do_something_many_times(self):
for i in range(1000):
silly.silly_printer(self.choose_function_given_choice())
2) storing the function I'd like to choose as a class attribute, since self calls are expensive, and the use case is numerical. This requirements disqualifies designs like:
def sillyprinter(chosen_function):
print chosen_function
print chosen_function()
# =================================
class FunctionChooser():
def __init__(function_choice="A"):
self.function_choice = function_choice
def choose_function_given_choice(self):
if self.function_choice == "A":
self.chosen_function = myfunctions.functionA
elif self.function_choice == "B":
self.chosen_function = myfunctions.functionB
def do_something_many_times(self):
for i in range(1000):
silly.silly_printer(self.chosen_function)
My current idea is to do the following:
def sillyprinter(chosen_function):
print chosen_function
print chosen_function()
# =================================
class FunctionChooser():
def __init__(function_choice="A"):
self.function_choice = function_choice
def choose_function_given_choice(self):
if self.function_choice == "A":
self.chosen_function = myfunctions.functionA
elif self.function_choice == "B":
self.chosen_function = myfunctions.functionB
def do_something_many_times(self):
chosen_function = self.chosen_function
for i in range(1000):
silly.silly_printer(chosen_function)
It is only very slightly different than the design I disqualified in 2), in that it makes a self call once and then stores that function for use as a local variable.
Is this the best way to design such "function choice" in Python, given my requirements? (see below)
EDIT: I figure I should make requirements clearer, in order to make the question less general
The "function choice string" does not have to be a string -- it could be any variable that encodes for some sort of function choice.
I want to avoid self. access calls (but perhaps . access calls in general?) due to issues with numba optimizing code with access calls: Design heuristics for writing Python classes that interact with `scipy.integrate.odeint`?
The "function choice" variable is only given once, so we can consider it to effectively be a constant.
The fundamental answer is that any of these three options may be the "best," depending on circumstances. But the differences between the options you've chosen are subtle, and not likely to affect performance significantly most of the time. Instead of worrying about efficiency here, you should worry about conceptual elegance. Then, if you need efficiency, optimize.
I could imagine situations when any of these three options would be preferable, conceptually.
Suppose the choice of function will depend on a value that changes frequently. You'll have to check its state frequently, so what will you gain by storing it? It makes more sense simply to look it up every time. In this case, (1) is the best option.
Suppose the choice of function won't be based on a value that changes often, or that is easy to "invert control" with (i.e. the code that pays attention to the variable knows to change the function selection as well). Unless you have an overriding reason to worry about the extra overhead of a single . access, just store this as an attribute. (And note that looking up an attribute in self is no more costly than looking up an attribute in some other object. The operation is exactly the same; there's nothing special about self!) In this case, (2) is the best option.
Suppose, as you have, that the choice of function won't be based on a value that changes often, but that the function will itself be called frequently. Furthermore, you are certain that the . access is slowing down your code, because you have done rigorous tests. Then it makes sense to cache the result of the . access in a local variable, as in option (3). (But note that in option (3) you're still using another . operation -- that should be cached as well, as in Ignacio's answer.) But beware premature optimization! Every local variable imposes an additional cognitive load on you and your fellow developers -- you must be sure it's worth it. Only choose this option if you've actually done tests, and it makes a significant speed difference.
A final note: there's also some extra complexity in your example code that I am assuming is supposed to be evocative of complexity rather than specifically purposeful in this particular case. For example, given the code you've actually posted, the choose_function_given_choice function is quite useless. But I think you know that already. Still, to restate the obvious -- you should make all of this happen in the simplest way possible.
No. Functions in Python are first-class objects; treat them as such.
class FunctionChooser():
def __init__(function_choice=myfunctions.functionA):
self.function_choice = function_choice
def do_something_many_times(self):
chosen_function = self.chosen_function
printer = silly.silly_printer
for i in range(1000):
printer(chosen_function)
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've been teaching 8th-9th graders basic computer programming for two weeks, and yesterday I tried to show them how they could make real simple text-adventure games in Python.
Scenes are functions, (e.g dragons_cave()) which consist of some print statements and then a call to input(), asking the player where they want to go next, which then gets passed to globals() to find the appropriate function and then called. I know it's not ideal (at what point would the huge chain of functions start becoming a problem?) but, of what crossed my mind, it seems to be the simplest for them while involving only a little handwaving.
My problem is with global state — ex. the player gets a key in one scene and only then can they unlock the gate in another scene. When I have global immutables like strings or booleans, Python wants me to use the global keyword at the beginning of the function.
global hasKey
hasKey = True
I'm pretty okay with that, but I have a vague sense (picked up from Stackoverflow among other places on the Internet) that global is frowned upon and always has a superior counterpart. I could have a global dictionary or wrap everything in a class, but I'm not sure if I could defend those options clearly to my kids (who are still thinking through the implications of variables).
Whatever I use, I want to be able to explain straightforwardly to my kids why we do it this way and why doing it this way is necessary. global seems to have both these properties, but is it bad?
I would encourage them to start learning OO
class Location:
name="a place"
description = "A dark place. there are exits to the North and East"
exits = "North","East"
def __str__(self):
return "%s\n%s"%(self.name,self.description)
class Player:
current_location = "Home"
inventory = ["Blue Key","Magic Thumbtacks"]
health = 100
name = "Unknown"
def __init__(self,name):
self.name = name
player = Player("Player 1")
loc = Location()
print loc
x = input("Input:")
To be honest a game is a difficult concept (even a text adventure). But I would start them directly on OO concepts, they will benefit more from that in the long term.
Granted this example is very small and leaves a lot of implementation details out.
An unrelated but better OO example would be:
class Animal:
voice = '...'
def speak(self):
return "A %s Says '%s'"%(self.__class__.__name__, self.voice)
class Dog(Animal):
voice = "Bark, Bark"
class Duck(Animal):
voice = "Quack, Quack"
print Dog().speak()
print Duck().speak()
Assuming you want to keep things as simple as possible (no OO) and want to avoid introducing the global keyword, you could instead use a state dictionary and assign variables in there.
state['hasKey'] = True
Since access to this dict is not a variable assignment you avoid introducing the global keyword and at the same time can teach how to use a dict (checking for keys etc.)
Of course you still use a global variable and don't really address the issue of good coding style. But on the other hand, it could serve as an introduction to scopes and namespaces.
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.