在 super() 上使用 **kwargs 给我属性错误
Using **kwargs on super() gives me Attribute Error
只是想创建一个简单的玩具示例来计算金字塔的表面积:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
#super().__init__(**kwargs)
def area(self):
return self.length * self.width
def perim(self):
return 2 * (self.length + self.width)
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
return super().area() + 4 * super().tri_area()
p = Pyramid(2,4)
p.surf_area()
但这给了我一个
的错误
AttributeError Traceback (most recent call last)
<ipython-input-154-d97bd6ab2312> in <module>
1 p = Pyramid(2,4)
----> 2 p.surf_area()
<ipython-input-153-457095747484> in surf_area(self)
6
7 def surf_area(self):
----> 8 return super().area() + 4 * super().tri_area()
<ipython-input-151-8b1d4ef9dca9> in tri_area(self)
5 super().__init__(**kwargs)
6 def tri_area(self):
----> 7 return 0.5 * self.base * self.height
AttributeError: 'Pyramid' object has no attribute 'base'
在线资源似乎并没有很好地提供对 **kwargs 的概念性理解(或者它们以对初学者来说过于迷宫的方式编写)。这是否与 **kwargs 作为可迭代对象在进行下一次调用之前需要完全耗尽这一事实有关?
我能理解您为什么会感到困惑。要实现的主要技巧是:绝对底线,kwargs
不是什么神奇的东西。它只是一个保存键值对的字典。如果调用需要比提供的更多的位置参数,它可以查看关键字参数并接受一些值。但是,kwargs 不会调用一些魔法来关联所有作为 self.<some_name_here>
提供的名称。
因此,首先要直观地了解正在发生的事情,当您不理解一段代码时,您应该做的是确保它按照您认为的方式运行。让我们添加几个打印语句,看看发生了什么。
版本 1:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
print(f"in rectangle. length = {self.length}, width = {self.width}")
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length, **kwargs):
print("in square")
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
print("in triangle")
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
print("in pyramid")
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
print(f"area : {super().area()}")
print(f"tri_area : {super().tri_area()}")
return super().area() + 4 * super().tri_area()
p = Pyramid(2,4)
p.surf_area()
输出:
in pyramid
in square
in rectangle. length = 2, width = 2
area : 4
#and then an error, note that it occurs when calling super().tri_area()
#traceback removed for brevity.
AttributeError: 'Pyramid' object has no attribute 'base'
我怀疑这已经打破了您对代码运行方式的一些假设。 请注意三角形的 init 从未被调用。但是让我们去掉工作正常的部分,并添加一个额外的打印语句。我也会冒昧地为第一个参数调用不同的值,这样更容易弹出。
版本 2:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
print(f"in rectangle. length = {self.length}, width = {self.width}")
print(f"kwargs are: {kwargs}")
class Square(Rectangle):
def __init__(self, length, **kwargs):
print("in square")
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
print("in triangle")
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
print("in pyramid")
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
print(f"tri_area : {super().tri_area()}")
return super().tri_area()
p = Pyramid(10000,4)
p.surf_area()
输出:
in pyramid
in square
in rectangle. length = 10000, width = 10000
kwargs are: {'base': 10000, 'height': 4}
#error with traceback
AttributeError: 'Pyramid' object has no attribute 'base'
底线:kwargs 持有一个名为 base 的密钥,但这与 self.base
无关。但是,我的建议是摆脱整个 class 结构,花一些时间玩弄任何基本功能,摆脱多余的东西。
说,演示:
def some_func(a, b, **kwargs):
print(a, b)
print(kwargs)
some_func(1, 2)
some_func(1, 2, c=42)
some_func(a=1, c=42, b=2)
def other_func(a, b, **look_at_me):
print(a, b)
print(look_at_me)
other_func(1, 2)
other_func(1, 2, c=42)
other_func(a=1, c=42, b=2)
这两个块产生相同的输出。这里没有魔法。
输出:
1 2
{}
1 2
{'c': 42}
1 2
{'c': 42}
当您将 classes 添加到混合和继承中时,一次发生的事情太多了。更容易错过发生的事情,因此最好使用较小的代码示例。
只是想创建一个简单的玩具示例来计算金字塔的表面积:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
#super().__init__(**kwargs)
def area(self):
return self.length * self.width
def perim(self):
return 2 * (self.length + self.width)
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
return super().area() + 4 * super().tri_area()
p = Pyramid(2,4)
p.surf_area()
但这给了我一个
的错误AttributeError Traceback (most recent call last)
<ipython-input-154-d97bd6ab2312> in <module>
1 p = Pyramid(2,4)
----> 2 p.surf_area()
<ipython-input-153-457095747484> in surf_area(self)
6
7 def surf_area(self):
----> 8 return super().area() + 4 * super().tri_area()
<ipython-input-151-8b1d4ef9dca9> in tri_area(self)
5 super().__init__(**kwargs)
6 def tri_area(self):
----> 7 return 0.5 * self.base * self.height
AttributeError: 'Pyramid' object has no attribute 'base'
在线资源似乎并没有很好地提供对 **kwargs 的概念性理解(或者它们以对初学者来说过于迷宫的方式编写)。这是否与 **kwargs 作为可迭代对象在进行下一次调用之前需要完全耗尽这一事实有关?
我能理解您为什么会感到困惑。要实现的主要技巧是:绝对底线,kwargs
不是什么神奇的东西。它只是一个保存键值对的字典。如果调用需要比提供的更多的位置参数,它可以查看关键字参数并接受一些值。但是,kwargs 不会调用一些魔法来关联所有作为 self.<some_name_here>
提供的名称。
因此,首先要直观地了解正在发生的事情,当您不理解一段代码时,您应该做的是确保它按照您认为的方式运行。让我们添加几个打印语句,看看发生了什么。
版本 1:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
print(f"in rectangle. length = {self.length}, width = {self.width}")
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length, **kwargs):
print("in square")
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
print("in triangle")
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
print("in pyramid")
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
print(f"area : {super().area()}")
print(f"tri_area : {super().tri_area()}")
return super().area() + 4 * super().tri_area()
p = Pyramid(2,4)
p.surf_area()
输出:
in pyramid
in square
in rectangle. length = 2, width = 2
area : 4
#and then an error, note that it occurs when calling super().tri_area()
#traceback removed for brevity.
AttributeError: 'Pyramid' object has no attribute 'base'
我怀疑这已经打破了您对代码运行方式的一些假设。 请注意三角形的 init 从未被调用。但是让我们去掉工作正常的部分,并添加一个额外的打印语句。我也会冒昧地为第一个参数调用不同的值,这样更容易弹出。
版本 2:
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
print(f"in rectangle. length = {self.length}, width = {self.width}")
print(f"kwargs are: {kwargs}")
class Square(Rectangle):
def __init__(self, length, **kwargs):
print("in square")
super().__init__(length = length, width = length, **kwargs)
class Triangle:
def __init__(self, base, height, **kwargs):
print("in triangle")
self.base = base
self.height = height
super().__init__(**kwargs)
def tri_area(self):
return 0.5 * self.base * self.height
class Pyramid(Square, Triangle):
def __init__(self, base, slant, **kwargs):
print("in pyramid")
kwargs["height"] = slant
kwargs["length"] = base
super().__init__(base = base, **kwargs)
def surf_area(self):
print(f"tri_area : {super().tri_area()}")
return super().tri_area()
p = Pyramid(10000,4)
p.surf_area()
输出:
in pyramid
in square
in rectangle. length = 10000, width = 10000
kwargs are: {'base': 10000, 'height': 4}
#error with traceback
AttributeError: 'Pyramid' object has no attribute 'base'
底线:kwargs 持有一个名为 base 的密钥,但这与 self.base
无关。但是,我的建议是摆脱整个 class 结构,花一些时间玩弄任何基本功能,摆脱多余的东西。
说,演示:
def some_func(a, b, **kwargs):
print(a, b)
print(kwargs)
some_func(1, 2)
some_func(1, 2, c=42)
some_func(a=1, c=42, b=2)
def other_func(a, b, **look_at_me):
print(a, b)
print(look_at_me)
other_func(1, 2)
other_func(1, 2, c=42)
other_func(a=1, c=42, b=2)
这两个块产生相同的输出。这里没有魔法。 输出:
1 2
{}
1 2
{'c': 42}
1 2
{'c': 42}
当您将 classes 添加到混合和继承中时,一次发生的事情太多了。更容易错过发生的事情,因此最好使用较小的代码示例。