Converting a program from FreeBASIC to Python: globalizing variables
In a previous post, I was told I am coding in Python like you would in BASIC (I am not "thinking" in Python yet). This is probably true and this is why I need help. This being said, I have read one book about Python so far (Bytes of Python), I bought two more books online (one of which is Invent with Python, which I am reading) and I did many tutorials from The New Boston. Still, my question might sound newbie-ish to you.
In FreeBasic, variables are all globalized. In Python, I have to globalize them for every single new function I create. This isn't very practical. So what am I expected to do? How would a "native Python speaker" tackle this problem? Below you'll find a small program I have created where I globalize in all my variables inside functions.
#-*- coding: iso8859_1 -*-
import random
ca1 = 10
ca2 = 10
taco = 20
pv1 = random.randint(1,10)
pv2 = random.randint(1,10)
cnt = 0
pv1Dep = pv1
pv2Dep = pv2
ast = "*" * 7
d20_1 = random.randint(1,20)
d8_1 = random.randint(1,8)
d20_2 = random.randint(1,20)
d8_2 = random.randint(1,8)
def intro():
global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
print "Imaginez deux guerriers de D&D 2e édition qui se battent."
print
print "Guerrier 1: " + str(pv1) + " PV, épée longue (1-8 points de dégât), TACO de 20, CA de " + str(ca1) + "."
print "Guerrier 2: " + str(pv2) + " PV, épée longue (1-8 points de dégât), TACO de 20, CA de " + str(ca2) + "."
print
def nouveauCombat():
global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
print ast + "NOUVEAU COMBAT" + ast
print
while ((pv1 > 0) and (pv2 > 0)):
cnt = cnt + 1
print ast + "ROUND " + str(cnt) + ": INITIATIVE" + ast
print
calcInitiative()
print
print ast + "RESULTAT" + ast
print
resultat()
def calcInitiative():
global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
initiative1 = random.randint(1,10)
initiative2 = random.randint(1,10)
print "Le guerrier 1 fait son jet d'initiative."
print str(initiative1) + "!"
print
print "Le guerrier 2 fait son jet d'initiative."
print str(initiative2) + "!"
print
if initiative1 == initiative2:
print "Les deux guerriers attaquent au même moment."
print
print ast + "ROUND " + str(cnt) + ": ATTAQUE" + ast
print
attaque1()
print
attaque2()
elif initiative1 < initiative2:
print "Le guerrier 1 attaque en premier."
print
print ast + "ROUND " + str(cnt) + ": ATTAQUE" + ast
print
attaque1()
print
if pv2 > 0:
print
attaque2()
else:
print "Le guerrier 2 attaque en premier."
print
print ast + "ROUND " + str(cnt) + ": ATTAQUE" + ast
print
attaque2()
print
if pv1 > 0:
print
attaque2()
def attaque1():
开发者_运维问答global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
print "Le guerrier 1 fait son jet de toucher."
print str(d20_1) + "!"
if d20_1 >= ca2:
print "Touché!"
pv2 = pv2 - d8_1
print str(d8_1) + " points de dégât!"
print "Le guerrier 2 est à " + str(pv2) + "/" + str(pv2Dep) + " PV!"
else:
print "Raté!"
def attaque2():
global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
print "Le guerrier 2 fait son jet de toucher."
print str(d20_2) + "!"
if d20_2 >= ca1:
print "Touché!"
pv1 = pv1 - d8_2
print str(d8_2) + " points de dégât!"
print "Le guerrier 1 est à " + str(pv1) + "/" + str(pv1Dep) + " PV!"
else:
print "Raté!"
def resultat():
global ca1
global ca2
global taco
global pv1
global pv2
global cnt
global pv1Dep
global pv2Dep
global d20_1
global d8_1
global d20_2
global d8_2
print "Le combat prend fin au round " + str(cnt) + "."
print
if pv1 == pv1Dep:
print "Le guerrier 1 n'a pas la moindre égratignure."
elif pv1 > 0:
print "Le guerrier 1 est blessé."
else:
print "Le guerrier 1 est mort."
print "Il finit le combat avec " + str(pv1) + "/" +str (pv1Dep) + " PV."
print
if pv2 == pv2Dep:
print "Le guerrier 2 n'a pas la moindre égratignure."
elif pv2 > 0:
print "Le guerrier 2 est blessé."
else:
print "Le guerrier 2 est mort."
print "Il finit le combat avec " + str(pv2) + "/" +str (pv2Dep) + " PV."
print
intro()
nouveauCombat()
You don't need to declare a name as global unless you are going to assign to it.
a = 1
b = 2
def foo():
global b
print a # prints 1
b = 3
foo()
print b # prints 3
I've reorganized your program to show you the basics of object oriented programming. You need to learn about classes and objects. You should also look at string formatting for the right way to put strings together.
Basically, you create two player objects, and then create a combat object for those two players. Then, you call methods on the combat object in order to actually do the combat. self
is how an instance of a class refers to itself. Any good Python tutorial should teach you about all of these things.
The only remaining global variable is a constant, ast
. Global constants can occasionally be OK.
#-*- coding: iso8859_1 -*-
import random
ast = "*" * 7
class Player(object):
def __init__(self, num, ca):
self.ca = ca
self.num = num
self.pv = random.randint(1,10)
self.d20 = random.randint(1,20)
self.d8 = random.randint(1,8)
self.pvDep= self.pv
class Combat(object):
def __init__(self, player1, player2):
self.player1 = player1
self.player2 = player2
self.cnt = 0
def intro(self):
print "Imaginez deux guerriers de D&D 2e édition qui se battent."
print
print "Guerrier 1: " + str(player1.pv) + " PV, épée longue (1-8 points de dégât), TACO de 20, CA de " + str(player1.ca) + "."
print "Guerrier 2: " + str(player2.pv) + " PV, épée longue (1-8 points de dégât), TACO de 20, CA de " + str(player2.ca) + "."
print
def nouveauCombat(self):
print ast + "NOUVEAU COMBAT" + ast
print
while ((self.player1.pv > 0) and (self.player2.pv > 0)):
self.cnt = self.cnt + 1
print ast + "ROUND " + str(self.cnt) + ": INITIATIVE" + ast
print
self.calcInitiative()
print
print ast + "RESULTAT" + ast
print
self.resultat()
def calcInitiative(self):
initiative1 = random.randint(1,10)
initiative2 = random.randint(1,10)
print "Le guerrier 1 fait son jet d'initiative."
print str(initiative1) + "!"
print
print "Le guerrier 2 fait son jet d'initiative."
print str(initiative2) + "!"
print
if initiative1 == initiative2:
print "Les deux guerriers attaquent au même moment."
print
print ast + "ROUND " + str(self.cnt) + ": ATTAQUE" + ast
print
self.attaque(self.player1, self.player2)
print
self.attaque(self.player2, self.player1)
elif initiative1 < initiative2:
print "Le guerrier 1 attaque en premier."
print
print ast + "ROUND " + str(self.cnt) + ": ATTAQUE" + ast
print
self.attaque(self.player1, self.player2)
print
if self.player2.pv > 0:
print
self.attaque(self.player2, self.player1)
else:
print "Le guerrier 2 attaque en premier."
print
print ast + "ROUND " + str(self.cnt) + ": ATTAQUE" + ast
print
self.attaque(self.player2, self.player1)
print
if self.player1.pv > 0:
print
self.attaque(self.player1, self.player2)
def attaque(self, player1, player2):
print "Le guerrier" + str(player1.num) + " fait son jet de toucher."
print str(player1.d20) + "!"
if player1.d20 >= player2.ca:
print "Touché!"
player2.pv = player2.pv - player1.d8
print str(player1.d8) + " points de dégât!"
print "Le guerrier 2 est à " + str(player2.pv) + "/" + str(player2.pvDep) + " PV!"
else:
print "Raté!"
def resultat(self):
print "Le combat prend fin au round " + str(self.cnt) + "."
print
if player1.pv == player1.pvDep:
print "Le guerrier 1 n'a pas la moindre égratignure."
elif player1.pv > 0:
print "Le guerrier 1 est blessé."
else:
print "Le guerrier 1 est mort."
print "Il finit le combat avec " + str(player1.pv) + "/" +str (player1.pvDep) + " PV."
print
if player2.pv == player2.pvDep:
print "Le guerrier 2 n'a pas la moindre égratignure."
elif player2.pv > 0:
print "Le guerrier 2 est blessé."
else:
print "Le guerrier 2 est mort."
print "Il finit le combat avec " + str(player2.pv) + "/" +str (player2.pvDep) + " PV."
print
player1 = Player(1, 10)
player2 = Player(2, 10)
combat = Combat(player1, player2)
combat.intro()
combat.nouveauCombat()
In python, as in many modern languages, prolific use of global variables is considered an anti-pattern. There are lots of reasons why:
- it obstructs function reentrancy, which is important for efficient multi-threaded code.
- it makes unit testing harder, which is helpful on medium to large projects
- it makes modules more interdependent, which makes it harder to track down problems and to fix them once they are found.
You should endevor to pass the data each function needs:
def foo():
bar = 10
baz(bar)
def baz(bar):
print bar
If you need to capture state from one function to the next, you can wrap that into a class.
class quux(object):
def __init__(self):
self.a = 1
self.b = "two"
def foo():
bar = quux()
baz(bar)
print bar.a, bar.b
def baz(bar):
bar.a = len(bar.b)
In summary, You almost never need globals, but in many cases, you need to have something that is not global.
Global variables by default are widely (universally?) considered a design flaw. If you want to write "Pythonic" code, you should strive to have the smallest possible amount of global state.
精彩评论