# # from test1.demo import *
#
# # 定义一个长方形类,实现求面积与周长两种方法
# class Rectangle:
# def __init__(self, length, width):
# self.length = length
# self.width = width
#
# def area(self):
# print("You're getting the area...vRectangle")
# return self.length * self.width
#
# def perimeter(self):
# print("You're getting the perimeter...")
# return 2 * (self.length + self.width)
#
#
# # 定义一个正方形类,同样实现求面积与周长两种方法
# # class Square:
# # def __init__(self, length):
# # self.length = length
# #
# # def area(self):
# # print('111')
# # return self.length * self.length
# #
# # def perimeter(self):
# # print('2222')
# # return 4 * self.length
#
# # 1.
# # # Rectangle类不变
# # class Square(Rectangle):
# # def __init__(self, length):
# # self.length = length
# # Rectangle.__init__(self, length, length)
#
# # 2. 使用super() 下面不用改父类名如果父类名改变的话
# # Rectangle类不变
# # class Square(Rectangle):
# # def __init__(self, length):
# # self.length = length
# # super().__init__(length, length)
# #
# #
# #
# # s = Square(5)
# # s.perimeter()
# # s.area()
#
#
# # 2.2 方法的扩充
# # 定义一个立方体类,继承自Square,并实现求表面积和体积的方法
# # class Cube(Square):
# # def surface_area(self):
# # face_area = super().area()
# # return face_area * 6
# #
# # def volumn(self):
# # face_area = super().area()
# # return face_area * self.length
# #
# # c = Cube(3)
# # print(c.surface_area())
# # print(c.volumn())
# # 通过2.1与2.2两个例子,我们大概能体会到super所起作用的方式:
# # super().method()会调用父类的方法。如super().area(),
# # 表示调用父类的.area()方法求面积;super().__init__()表示调用父类的.__init__()方法。
#
# """
# 3、带参数的super
# 在上面的例子中,调用super时均没有向其中传入任何参数,实际上,super是有两个可选参数的。
# 第一个可选参数是一个类(type),第二个可选参数是一个类(type2)或一个实例(object)。
# 特别地,如果第二个参数是一个object,那么必须有isinstance(object, type)==True;
# 如果第二个参数是一个类,那么必须有issubclass(type2, type)==True。
# 上文中关于Square和Rectangle类的代码可以修改如下:
# """
# # super(Square, self).__init__(length, length)
# # super().__init__(length, length) 这两个含义相同
#
# # class Rectangle:
# # def __init__(self, length, width):
# # self.length = length
# # self.width = width
# #
# # def area(self):
# # print("You're getting the area...")
# # return self.length * self.width
# #
# # def perimeter(self):
# # print("You're getting the perimeter...")
# # return 2 * (self.length + self.width)
#
#
# # class Square(Rectangle):
# # def __init__(self, length):
# # super(Square, self).__init__(length, length)
# #
# # print(Square(3).area())
#
# """
# 这里的super接受了两个参数,第一个为子类,第二个是该类的实例。
# 这其实与直接写super().__init__(length, length)的作用是一样的。
# 类似地,可以修改Cube类的代码如下:
# """
#
# # class Cube(Square):
# # def surface_area(self):
# # face_area = super(Square, self).area()
# # return face_area * 6
# #
# # def volumn(self):
# # face_area = super(Square, self).area()
# # return face_area * self.length
# #
# #
# #
# # c = Cube(3)
# # print(c.surface_area())
# # print(c.volumn())
# """
# 在这里,super的第一个参数是Square而不是Cube,这意味着,super会从Square类的上一层(也就是Rectangle)来寻找匹配的.area()方法。也许你已经想到了,这种用于法可以适用于当Square类中也定义了.area()方法而你却想调用Rectangle的.area()方法的情况:
# """
# class Square(Rectangle):
# def __init__(self, length):
# super(Square, self).__init__(length, length)
#
# def area(self):
# print("You're getting Square area...")
# return 0
#
# class Cube(Square):
# def surface_area(self):
# face_area = super().area()
# return face_area * 6
#
# def volumn(self):
# face_area = super(Square, self).area()
# print(face_area,self.length)
# return face_area * self.length
#
# c = Cube(9)
# print(c.surface_area())
# print(c.volumn())
# # You're getting Square area...
# # 0
# # You're getting the area...
# # 729
#
# print(Rectangle.__mro__)
# print(Cube.__mro__)
#
## 4.2 super . MRO 与多继承
# class Rectangle:
# def __init__(self, length, width):
# self.length = length
# self.width = width
#
# def area(self):
# print("You're getting the area...")
# return self.length * self.width
#
# def perimeter(self):
# print("You're getting the perimeter...")
# return 2 * (self.length + self.width)
#
# class Square(Rectangle):
# def __init__(self, length):
# super(Square, self).__init__(length, length)
#
# class Triangle:
# def __init__(self, base, height):
# # 给定边和对应的高
# self.base = base
# self.height = height
#
# def area(self):
# return 0.5 * self.base * self.height
#
# class RightPyramid(Triangle, Square):
# def __init__(self, base, slant_height):
# # 给定底面边长和各侧面的斜高
# self.base = base
# self.slant_height = slant_height
#
# def area(self):
# base_area = super().area()
# perimeter = super().perimeter()
# return 0.5 * perimeter * self.slant_height + base_area
#
# # pyramid = RightPyramid(2,4)
# # print(pyramid.area())
#
# '''
# Traceback (most recent call last):
# File "D:/ytspider/test1/demo02.py", line 192, in <module>
# print(pyramid.area())
# File "D:/ytspider/test1/demo02.py", line 187, in area
# base_area = super().area()
# File "D:/ytspider/test1/demo02.py", line 178, in area
# return 0.5 * self.base * self.height
# AttributeError: 'RightPyramid' object has no attribute 'height'
# '''
#
# """
# 这个错误的意思是,在调用RightPyramid的某个父类的.area()时触发了属性不匹配的错误。
# 仔细观察上面的代码,我们虽然试图通过super().area()来调用父类的.area(),
# 但RightPyramid的两个父类Triangle和Rectangle均实现了.area()方法。从需求出发,
# 我们希望调用的是Rectangle的.area()方法,而实际上是这样吗?
# 可以查看RightPyramid的MRO来帮助判断:
# """
# # print(RightPyramid.__mro__)
# # (<class '__main__.RightPyramid'>, <class '__main__.Triangle'>, <class '__main__.Square'>, <class '__main__.Rectangle'>, <class 'object'>)
# '''
# 可以看出,在调用.area()方法时,解释器首先找到了Triangle的.area()方法,但该方法的执行需要实例对象有base和height属性——而RightPyramid实例是没有height属性的,因此而报错。
# 上述代码的第一个问题是,继承顺序不对。我们希望继承的是Rectangle的.area()方法,而非Triangle的,为此,需要调整一下父类的顺序:
# '''
# # class RightPyramid(Square,Triangle):
# # pass # other codes to be added
# '''
# 此外,在求底面积的时候(即调用Rectangle的.area()方法时),需要实例具有length和width两个属性。所以,我们将RightPyramid类改写如下:
# '''
#
#
# class RightPyramid(Square, Triangle):
# def __init__(self, base, slant_height):
# # 给定底面边长和各侧面的斜高
# self.base = base
# self.slant_height = slant_height
# super().__init__(base) # 调用Square的__init__方法,从而使RightPyramid的实例也具有length和width两个属性
#
#
# def area(self):
# base_area = super().area()
# print(base_area)
# perimeter = super().perimeter()
# print(perimeter)
# return 0.5 * perimeter * self.slant_height + base_area
#
# pyramid = RightPyramid(2,4)
# print(pyramid.area())
# '''
# 再次执行验证代码,你会发现它可以输出正确的结果。
# 回顾一下上述过程可以发现,我们在两个不同的类中实现了名称相同的方法(.area()),这导致了子类在继承时会选错。
# 因此,一个良好的编程习惯是,在不同的类中使用不同的方法签名(例如可以把Triangle中的.area()改成.tri_area()),这样无论是从代码可读性,还是维护成本上考虑,都是更优的选择。
# '''
# class Triangle:
# def __init__(self, base, height):
# # 给定边和对应的高
# self.base = base
# self.height = height
#
# def tri_area(self):
# return 0.5 * self.base * self.height
#
# class RightPyramid(Square,Triangle):
# def __init__(self, base, slant_height):
# # 给定底面边长和各侧面的斜高
# self.base = base
# self.slant_height = slant_height
# super().__init__(self.base)
#
# def area(self):
# base_area = super().area()
# perimeter = super().perimeter()
# return 0.5 * perimeter * self.slant_height + base_area
#
# def area_2(self):
# base_area = super().area()
# triangle_area = super().tri_area()
# return triangle_area * 4 + base_area
# pyramid = RightPyramid(2,4)
# print(pyramid.area_2())
'''
这里再调用.area()便不会产生歧义了。
此外,在RightPyramid类中,又实现了.area_2()用于求表面积,这种方法是先求每个侧面的面积,再加上底面积。
但如果你运行pyramid.area_2()时,会触发一个AttributeError,这是因为在调用Triangle的.tri_area()方法时,pyramid的height并没有值。也就是说,通过super().method()调用父类的方法时,如果实例缺乏必要的属性值,则会导致调用失败。
为了解决这个问题,我们要做一些稍微复杂的修改:
对于每一个需要调用父类方法的子类,均需要在其.__init__()方法中调用父类的.__init__()方法,即添加super().__init__()代码;
在super().__init__()代码中传入关键字参数的字典。
完整的示例代码如下:
'''
class Rectangle:
def __init__(self, length, width, **kwargs):
self.length = length
self.width = width
super().__init__(**kwargs)
def area(self):
print("You're getting the area...")
return self.length * self.width
def perimeter(self):
print("You're getting the perimeter...")
return 2 * (self.length + self.width)
class Square(Rectangle):
def __init__(self, length, **kwargs):
super().__init__(length=length, width=length, **kwargs)
class Cube(Square):
def surface_area(self):
face_area = super().area()
return face_area * 6
def volume(self):
face_area = super().area()
return face_area * self.length
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 RightPyramid(Square, Triangle):
def __init__(self, base, slant_height, **kwargs):
self.base = base
self.slant_height = slant_height
kwargs["height"] = slant_height
kwargs["length"] = base
super().__init__(base=base, **kwargs)
def area(self):
base_area = super().area()
perimeter = super().perimeter()
return 0.5 * perimeter * self.slant_height + base_area
def area_2(self):
base_area = super().area()
triangle_area = super().tri_area()
return triangle_area * 4 + base_area
pyramid = RightPyramid(2,4)
print(pyramid.area_2())
引用地址:
Django的ListView超详细用法(含分页paginate功能)_Young文人的博客-CSDN博客_django listview