我正在用OOP开发一个纸牌游戏只是为了练习,我在我写的东西里有一些奇怪的行为。当我使用clear方法清空双手时,所发生的是单个的手显示它们是空的,但是当我查看hands变量(显示两只手)时,它们不是空的。我的问题是为什么,哈哈?我将把代码放在下面,结果放在下面。谢谢你的帮助。你知道吗
import random
class a:
my_hand = []
other_hand = []
hands = [my_hand, other_hand]
def h(self):
for rounds in range(5):
for hand in a.hands:
hand.append(rounds)
def shuffle(self):
random.shuffle(a.my_hand)
random.shuffle(a.other_hand)
def clear(self):
a.my_hand = []
a.other_hand = []
x = a()
x.h()
x.shuffle()
x.hands
[[1, 0, 4, 2, 3], [3, 4, 2, 0, 1]]
x.clear()
[[1, 0, 4, 2, 3], [3, 4, 2, 0, 1]]
x.my_hand
[]
x.other_hand
[]
x.hands
[[1, 0, 4, 2, 3], [3, 4, 2, 0, 1]]
您正在创建新的空列表,但是
hands
仍然引用旧列表。你知道吗您可以简单地确保
hands
引用新的空列表。你知道吗或者可以通过删除所有元素来修改列表本身。你知道吗
仅供参考,所有函数都定义为成员方法,但变量始终是静态的。您可能希望引用
self
而不是a
,或者使您的方法成为静态的(使用@staticmethod
)。你知道吗在
a
类中,my_hand
、other_hand
和hands
变量都是类属性(即静态属性),而不是实例属性。你知道吗同样在
clear
方法中,您重新分配了my_hand
和other_hand
,但是hands
仍然引用旧的list
,因此它的内容没有改变。如果您使用的是python3,那么应该使用list
的clear()
方法:my_hand.clear()
和other_hand.clear()
,那么hands
将引用两个空的list
。 在python2上,您应该执行del my_hand[:]
。你知道吗如果要分配实例属性,必须执行
self.attribute = value
。 为此,赋值应该放在类的构造函数__init__
方法中。你知道吗就目前的代码而言,如果您创建两个
a
实例,那么它们将共享双手,这可能是您所不希望的。你知道吗正确的代码是:
使用iPython的示例输出:
请注意,它可用于多个实例:
您的代码将在两个实例之间共享
hands
。你知道吗为了避免写太多的评论,我在这里对发生的事情做了更多的解释。你知道吗
首先,在代码中
my_hand
和other_hand
是类属性。为什么这很重要?这很重要,因为类属性在实例之间共享:调用
clear
修改类属性,从而修改使用它们的所有实例。这通常是你做的而不是你想要的。你知道吗t实例没有任何其他实例属性,这意味着所有实例实际上是相等的;它们的行为和提供的数据都相同。唯一的区别是他们的身份。如果您不打算使用标识,那么拥有一个类和多个实例是没有用的,因为您可以简单地使用单个对象。你知道吗
如果希望实例拥有自己的数据,独立于其他实例的数据,则必须使用实例属性。你知道吗
关于
del
语句。正如我在评论中已经说过的del
有两种不同的用法。语句的full语法是:其中“sequence,of,del_targets”是一个逗号分隔的列表,我称之为
del_targets
。根据del_target
,行为会发生变化。你知道吗如果它是一个大于
del
的标识符,则从作用域中删除引用,减少标识符引用的对象的引用计数。你知道吗例如:
如果一个对象没有引用,它将被销毁,因此在
del a
之后,空列表将被解释器销毁。你知道吗目标也可以是“下标”,即像
name[key-or-index]
或name[a:slice]
(或name[start:stop:step]
)这样的表达式。 切片语法(带冒号的语法)用于指定一系列索引:当将
del
语句与这样的表达式一起使用时,python调用对象的__delitem__
方法,传递索引或切片。这意味着:意思是:删除列表
numbers
中与片:
中的索引相对应的所有元素。因为切片:
意味着“序列中的所有索引”,所以结果是清空列表。请注意,它不会从列表中删除引用。它只作用于它的元素。你知道吗您可以使用以下方法获得相同的效果:
这告诉python用
[]
中的元素替换片:
对应的元素序列。因为:
表示“所有元素”,而[]
是空的,所以效果是从列表中删除所有元素。 这种语法在引擎盖下调用list.__setitem__
而不是list.__delitem__
,但结果是相同的。 但是您也可以这样做:numbers[:] = [2]
,然后numbers
的所有元素都将被删除并且将插入2
,从而产生列表[2]
。你知道吗这两种方法都有效,但是我更喜欢
del
语法,因为它可以明确您的意图。 当你读到:你知道这个语句会删除一些东西。然后您看到了下标
[:]
,您知道它将删除something
中的元素,而不是引用something
。但是当你看到:首先你想,好吧,这是一项任务。然后您会看到
[:]
,并且您知道您正在“覆盖”列表的内容。然后看右边的[]
,我们将用一个空列表覆盖元素。。。最后,您知道该语句将从列表中删除所有元素。你知道吗作为OOP的练习,你的代码很奇怪。。。您正在实例方法中使用类成员。方法中的类实例名为
self
,而不是a
。将代码更改为对代码的其他部分也一样。你知道吗
然而,您面临的问题是另一个:当重新分配
a.hand
和a.other_hand
时,您正在创建两个新的空数组,因此a.hands
一直指向在h
中创建的旧数组。你知道吗将代码更改为
或者更惯用一点
会解决这个问题。你知道吗
在Python中
[:]
语法表示“的所有元素”,还允许切片(例如a.hand[1:-1]
是a.hand
中除first和last之外的元素列表)。你知道吗相关问题 更多 >
编程相关推荐