Python-类属性的意外行为

时间:2018-06-20 15:00:32

标签: python python-3.x class object class-attributes

用简单的文字编辑

代码:

#include <tesseract/baseapi.h>
#include <leptonica/allheaders.h>

int main()
{
    char *outText;

    tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
    // Initialize tesseract-ocr with English, without specifying tessdata path
    if (api->Init(NULL, "eng")) {
        fprintf(stderr, "Could not initialize tesseract.\n");
        exit(1);
    }

    // Open input image with leptonica library
    Pix *image = pixRead("/usr/src/tesseract/testing/phototest.tif");
    api->SetImage(image);
    // Get OCR result
    outText = api->GetUTF8Text();
    printf("OCR output:\n%s", outText);

    // Destroy used object and release memory
    api->End();
    delete[] outText;
    pixDestroy(&image);

    return 0;
}

输出:

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] 个对象append上调用了attr2,但是t1改变了两个对象的append。如果attr2是共享的(类属性),那么attr2attr1的{​​{1}}值为何不同。是什么引起了这种意外行为?

老问题

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

t1

此代码的输出如下

t2

如您所见,我在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()和{{1} }对象。但是dealer属性是不同的。谁能解释导致这种意外行为的原因?

2 个答案:

答案 0 :(得分:1)

我明白了你的要求。您需要将所有卡与玩家卡区分开。因此,建议您不要将所有内容都命名为卡,

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是一个可变对象,并且仅在定义类时才创建一次,这就是为什么在创建两个实例时它会被共享。因此,要解决此问题,我们可以像上面提到的那样使用构造函数。当我们将列表放入构造函数中时,每当实例化对象时,也会创建新列表。

答案 1 :(得分:1)

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

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

通常,如果您不希望所有实例共享列表或其他可变值作为类变量,通常不是一个好主意。但这并不是禁止的,因为有时您确实确实希望共享行为。