python菱形问题

Python类分为两种,一种叫经典类,一种叫新式类。都支持多继承,但继承顺序不同。

  • 新式类:从object继承来的类。(如:class A(object)),采用广度优先搜索的方式继承(即先水平搜索,再向上搜索)。
  • 经典类:不从object继承来的类。(如:class A()),采用深度优先搜索的方式继承(即先深入继承树的左侧,再返回,再找右侧)。

1、普通继承

子类中调用父类方法并不难,下面是一个简单示例

class A:
    def __init__(self):
        self.attr_a = 1
        print('执行A的初始化函数')


class B(A):
    def __init__(self):
        A.__init__(self)
        self.attr_b = 2

b = B()
print(b.attr_a, b.attr_b)

输出结果:

执行A的初始化函数
1 2

 2. 菱形继承

在子类中直接调用父类的方法虽然可行,但在特定场景下会有问题,比如菱形继承

class A:
    def __init__(self):
        self.attr_a = 1
        print('执行A的初始化函数')


class B(A):
    def __init__(self):
        A.__init__(self)
        self.attr_b = 2
        print('执行B的初始化函数')

class C(A):
    def __init__(self):
        A.__init__(self)
        self.attr_c = 3
        print('执行C的初始化函数')

class D(B, C):
    def __init__(self):
        B.__init__(self)
        C.__init__(self)
        self.attr_d = 4
        print('执行D的初始化函数')


d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)

A是B和C的父类,D同时继承了B和C, 这样就形成了菱形继承,所谓菱形继承,仅仅是因形状上像菱形。程序执行结果

执行A的初始化函数
执行B的初始化函数
执行A的初始化函数
执行C的初始化函数
执行D的初始化函数
1 2 3 4

应该注意到,类A的初始化函数被执行了两次,这是一个非常危险的行为,如果A的初始化函数执行了一些一个进程中只能执行一次的代码,这样的多进程就会导致严重的问题, super的引入就是为了解决这种问题。

class A:
    def __init__(self):
        self.attr_a = 1
        print('执行A的初始化函数')


class B(A):
    def __init__(self):
        super().__init__()
        self.attr_b = 2
        print('执行B的初始化函数')

class C(A):
    def __init__(self):
        super().__init__()
        self.attr_c = 3
        print('执行C的初始化函数')

class D(B, C):
    def __init__(self):
        super().__init__()
        self.attr_d = 4
        print('执行D的初始化函数')


d = D()
print(d.attr_a, d.attr_b, d.attr_c, d.attr_d)

执行结果

执行A的初始化函数
执行C的初始化函数
执行B的初始化函数
执行D的初始化函数
1 2 3 4

在D的初始化函数中,只使用了一行代码super().__init__(), 就将两个父类B和C的初始化函数都执行了, 而且不会重复执行A的初始化函数,这些都是super帮助我们完成的。 

3. MRO

在第2小结的示例中, 执行D的初始化函数,使用了super,会自动执行B,C的初始化函数,那么B与C的初始化函数先执行哪个呢?对于这个问题,在我们定义类时,python会计算出一个方法解析顺序列表,也就是MRO,这个MRO列表就是一个简单的所有基类的线性顺序表, 类的mro()方法可以获得MRO

print(D.mro())

输出结果

[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

按照顺序,先执行B的初始化函数,在执行C的初始化函数,最后执行A的初始化函数。

4. 带参数的super方法使用示例

为了简化代码,前面的示例代码在执行super方法时,都没有使用任何参数,下面提供了有参数的示例

class A:
    def __init__(self):
        self.attr_a = 1

    def add(self, a, b):
        return a + b

class B(A):
    def __init__(self):
        super().__init__()
        self.attr_b = 2

    def add(self, a, b):
        print('执行B的add')
        return a + b + 1


class C(A):
    def __init__(self):
        super().__init__()
        self.attr_c = 3

    def add(self, a, b):
        print('执行C的add')
        return a + b + 2

class D(B, C):
    def __init__(self):
        super().__init__()
        self.attr_d = 4

    def add(self, a, b):
        return super().add(a, b)

d = D()
print(d.add(1, 2))

程序执行结果

执行B的add
4

D的父类B和C都有add方法,在D的add方法时,super().add()会根据mro来决定调用哪个父类的add方法,根据顺序,应该执行B的add方法, 如果你希望执行C的add方法, 那么可以这样来实现add方法

def add(self, a, b):
    return super(B, self).add(a, b)

在mro列表里,B的后面是C, super的第一个函数指定为B, 第二个参数设置为self,就会执行C的add方法。

引文:python面向对象--super() | 酷python

### 方法一:绝对值计算法 通过控制每行的空格数和星号数,可以使用绝对值计算法实现菱形的打印。以下是实现代码: ```python size = 5 # 控制菱形高度(必须为奇数) mid = size // 2 for i in range(size): spaces = abs(mid - i) stars = size - 2 * spaces print(' ' * spaces + '*' * stars) # 打印菱形图案 [^1] ``` ### 方法二:分步绘制法 将菱形分为上半部分和下半部分分别绘制,可以使用分步绘制法实现。以下是实现代码: ```python n = 3 # 控制菱形上半部分层数 for i in range(n): print(' ' * (n - i - 1) + '*' * (2 * i + 1)) # 打印上半部分 [^1] for i in range(n-2, -1, -1): print(' ' * (n - i - 1) + '*' * (2 * i + 1)) # 打印下半部分 ``` ### 方法三:函数封装法 通过定义一个函数来实现菱形的打印,可以更灵活地控制行数。以下是实现代码: ```python def print_diamond(rows): # 打印上半部分 for i in range(1, rows, 2): print(" " * ((rows - i) // 2) + "*" * i) # 上半部分星号排列 [^2] # 打印中间行 print("*" * rows) # 中间行全部为星号 [^2] # 打印下半部分 for i in range(rows - 2, 0, -2): print(" " * ((rows - i) // 2) + "*" * i) # 下半部分星号排列 # 菱形的总行数 total_rows = 7 # 打印菱形 print_diamond(total_rows) ``` ### 方法四:居中对齐法 使用字符串的居中对齐功能,可以简化菱形的打印逻辑。以下是实现代码: ```python if __name__ == '__main__': m = int(input()) # 输入菱形的层数 n = 2 * m - 1 s = '*' # 定义要打印的符号 for i in range(1, 2 * m, 2): print((s * i).center(n)) # 上半部分居中对齐 [^4] for i in reversed(range(1, n-1, 2)): print((s * i).center(n)) # 下半部分居中对齐 ``` ### 方法五:菱形的空心实现 如果需要打印空心菱形,可以通过控制星号的位置实现。以下是实现代码: ```python n = 5 # 控制菱形的大小 for i in range(n): if i == 0 or i == n - 1: print(' ' * (n - i - 1) + '*') # 打印顶部和底部的星号 else: print(' ' * (n - i - 1) + '*' + ' ' * (2 * i - 1) + '*') # 打印中间部分的星号 [^5] for i in range(n - 2, -1, -1): if i == 0 or i == n - 1: print(' ' * (n - i - 1) + '*') # 打印底部和顶部的星号 else: print(' ' * (n - i - 1) + '*' + ' ' * (2 * i - 1) + '*') # 打印中间部分的星号 [^5] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘贤松

一本万利

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值