Python - 类属性的意外行为



用简单的文字编辑

法典:

class temp:
attr1 = 0
attr2 = []
t1 = temp()
t2 = temp()
t1.attr1 = 50
t1.attr2.append(50)
print(t1.attr1)
print(t1.attr2)
print(t2.attr1)
print(t2.attr2)

输出:

50
[50]
0
[50]

我只在对象t1上调用了appendattr2append更改了两个对象的attr2。 如果共享attr2(类属性(,那么为什么attr1值对于t1t2是不同的。是什么导致了这种意外行为?

老问题

我正在为二十一点编写python代码。我编写的代码如下。

from random import randint
from IPython.display import clear_output
deck = ["S","D","C","H"]
class Player:
cards = []
total = 0
amount = 0
def __init__(self,money=0):
self.amount = money
def busted(self):
return self.total > 21
def showCards(self):
for i in self.cards:
print("| {}{} |".format(i%13,deck[i//13]),end = " ")
print()
def hit(self):
no = randint(1,53)
self.cards.append(no)
if no % 13 == 1:
if self.total + 11 > 21:
self.total+=1
else:
self.total+=11
else:
self.total += (no%13 if no%13 <= 10 else 10)

dealer = Player(10000)
p1 = Player(0)
print("Welcome to BlackJack ....")
while True:
try:
p1.amount = int(input("Enter the amount you currrently have for the game"))
except:
print("invalid Value")
continue
else:
break
Game = True
while Game:
print(dealer.cards)
print(p1.cards)
dealer.hit()
print(dealer.cards)
print(p1.cards)
print(dealer.total)
print(p1.total)
Game = False

此代码的输出如下

Welcome to BlackJack ....
Enter the amount you currrently have for the game55
[]
[]
[45]
[45]
6
0

如您所见,我只在对象上调用hit()一次dealer但它将其附加到dealerp1对象的cards属性。但是total属性是不同的。谁能解释可能导致这种意外行为的原因?

当你执行t1.attr1 = 50时,你会attr1重新绑定到t1对象的属性命名空间中的新值。它以前允许您访问类命名空间中绑定的值,但是当您绑定新值时,您将从类中隐藏该值(仅适用于该实例(。

相反,当你执行t1.attr2.append(50)时,你正在改变现有的列表(它绑定在类命名空间中,但通过所有实例都可见(,根本不会发生变量的重新绑定。这就是为什么你会看到t2的变化。变量t1.attr2t2.attr2都是对同一对象的引用(您可以使用is运算符进行验证:t1.attr2 is t2.attr2(。

通常,如果不希望所有实例共享类变量,则对类变量使用列表或其他可变值通常不是一个好主意。不过,这并不是禁止的,因为有时您确实特别想要共享行为。

我明白你的要求。您需要区分所有带有玩家卡的卡片。因此,与其将所有内容命名为卡片,我建议这样做:

class Player:
all_cards = []
total = 0
amount = 0

并将__init__更新为:

def __init__(self, money=0):
self.amount = money
self.player_cards = []

在执行追加操作时,将其附加到all_cardsplayer_cards。无论如何,您只打印玩家卡,您可以看到不同的卡片列表。

这是完整的代码:

from random import randint
from IPython.display import clear_output
deck = ["S","D","C","H"]
class Player:
all_cards = []
total = 0
amount = 0
def __init__(self,money=0):
self.player_cards = []
self.amount = money
def busted(self):
return self.total > 21
def showCards(self):
for i in self.player_cards:
print("| {}{} |".format(i%13,deck[i//13]),end = " ")
print()
def hit(self):
no = randint(1,53)
self.player_cards.append(no)
self.all_cards.append(no)
if no % 13 == 1:
if self.total + 11 > 21:
self.total+=1
else:
self.total+=11
else:
self.total += (no%13 if no%13 <= 10 else 10)

dealer = Player(10000)
p1 = Player(0)
print("Welcome to BlackJack ....")
while True:
try:
p1.amount = int(input("Enter the amount you currrently have for the game"))
except:
print("invalid Value")
continue
else:
break
Game = True
while Game:
print(dealer.player_cards)
print(p1.player_cards)
dealer.hit()
print(dealer.player_cards)
print(p1.player_cards)
print(dealer.total)
print(p1.total)
Game = False

发生这种情况是因为 list 是一个可变对象,并且仅在定义类时创建一次,这就是为什么当您创建两个实例时它会变得共享的原因。因此,为了解决这个问题,我们可以使用我上面提到的构造函数。当我们把列表放在构造函数中时,每当对象实例化时,也会创建新列表。

相关内容

  • 没有找到相关文章

最新更新