python--格式化打印杨辉三角(format)

时间:2022-09-15 14:02:36

打印目标:

>>> runfile('E:/桌面/代码池/untitled0.py', wdir='E:/桌面/代码池')
num:11
                                1                                 
                             1     1                              
                          1     2     1                           
                       1     3     3     1                        
                    1     4     6     4     1                     
                 1     5     10    10    5     1                  
              1     6     15    20    15    6     1               
           1     7     21    35    35    21    7     1            
        1     8     28    56    70    56    28    8     1         
     1     9     36    84   126   126    84    36    9     1      
  1     10    45   120   210   252   210   120    45    10    1 

代码:

def triangle(num):
    triangle=[[1]]
    for i in range(2,num+1):
        triangle.append([1]*i)
        for j in range(1,i-1):
            triangle[i-1][j]=triangle[i-2][j]+triangle[i-2][j-1]
    return triangle
def printtriangle(triangle,width):
    column=len(triangle[-1])*width
    for sublist in triangle:
        result=[]
        for contents in sublist:
            result.append('{0:^{1}}'.format(str(contents),width))
        print('{0:^{1}}'.format(''.join(result),column))
        
if __name__=='__main__':
    num=int(input('num:'))
    triangle=triangle(num)
    width=len(str(triangle[-1][len(triangle[-1])//2]))+3
    printtriangle(triangle,width)


第一步,获取由杨辉三角各行所构成的表格

实现方法有很多,这里详细介绍一种,其余几种方法会在下一篇文章中介绍。先来看这样一段代码:

  def triangle(num):#num是打印杨辉三角的行数
        triangle=[]
        sublist=[]
        for i in range(1,num+1):     
            sublist.append(1)           
            for j in range(1,i-1):
                sublist[-j-1]=sublist[-j-1]+sublist[-j-2]#从倒数第二个元素开始向前处理,直到正数第二个元素。
            triangle.append(sublist)
        return triangle
除了中间递归看着比较累外,其他地方似乎没什么问题。运行一下看看:

>>> runfile('E:/桌面/代码池/untitled0.py', wdir='E:/桌面/代码池')
num:5
  1     4     6     4     1   
  1     4     6     4     1   
  1     4     6     4     1   
  1     4     6     4     1   
  1     4     6     4     1   

怎么会这样呢?这里隐藏着python中的一个天坑:

python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。

重点是那句“能修改对象的原始值”。由于传入的sublist是可变对象,因此加入triangle的仅仅是sublist的引用。虽然我们已经一步步将sublist加到了triangle里面,但每一步对sublist进行append操作,都将原有的sublist进行了改变。我们本以为的实现方式是这样的:

python--格式化打印杨辉三角(format)

python--格式化打印杨辉三角(format)

但代码实际上在python内部实现的过程是这样的:

python--格式化打印杨辉三角(format)

python--格式化打印杨辉三角(format)

为了更好的理解“传值”与“传引用”,我们看这样一段代码:

triangle=[]
sublist=1
for i in range(1,10):     
    sublist+=1              
    triangle.append(sublist)
print(sublist)


在python内部实现的方式是怎样的呢?

python--格式化打印杨辉三角(format)python--格式化打印杨辉三角(format)

我们可以看到,对于不可变元素,python采取的就是“传值”的方式。

知道了问题所在,该如何去修改呢?我们只需要在sublist加入triangle之前,使sublist指向一个新的列表对象。

 sublist=sublist+[1]   #替代sublist.append(1)   

改动完成,打印一下看看:

>>> runfile('E:/桌面/代码池/untitled1.py', wdir='E:/桌面/代码池')
[[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1], [1, 5, 10, 10, 5, 1], [1, 6, 15, 20, 15, 6, 1], [1, 7, 21, 35, 35, 21, 7, 1], [1, 8, 28, 56, 70, 56, 28, 8, 1]]

嗯,貌似还不错,获得了杨辉三角各行组成的列表,下面的任务就是格式化打印了。全部代码如下先看代码:

def printtriangle(triangle,width):
    column=len(triangle[-1])*width
    for sublist in triangle:
        result=[]
        for contents in sublist:
            result.append('{0:^{1}}'.format(str(contents),width))
        print('{0:^{1}}'.format(''.join(result),column))
        
if __name__=='__main__':
    num=int(input('num:'))
    triangle=triangle(num)
    width=len(str(triangle[-1][len(triangle[-1])//2]))+3
    printtriangle(triangle,width)

重点解释一下这两行:

result.append('{0:^{1}}'.format(str(contents),width)) #控制各行数字间距
        print('{0:^{1}}'.format(''.join(result),column)) #控制缩进
第一行用来控制同行数字的间距,具体而言:str(contents)占据的总宽度为width,不足的 在两边用空格补齐。这样做的结果是每一个加入result的数字两边都有空格。

<pre name="code" class="python" style="font-size: 11.8518514633179px;">x=['1','2']=> x=[' 1 ',' 2 ']#效果类似这样

 

第二行同理:‘’.join()占据总宽度为‘盒子’总宽度column(而column又由行数决定),并用空格在两边补齐空位。

如果不想用短线补齐空位呢?只需要这样修改:

print('{0:-^{1}}'.format(''.join(result),column)) #控制缩进

好了,输入num=10,看看效果:

>>> runfile('E:/桌面/代码池/untitled0.py', wdir='E:/桌面/代码池')
                             1                              
                          1     1                           
                       1     2     1                        
                    1     3     3     1                     
                 1     4     6     4     1                  
              1     5     10    10    5     1               
           1     6     15    20    15    6     1            
        1     7     21    35    35    21    7     1         
     1     8     28    56    70    56    28    8     1      
  1     9     36    84   126   126    84    36    9     1   

到这里基本就大功告成了,感兴趣的朋友还可以看看其它四种实现方法(尤其,后面两种):


def gettriangle(num):#1
    triangle=[]
    sublist=[]
    for i in range(1,num+1):
        sublist=sublist+[1]#思考:为什么不能写成sublist.append(1)
        for j in range(1,i-1):
            sublist[-j-1]=sublist[-j-1]+sublist[-j-2]
        triangle.append(sublist)
    return triangle

</pre><pre name="code" class="python">
</pre><pre name="code" class="python">def gettriangle(num):#2 
    triangle=[[1]]
    sublist=[1]
    for i in range(1,num):
        sublist.append(1)
        sublistcopy=sublist[:]
        for j in range(1,i):
            sublistcopy[j]=sublist[j]+sublist[j-1]
        sublist=sublistcopy[:]    
        triangle.append(sublistcopy)

def gettriangle(num):#3
    triangle=[[1]]
    sublist=[1]
    for i in range(1,num):
        sublist=[1]+[sublist[i]+sublist[i+1] for i in range(len(sublist)-1)]+[1]
        triangle.append(sublist)
    return triangle


def gettriangle(num):#4
    triangle=[[1]]
    sublist=[1]
    for i in range(1,num):
        sublist=[sum(i) for i in zip([0]+sublist,sublist+[0])]
        triangle.append(sublist)
    return triangle