我有一个创建播放器对象的函数,但是当引用该对象时,会出现NameError。我认为这是由于本地范围而发生的,但全球应该解决此问题...
我刚开始使用OOP,此代码在python shell中有效,但在脚本模式下不起作用。
endl = lambda a: print("\n"*a)
class Score:
_tie = 0
def __init__(self):
self._name = ""
self._wins = 0
self._loses = 0
def get_name(self):
print
self._name = input().upper()
def inc_score(self, wlt):
if wlt=="w": self._wins += 1
elif wlt=="l": self._loses += 1
elif wlt=="t": _tie += 1
else: raise ValueError("Bad Input")
def player_num(): #Gets number of players
while True:
clear()
endl(10)
print("1 player or 2 players?")
endl(5)
pnum = input('Enter 1 or 2: '.rjust(55))
try:
assert int(pnum) == 1 or int(pnum) == 2
clear()
return int(pnum)
except:
print("\n\nPlease enter 1 or 2.")
def create_player(): #Creates players
global p1
p1 = Score()
yield 0 #stops here if there is only 1 player
global p2
p2 = Score()
def pr_(): #testing object
input(p1._wins)
input(p2._wins)
for i in range(player_num()):
create_player()
input(p1)
input(p1._wins())
pr_()
无论我在哪里引用p1,我都应该获得必需的对象属性,但是我遇到了这个错误
Traceback (most recent call last):
File "G:/Python/TicTacTwo.py", line 83, in <module>
input(p1)
NameError: name 'p1' is not defined
答案 0 :(得分:1)
您的问题不是global
,而是yield
中的create_player()
,这会使函数变成生成器。
您可以做什么:
实际上是通过执行list(create_player())
在生成器中运行的(不好,但是可行)。
但是我建议您改为重新设计代码,例如通过调用具有玩家人数的方法:
def create_player(num): #Creates players
if num >= 1:
global p1
p1 = Score()
if num >= 2:
global p2
p2 = Score()
如果您解决此问题,下一个问题将是
1)input(p1)
将打印p1
的字符串表示形式,并且输入将丢失,您可能想要p1.get_name()
。
2)input(p1._wins())
将提高TypeError: 'int' object is not callable
答案 1 :(得分:0)
我将重新设计该应用程序,以引入功能强大的python构造,这对进入OOP可能会有所帮助。
Score
,不要叫他们Player
。_tie
使其成为一个类变量,因此该值将为所有玩家共享。只有两个参与者,这可能是正确的,但是当您尝试扩展到更多玩家时,这会伤害您。保留它作为实例变量。__slots__
的粉丝。它是一类特殊变量,它告诉实例变量它们可以具有哪些属性。这将防止错误地插入新属性,并提高每个实例所需的内存,您可以删除此行,它会起作用,但我建议您保留它。 __slots__
是任何可迭代的。我推荐使用元组,因为它们是不可变的。a = instance.property
),为其分配值(instance.property = value
)或删除值(del instance.property
)时的行为。 。名称似乎非常适合房地产。 getter将仅返回存储在_name
中的值,setter将删除开头和结尾的空格,并将每个单词的首字母大写,而deletter将再次设置默认名称。代码看起来像这样:
# DEFAULT_NAME is a contant so that we only have to modify it here if we want another
# default name instead of having to change it in several places
DEFAULT_NAME = "Unknown"
class Player:
# ( and ) are not needed but I'll keep them for clarity
__slots__ = ("_name", "_wins", "_loses", "_ties")
# We give a default name in case none is provided when the instance is built
def __init__(self, name=DEFAULT_NAME):
self._name = name
self._wins = 0
self._loses = 0
self._ties = 0
# This is part of the name property, more specifically the getter and the documentation
@property
def name(self):
""" The name of the player """
return self._name
# This is the setter of the name property, it removes spaces with .strip() and
# capitalizes first letters of each word with .title()
@name.setter
def name(self, name):
self._name = name.strip().title()
# This is the last part, the deleter, that assigns the default name again
@name.deleter
def name(self):
self._name = DEFAULT_NAME
def won(self):
self._wins += 1
def lost(self):
self._loses += 1
def tied(self):
self._ties += 1
现在,这就是播放器本身所需要的。游戏应该在创建玩家的类别上有所不同。
class Game:
_min_players = 1
_max_players = 2
def __init__(self, players):
# Check that the number of players is correct
if not(self._min_players <= players <= self._max_players):
raise ValueError("Number of players is invalid")
self._players = []
for i in range(1, players+1):
self._players.append(Player(input("Insert player {}'s name: ".format(i))))
@property
def players(self):
# We return a copy of the list to avoid mutating the inner list
return self._players.copy()
现在将按照以下方式创建游戏:
def new_game():
return Game(int(input("How many players? ")))
此后,您将为游戏创建新的方法,例如进行比赛,从而调用玩家won
,lost
或tied
方法,等等。
我希望这里介绍的一些概念对您有用,例如属性,插槽,将对象创建委托给所有者对象等。