鍍金池/ 問答/Python  測(cè)試  網(wǎng)絡(luò)安全  HTML/ Python unittest 模塊關(guān)于對(duì)象的類屬性和實(shí)例屬性的異常現(xiàn)象

Python unittest 模塊關(guān)于對(duì)象的類屬性和實(shí)例屬性的異?,F(xiàn)象

在編寫模塊的過程中,我寫到以下類和方法(這里用 A,B 抽象表示):

class A:
    pass


class B:
    prop_list = [None]

    def __init__(self):
        self.a = A()
        self.prop_list[0] = self.a

作用就是類 B 的屬性 aA 的一個(gè)實(shí)例,而 B.prop_list 中包含這個(gè)實(shí)例。

然后寫單元測(cè)試的時(shí)候,寫了如下測(cè)試(簡(jiǎn)化模型):

import unittest

class TestFirst(unittest.TestCase):
    b = B()
    assert b.prop_list[0] is b.a

    def test_func1(self):
        assert self.b.prop_list[0] is self.b.a
        
unittest.main()

作用就是判斷 B 的實(shí)例 b 中的屬性 a 就是它 prop_list 中的 a,測(cè)試通過

但是當(dāng)我添加一個(gè)一模一樣的測(cè)試時(shí)候:

import unittest

class TestFirst(unittest.TestCase):
    b = B()
    assert b.prop_list[0] is b.a

    def test_func1(self):
        # !!! AssertionError
        assert self.b.prop_list[0] is self.b.a


class TestSecond(unittest.TestCase):
    b = B()
    assert b.prop_list[0] is b.a

    def test_func1(self):
        assert self.b.prop_list[0] is self.b.a
        
unittest.main()

卻發(fā)現(xiàn) AssertionError !

我嘗試?yán)?print 函數(shù)把每個(gè)屬性打印出來:

class TestFirst(unittest.TestCase):
    b = B()
    print('test_1:')
    print(b.a)
    print(b.prop_list[0])
    # assert b.prop_list[0] is b.a

    def test_func1(self):
        print('func1:')
        print(self.b.a)
        print(self.b.prop_list[0])
        # assert self.b.prop_list[0] is self.b.a


class TestSecond(unittest.TestCase):
    b = B()
    print('test_2:')
    print(b.a)
    print(b.prop_list[0])
    # assert b.prop_list[0] is b.a

    def test_func2(self):
        print('func2')
        print(self.b.a)
        print(self.b.prop_list[0])
        # assert self.b.prop_list[0] is self.b.a

得到以下結(jié)果:

test_1:
<__main__.A object at 0x000001F07CD7D7F0>
<__main__.A object at 0x000001F07CD7D7F0>
test_2:
<__main__.A object at 0x000001F07CD7D828>
<__main__.A object at 0x000001F07CD7D828>
func1:
<__main__.A object at 0x000001F07CD7D7F0> 
<__main__.A object at 0x000001F07CD7D828>  // 這里居然不是 0x000001F07CD7D7F0
.func2
<__main__.A object at 0x000001F07CD7D828>
<__main__.A object at 0x000001F07CD7D828>
.
----------------------------------------------------------------------
Ran 2 tests in 0.002s
  • 為什么 TestFirst 實(shí)例方法 test_func1self.b.prop_list[0] 和自己的 self.b.a 不是同一個(gè)對(duì)象,而和 TestSecond 實(shí)例方法 test_func2 中的 self.b.prop_list[0] 一樣呢?

另外,如果我把 class Bprop_list 當(dāng)作實(shí)例屬性,在初始化函數(shù) __init__() 中聲明:

class A:
    pass


class B:
    def __init__(self):
        self.a = A()
        self.prop_list= [self.a]

再次運(yùn)行上述測(cè)試時(shí)候,發(fā)現(xiàn)可以通過。

這兩種方式為什么會(huì)有差別,這里面還有其他坑沒有?

回答
編輯回答
拮據(jù)

是這樣的:

這裡從頭到尾的 prop_list 都是同一個(gè)!

所以 TestSecondb 被初始化的時(shí)候, 就將 prop_list[0] 的值設(shè)定為 TestSecondb.a 的值了, 而 test_func1 又在之後被調(diào)用, 此時(shí)prop_list[0] 的值自然跟 TestFirstb.a 的值不同, 而是與 TestSecond 中的 b.a 相同。

補(bǔ)充一下, 為什麼 prop_list 為什麼都是同一個(gè)呢, 因?yàn)樗?B 的類別屬性, 會(huì)自然成為每個(gè) B 實(shí)例的屬性, 而且他從頭到尾沒有在任何 B 的實(shí)例中被重新賦值過(他的第零個(gè)元素 prop_list[0] 倒是有被重新賦值過), 所以他 always 是同一個(gè)人。


我回答過的問題: Python-QA

2018年5月6日 08:05