Python中 super()方法的作用

# # 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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值