在继承中带有/不带有下划线的python变量

时间:2019-06-12 03:37:45

标签: python python-decorators

我对self._value继承后的来源感到困惑。父类仅具有self.value,而没有self._value

from abc import ABCMeta, abstractmethod

class Card(metaclass=ABCMeta):

    def __init__(self, value):
        self.value = value

    @property
    @abstractmethod
    def value(self):
        pass

    @value.setter
    @abstractmethod
    def value(self, other):
        pass


class BlackJackCard(Card):

    def __init__(self, value):
        super().__init__(value)

    def is_ace(self):
        return self._value == 1

    def is_face_card(self):
        """Jack = 11, Queen = 12, King = 13"""
        return 10 < self._value <= 13

    @property
    def value(self):
        if self.is_ace() == 1:
            return 1
        elif self.is_face_card():
            return 10
        else:
            return self._value

    @value.setter
    def value(self, new_value):
        if 1 <= new_value <= 13:
            self._value = new_value
        else:
            raise ValueError('Invalid card value: {}'.format(new_value)) 

但是,我运行了这段代码,发现可以通过构造函数分配的Foo实例化BlackJackCard类。 self._value == self.value == Foo。

但是父类 init 方法没有self._value ...

魔术在哪里?

1 个答案:

答案 0 :(得分:1)

def value(self, new_value)方法上使用 @ value.setter 装饰器时,是在告诉Python使用该方法作为setter,这意味着只要{{1} }被调用。

因此self.value = something构造函数调用BlackJackCard构造函数,该构造函数表示Card调用self.value = x,后者依次执行value(self, x)。因此,您的卡最终会将self._value = xvalue属性都设置为_value


带有@装饰的示例:

x

输出:

class A(metaclass=ABCMeta):
    def __init__(self, value):
        print('constructing A')
        self.x = value

class B(A):
    def __init__(self, value):
        print('constructing B')
        super().__init__(value)

    @property
    def x(self):
        print('getting x')
        return self._internalX

    @x.setter
    def x(self, new_x):
        print('setting x')
        self._internalX = new_x

# test B
b = B('X')
print('b.x = "{}"'.format(b.x))
print('b._internalX = "{}"'.format(b._internalX))

没有@装饰器的反例:

constructing B
constructing A
setting x
getting x
b.x = "X"
b._internalX = "X"

输出:

class A(metaclass=ABCMeta):
    def __init__(self, value):
        print('constructing A')
        self.x = value

class C(A):
    def __init__(self, value):
        print('constructing C')
        super().__init__(value)

    def x(self):
        print('not getting x')
        return self._internalX

    def x(self, new_x):
        print('not setting x')
        self._internalX = new_x

# test C
c = C('X')
print('c.x = "{}"'.format(c.x))
try:
    print('c._internalX = "{}"'.format(c._internalX))
except AttributeError as e:
    print('oops:',e)