我刚刚开始在python3中学习OOP,今天我们就开始了这个小课程。
class Square:
def __init__(self, side):
self.side = side
def show_perimeter(self):
print(self.side * 4)
test_square = Square(10)
test_square.show_perimeter()
>> 40
现在我正在考虑是否可以在创建对象时获取周长的值,例如......
class Square:
def __init__(self, side):
self.side = side
self.permiter = get_perimeter(self)
def get_perimeter(self):
return self.side * 4
test_square = Square(10)
print(test_square.perimeter)
这是你能做的吗? 如果是这样,这是一个好习惯吗?
如果没有,那么通过使用侧面来获得周边的最佳方法是什么?
答案 0 :(得分:6)
__init__
方法没有什么特别之处,除了它作为构造对象的一部分自动调用(__new__
创建对象,__init__
初始化它)。因此,您可以在其中做任何您需要做的事情。但是,您需要确保不会无意中执行会对部分初始化对象执行操作的操作。使用下面的@property
可以解决大部分边缘情况。
唯一的区别是,在大多数情况下调用self.method()
而不是method(self)
是更好的形式。
class Square:
def __init__(self, side):
self.side = side
self.permiter = self.get_perimeter()
def get_perimeter(self):
return self.side * 4
test_square = Square(10)
print(test_square.perimeter)
但是,我想指出在这种情况下财产可能更好:
class Square():
def __init__(self, side):
self.side = side;
@property
def perimeter(self):
return self.side * 4
x = Square(10)
print(x.perimeter)
>>> 40
在这种情况下,@property
装饰器将perimeter
方法转换为可以被访问的属性,就像它是另一个属性一样,但它是在被要求时计算的。
答案 1 :(得分:3)
这是允许的,但它也比人们通常意识到的要危险得多。
说你有以下课程:
class Thing:
def __init__(self):
self._cached_size = self.compute_size()
def compute_size(self):
return 1000
这似乎可以自行运行,但是如果你尝试将其子类化:
class SubThing(Thing):
def __init__(self, more_stuff):
super().__init__()
self.more_stuff = more_stuff
def compute_size(self):
return super().compute_size() + self.more_stuff
SubThing(5)
Everything goes to pieces,因为Thing.__init__
调用SubThing.compute_size
,SubThing.compute_size
假设self.more_stuff
已准备就绪,但尚未就绪:
Traceback (most recent call last):
File "./prog.py", line 14, in <module>
File "./prog.py", line 9, in __init__
File "./prog.py", line 3, in __init__
File "./prog.py", line 12, in compute_size
AttributeError: 'SubThing' object has no attribute 'more_stuff'
你基本上不应该调用__init__
中你希望被覆盖的方法,因为你的对象处于一个非常不稳定的半构造状态,特别是子类负责的状态部分。
如果你想使用你自己的类的方法版本并忽略覆盖(避免子类状态的问题),你可以直接调用它:
class Thing:
def __init__(self):
self._cached_size = Thing.compute_size(self)
def compute_size(self):
return 1000
有些人可能会建议在调用super().__init__
之前让子类初始化它们的状态,但这会导致一个非常混乱的不同类的混乱,这取决于其他类的特定部分是否准备就绪。这不会减少你遇到的问题。
答案 2 :(得分:1)
您应该使用self
在同一个类中引用该方法。
class Square:
def __init__(self, side):
self.side = side
self.perimeter = self.get_perimeter()
def get_perimeter(self):
return self.side * 4