【问题标题】:python variables with/without underscore in inheritance继承中带/不带下划线的python变量
【发布时间】:2019-10-26 12:06:38
【问题描述】:

我对继承后 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...

魔法在哪里?

【问题讨论】:

  • 呃……Card.__init__调用BlackJackCard.value(setter)赋值给self._value

标签: python python-decorators


【解决方案1】:

当您在 def value(self, new_value) 方法上使用 @value.setter 装饰器时,您是在告诉 Python 将该方法用作 setter,这意味着在调用 self.value = something 时调用它。

所以BlackJackCard 构造函数调用Card 构造函数,它说self.value = x 调用value(self, x),然后执行self._value = x。因此,您的卡最终将value_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)

输出:

constructing C
constructing A
c.x = "X"
oops: 'C' object has no attribute '_internalX'

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 2011-07-30
    • 1970-01-01
    • 2019-12-04
    • 2014-06-09
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多