为什么改变类的属性会导致不同的后果?

Why change class's attributes result in different consequences?

我创建了一张 class 卡片,其属性为 suitList 和编号。当我更改它们时,我希望它不会影响不同的对象。然而,结果令人困惑。为什么更改 suitList 会影响其他对象的 suitList?请解释一下。

class Card:
  suitList = ["CLubs"]
  number = 1

  def __init__ (self, rank = 0):
      self.rank = rank

  def __str__ (self):
      return (self.suitList[self.rank] + "  " + str(self.number) + ";\n")
c1 = Card()
c2 = Card()
print c1
c1.suitList[0] = "Heart"
c1.number = 3
print c1
print c2
c3 = Card()
print c3

那是因为您已将 suitList 设为 class 属性 ,该属性在 class 的所有实例之间共享。如果您希望每个实例都有一个唯一的 suitList 列表,您应该将其设为 实例属性 :

def __init__(self, rank = 0):
     self.rank = rank
     self.suitList = ["CLubs"]

您可能还想将 number 的定义移动到 __init__ 方法中,以便它也成为实例属性:

def __init__(self, rank = 0):
     self.rank = rank
     self.suitList = ["CLubs"]
     self.number = 1

有关这方面的更多信息,请参阅 Python: Difference between class and instance attributes


此外,您会注意到我在所有名称前都添加了 self. 前缀。您需要这样做,以便将值设为 class 的属性。如果我们改为这样做:

def __init__(self, rank = 0):
     self.rank = rank
     suitList = ["CLubs"]
     number = 1

suitListnumber 将成为 __init__ 方法的局部。

这 2 个属性是 class 属性 static variables。如果要声明非静态属性,则必须在变量名称前加上 self,它指的是您正在使用的 class 的当前实例:

class MyClass:
    def __init__(self):
        self.suitList = ["CLubs"]
        self.number = 1

有关什么是 self 以及静态和非静态 class 变量的区别的更多信息:

  1. Python __init__ and self what do they do?

  2. Python 'self' keyword

  3. Explaining the python 'self' variable to a beginner

  4. What is the purpose of self?

  5. Python: Difference between class and instance attributes

如前所述,您混淆了 class 属性和实例属性。

在你的例子中,suitList 和 number 是 class 属性,它们在所有实例(c1,c2,c3)之间共享 当您像 c1.suitList[0] = "Heart" 中那样更改 class 属性时,它将反映在所有 class 个实例中。

要解决此问题,您有一些选择:我给您两个。

1) 仅使用实例属性:

class Card:
    def __init__(self,number=0,suit="CLubs"):
        self.number = number
        self.suit = suit

    def __str__(self):
        return "%s %d"%(self.suit,self.number)

c1 = Card()
c2 = Card()
c1.suit = "Heart"
c1.number = 3
print c1
print c2

在这种情况下,没有 class 属性,要更改您直接使用 c1.suit 分配的卡组。

2) 混合使用 class/attribute:

class Card:
    suitList = ["CLubs", "Heart"]
    def __init__(self,number=0,rank=0):
        self.rank = rank
        self.number = number

    def __str__(self):
        return (Card.suitList[self.rank] + "  " + str(self.number))

c1 = Card()
c2 = Card()
c1.rank = 1
c1.number = 3
print c1
print c2

Rank 在这种情况下是在 suitList 中查找的索引。要更改牌的花色,您需要更改它的等级,而不是花色列表。

两个示例输出:

Heart 3
CLubs 0