python 变量 with/without 继承中的下划线
python variables with/without underscore in inheritance
我对继承后 self._value 的来源感到困惑。父class只有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 class。 self._value == self.value == Foo.
但是父 class init 方法没有 self._value...
神奇在哪里?
当您在 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"
Counter-example 没有 @ 装饰器:
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'
我对继承后 self._value 的来源感到困惑。父class只有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 class。 self._value == self.value == Foo.
但是父 class init 方法没有 self._value...
神奇在哪里?
当您在 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"
Counter-example 没有 @ 装饰器:
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'