【学习】Python基础学习

一、菜鸟教程


python3菜鸟.png

二、实际应用

anaconda——jupiter.png

三、其他总结

1、class、type、isinstance和self的用法
class是类,是抽象的概念,同时拥有很多属性。

>>> class A:
...     pass

>>> class B(A):
...     pass

“>>> class B(A):”中认为,B的属性(子类)全部继承自A(父类)。
isinstance 和 type 的区别在于:
type()不会认为子类是一种父类类型。
isinstance()会认为子类是一种父类类型。

>>> isinstance(A(), A)
True
>>> type(A()) == A 
True
>>> isinstance(B(), A)
True
>>> type(B()) == A
False

2、yield生成器的用法
https://blog.csdn.net/mieleizhi0522/article/details/82142856
可以简单把yield理解为return,每次yield会返回一个值,此时函数终止,下一次运行时会从这个位置继续进行循环,直到再次遇到yield并返回新值。

3、Python中self的使用
https://www.cnblogs.com/jessonluo/p/4717140.html
A:

class MyClass:
    """一个简单的类实例"""
    i = 12345
    def f(self):
        return 'hello world'
 
# 实例化类
x = MyClass()
 
# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f())

首先,f方法因为有return,所以必须有输入(不然就是f=‘hello world’),这里因为是return固定值回去,所以输入不限,这里用self代替,也可以用其他字符代替。
其次,x = MyClass()已经是实例化例子,默认所有的方法都有输入为其本身(这里认为是self,如果是其他字符,就认为是其他字符)。所以如果输出语句是:

print("MyClass 类的方法 f 输出为:", x.f(self))  

显示报错:

TypeError: f() takes 1 positional argument but 2 were given

说明是实例化本身有一个默认输入参数self,然后 x.f(self)又多加了一个参数。

B:
有具体参数输入的,可以选择类化,或者利用构造方法创建有参数的实例化类,下面是类化

class MyClass:
    """一个简单的类实例"""
    i = 12345
    def f(m):
        return m+1
 
# 类化(非实例化)
x = MyClass

# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f(2))

下面是有参数输入的实例化类:需要利用构造方法init(self,参数)来进行实例化类的输入定义。

class MyClass:
    """一个简单的类实例"""
    i = 12345
    #定义f基本属性为数值,实际上f的值为多少并不影响最后返回的self.f的值
    f = 0
    #定义构造函数,有构造参数才能进行参数输入
    def __init__(self,m):
        self.f=m+1
 
# 实例化
x = MyClass(2)

# 访问类的属性和方法
print("MyClass 类的属性 i 为:", x.i)
print("MyClass 类的方法 f 输出为:", x.f)

4、菜鸟教程实例总结
(1)、input默认输入的类型位string,对其数值运算须进行转化:

num1 = input('输入第一个数字:')
num2 = input('输入第二个数字:')
 
# 求和
sum = float(num1) + float(num2)
 
# 显示计算结果
print('数字 {0} 和 {1} 相加结果为: {2}'.format(num1, num2, sum))

(2)、输出函数传递有两种方法:
A、利用序列/关键字参数传递:

print('数字 相加结果为: {0}'.format(sum))

B、或利用%传递(如果要对输出参数进行格式美化,只有采用%传递的方式):

print('数字 相加结果为:%.1f'%(sum))

利用%传递可以实现输出美化,常用的有格式化符号:


image.png

image.png

以及辅助指令(m可缺省),放在格式化符号之间,如上式中的'%.1f':


image.png

(3)构造递归函数
以下代码使用递归的方式来生成斐波那契数列:

def recur_fibo(n):
   """递归函数
   输出斐波那契数列"""
   if n <= 1:
       return n
   else:
       return(recur_fibo(n-1) + recur_fibo(n-2))
 
 
# 获取用户输入

while True:
    nterms = int(input("您要输出几项? "))
 # 检查输入的数字是否正确
    if nterms >0:
        break
    else:
        print("输入正数")

print("斐波那契数列:")
for i in range(nterms):
    print(recur_fibo(i))

(4)使用join连结列表中的字符串,使用split分割列表中的字符串
join连接:

a=['my','name','is','wuxiao']
" ".join(a)

显示:

'my name is wuxiao'

split分割:

b=" ".join(a)
b.split(" ")

显示

['my', 'name', 'is', 'wuxiao']

(5)python中in的使用
列表和元祖都可以直接用in来确认字符/数字等是否存在其中,在字典中,in用来确认key值,而无法用于确认value值:

letters = ['A','B','C','D','E','F','G']
if 'A' in letters:
    print('A'+' exists')
if 'h' not in letters:
    print('h'+' not exists')

(6)python中的赋值和复制

a=[1,2,3]
b=a
c=a[:]

print(a is b)
print(a is c)

结果显示:

True
False

(7)常用的正则式匹配
()和[]的区别:()是把括号里的元素当整体对待,[]通常是对里面进行限定,如[0-9],只能匹配一个0 ~ 9范围的数,如果是(0 ~ 9)会认为这是由三个字符构成的字符串;
^ 在方括号外(或不含方括号)使用,表示文本开头,在方括号内使用,表示不接受该类合集,如[^\s]表示,不接受除了空格、制表符等等,也就是只接受数字、字母、标点等。
$ 文本结尾

  • 零或多次 + 一或多次 ?匹配零或一次
    . 匹配除换行符 \n 之外的任何单字符。要匹配 . ,使用 .
    \ 匹配特殊字符的标记,序列 '\' 匹配 "",而 '(' 则匹配 "("
    | 指明两项之间的一个选择。要匹配 |,请使用 |。
    [] 中括号表达式
    {}限定符,{n,m}匹配n~m次
    \w 匹配字母、数字、下划线。等价于'[A-Za-z0-9_]'。
    \d 匹配一个数字字符。等价于 [0-9]。
    \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
    https://c.runoob.com/front-end/854](https://c.runoob.com/front-end/854列出了各种典型数据的正则式匹配方式,比如:
    InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]*)?$

(8) 'str' object is not callable报错
前面已经定义了str为变量,再用a=str(b)的字符串转换函数则会报错。del str即可。
https://www.cnblogs.com/gstblog/p/9233566.html

(9)排序法对比(算法的核心要么是比较法,要么是“分治+递归”)
A:冒泡排序法:1号与2号比较,序号最大的沉到最下面,2号与3号对比,序号最大的嗔道最下面。。。。。。第一轮完毕,序号最大的沉到最下面,然后进行下一轮对1~n-1号进行排序,把其中序号最大的沉到n-1号。直至完毕。比较次数为m次。

B:插入排序:从0号开始拍,然后1号,然后2号,前面n号已经排好,排低n+1号时,与前面的n号进行对比,并找到自己的位置,此时n+1号也排好。平均比较次数为m/2次。

C:快速排序:分而治之+递归函数的理论。分治是基本理论,设定一个基准值,然后将大于基准值的放在右边,小于基准值的放在左边。递归是函数嵌套,让所有组最后不能再分为止:(快速排序只有基本理论,实际上有很多写法)

array = [4,6,2,5,1]


def quickSort(arr):
    lenth=len(arr)
    if lenth>=2:     
        #不在分治排序的终止条件就是只剩下一个数了。
        #如果还剩两个数,那么还需要进行判断,
        #把第二个数设为基准值,如果第一个数比第二个数小,那么放在左边,比第二个数大,放在右边。
        left=[]
        right=[]
        mid=arr[lenth//2]
        for i in range(lenth):
            if i!=(lenth//2):   #对mid值不进行判定
                if arr[i]<=mid:
                    left.append(arr[i])
                if arr[i]>mid:
                    right.append(arr[i])
        arrn=quickSort(left)+[mid]+quickSort(right)
        return arrn
    else:
        return arr

print(quickSort(array))

D:并归排序:将两个顺序序列合并成一个顺序序列的方法。由最小的2合4,4合8开始直至完毕。数字排序的思想除了比较法的思想(比如冒泡法、插入排序法),剩下一类基本上都是“分治+递归”的思想。并归排序把大列表分为两个小列表的思想是分治,但是小列表要层层细分,最后实现小列表中是按顺序排列的,则要涉及到递归的思想(由2,递归到4,4递归到8)。不同的是,并归排序是反递归:要实现对4的排序←对两个2进行排序←但是首先要对两个2进行内部排序。针对反递归的,可以先根据只有2个数字的情况进行考虑,由少数变多数。当数字很多,只需要再内部再循环一次(比如下面代码中的一直细分),就可以实现内部不断循环,最终由少数返回多数。

array = [6,202,100,301,38,8,1]


def merge(arr):
    lenth=len(arr)
    if lenth==1:
        return arr
    else:
        arrnew1=arr[0:(lenth//2)]
        if len(arrnew1)!=1:   #需要一直细分,直到分到只有1个数,不然再内部进行排序为止(也就是反递归的思想)
            arrnew1=merge(arrnew1)  #再次进行内部细分和排序
        arrnew2=arr[lenth//2:]
        if len(arrnew2)!=1:   #需要一直细分,知道分到只有1个数,不然再内部进行排序为止
            arrnew2=merge(arrnew2)  #再次进行内部细分和排序
 
        arrnew=arr
        m=0
        n=0      #设指针
        i=0
        while m <(len(arrnew1)) or n <(len(arrnew2)) :   #判定条件为两个list的指针都超出自身lenth时停止
            if  m <(len(arrnew1)) and n <len(arrnew2):#如果指针还在列表内
                if arrnew1[m]<=arrnew2[n]:
                    arrnew[i]=arrnew1[m]
                    i+=1
                    m+=1
                else:
                    arrnew[i]=arrnew2[n]
                    i+=1
                    n+=1
            elif  m >=(len(arrnew1)) :      #如果有一个指针超出了列表,则把没超出列表的指针对应的数加上就行了
                arrnew[i]=arrnew2[n]
                i+=1
                n+=1            
            elif  n >=(len(arrnew2)) :
                arrnew[i]=arrnew1[m]
                i+=1
                m+=1
        return arrnew

print(merge(array))

E:堆排序:对堆排序的逻辑理解容易发生偏差,尤其容易理解为第一种方案(当然是因为第一种方案更适合用递归函数,有点像冒泡法或者是选择排序),但实际上并不是堆排序


image.png

第一种方案(写得太长了,实际上包括两个部分,一个是堆的对应方式,另一个是最小堆中数据的置换,其实用两个def函数进行内嵌,会大大节约写作工作量):

array = [4,2,3,1,5,11,2,7,2,4,0,2]

def heapSort(arr):
    #首先要确定堆的序列方式,有两个关键因素,层级level确定可以分为几层,其次两个子序列2**(i-1)-1、2**i对应父序列编号是[(第一个子序列+1)/2-1](因为序列是以0开头,如果是以1开头就方便多了)
    lenth=len(arr)
    if lenth==1:
        return arr
    else:
        import math
        level=math.ceil(math.log(lenth+1,2))    #确定有多少层级 (要用等比数列公式来算,如果有n层,那么最多有2**n-1个数)
        for i in range(level,0,-1):    #从最后一个层级的第一个数开始进行倒推(有1,...,level)个层级,所以range需要到0
           if i==level:
             num=lenth-(2**(i-1)-1) #确定i层级(最多)有多少个数,前(n-1)层有2**(n-1)-1个数
             m=0
             if num%2==0:
                 while m <num:
                  #第i个层级的第一个数和第二个数是2**(i-1)-1、2**(i-1),对应父序列2**(i-2)-1,找其最小值,并对换
                     son1=2**(i-1)-1+m
                     son2=2**(i-1)+m
                     father=int((son2/2)-1)
                     if arr[son2]>=arr[son1] and arr[father]>arr[son1]: 
                         arr[father],arr[son1]=arr[son1],arr[father]    #对换
                     if arr[son1]>=arr[son2] and arr[father]>arr[son2]: 
                         arr[father],arr[son2]=arr[son2],arr[father]    #对换
                     m+=2
             elif num%2!=0:     #出现不能配对的情况
                 while m <num-1:
                  #第i个层级的第一个数和第二个数是2**(i-1)-1、2**(i-1),对应父序列2**(i-2)-1,找其最小值,并对换
                     son1=2**(i-1)-1+m
                     son2=2**(i-1)+m
                     father=int((son2/2)-1)
                     if arr[son2]>=arr[son1] and arr[father]>arr[son1]: 
                         arr[father],arr[son1]=arr[son1],arr[father]    #对换
                     if arr[son1]>=arr[son2] and arr[father]>arr[son2]: 
                         arr[father],arr[son2]=arr[son2],arr[father]    #对换   
                     m+=2
                 while m==(num+1):    #遇到单个落单的情况
                     son1=2**(i-1)-1+m
                     father=int(son2/2)
                     if arr[father]>arr[son1]:
                         arr[father],arr[son1]=arr[son1],arr[father]    #对换
                     break  #只执行一次,跳出
      
           else:
             num=2**(i-1) #确定i层级(最多)有多少个数
             m=0   #m用于在i层级进行横向循环,每次增加两个数
             while m <num:
                  #第i个层级的第一个数和第二个数是2**(i-1)-1、2**(i-1),对应父序列2**(i-2)-1,找其最小值,并对换
                     son1=2**(i-1)-1+m
                     son2=2**(i-1)+m
                     father=int((son2/2)-1)
                     if arr[son2]>=arr[son1] and arr[father]>arr[son1]: 
                         arr[father],arr[son1]=arr[son1],arr[father]    #对换
                     if arr[son1]>=arr[son2] and arr[father]>arr[son2]: 
                         arr[father],arr[son2]=arr[son2],arr[father]    #对换   
                     m+=2
        arr0=arr[0]   #循环一次后,进行堆的更新和迭代   
        arr[0]=arr[lenth-1]  
        del arr[lenth-1]     
        arrnew=[arr0]+heapSort(arr)
        return arrnew

第二种方案(堆排序法,先从底层开始检验堆→当上层堆发生改变时,要对改变堆的下属堆进行重新校验,保证下层始终是对的,直至校验至顶层→更新堆→对新堆不用再从下层进行校验,而是从顶层开始校验,当顶层堆发生改变,对改变堆的下属堆进行重新校验,直至完毕→更新堆。。。)
用两个内嵌函数节约工作量):

array = [0,1,-2,4,2,3]

def heapSort(arr,m=1):
    lenth=len(arr)
    if lenth==1:
        return arr
    else:
      import math
      level=math.ceil(math.log(lenth+1,2))    #确定有多少层级 (要用等比数列公式来算,如果有n层,那么最多有2**n-1个数)
      if m==1:    #第一次排序要对底层进行排序,之后的排序,只用对顶层进行校验就好了
        for i in range(level-1,0,-1):    #以父节点的层级开始倒推,父节点对少也在level-1的层级
            for father in range((2**(i-1)-1),2**i-1):   #第一次排序需要对所有节点排序,所以需要循环全部父节点
                heapSSort(arr,i,level,father)
      if m!=1:
         heapSSort(arr,1,level,0)    #从第一层级开始顺推,i=1,定点排序为0
      arr0=arr[0]   #循环一次后,进行堆的更新和迭代   
      arr[0]=arr[lenth-1]  
      del arr[lenth-1]
      m+=1 
      arrnew=[arr0]+heapSort(arr,m)
      return arrnew     
                
def heapSSort(arr,i,level,father):
    if i==level-1:   #如果父节点推到最底层了,则只用排序就行了
        lenth=len(arr)
        son1=(father+1)*2-1
        son2=(father+1)*2
        if lenth-1<son1:
             pass   #父节点下面没有子节点,直接返回
        elif lenth-1==son1:   #只有一个子节点
             if arr[father]>arr[son1]:
                 arr[father],arr[son1]=arr[son1],arr[father]
        elif lenth-1>=son2:   #有两个子节点
             if arr[son2]>=arr[son1] and arr[father]>arr[son1]: 
                 arr[father],arr[son1]=arr[son1],arr[father]    #对换
             if arr[son1]>=arr[son2] and arr[father]>arr[son2]: 
                 arr[father],arr[son2]=arr[son2],arr[father]    #对换
    else:    # 不是底层父节点的话,是不用进行lenth判断的
        son1=(father+1)*2-1
        son2=(father+1)*2
        if arr[son2]>=arr[son1] and arr[father]>arr[son1]: 
            arr[father],arr[son1]=arr[son1],arr[father]    #对换
            heapSSort(arr,i+1,level,son1)  #节点对换后,需要对更换后的子节点的孙节点进行校验
        if arr[son1]>=arr[son2] and arr[father]>arr[son2]: 
            arr[father],arr[son2]=arr[son2],arr[father]    #对换        
            heapSSort(arr,i+1,level,son2)  #节点对换后,需要对更换后的子节点的孙节点进行校验
    return arr


print(heapSort(array))

发现自己写的复杂报了,去找了下标准答案:

def heapify(arr, n, i): 
    largest = i  
    l = 2 * i + 1     # left = 2*i + 1 
    r = 2 * i + 2     # right = 2*i + 2 
  
    if l < n and arr[i] < arr[l]: 
        largest = l 
  
    if r < n and arr[largest] < arr[r]: 
        largest = r 
  
    if largest != i: 
        arr[i],arr[largest] = arr[largest],arr[i]  # 交换
  
        heapify(arr, n, largest) 
  
def heapSort(arr): 
    n = len(arr) 
  
    # Build a maxheap. 
    for i in range(n, -1, -1): 
        heapify(arr, n, i) 
  
    # 一个个交换元素
    for i in range(n-1, 0, -1): 
        arr[i], arr[0] = arr[0], arr[i]   # 交换
        heapify(arr, i, 0) 
  
arr = [ 12, 11, 13, 5, 6, 7] 
heapSort(arr)
print(arr)

标准答案简化在:1、去掉了层级和最底层单双数目的确定,直接用“if l < n and arr[i] < arr[l]: ”语句判断,如果son1的序列号直接超出长度,直接跳出;2、用large来记录更大(我的函数用的是更小)数的序列号,再更换数据上更方便3、不用那么多return。。

F:计数排序:核心思想在于将输入的数据值转化为键存储在额外开辟的数组空间中。额外建立两个数组,一个数组用来记录原始数据中出现了那些数据(这个数组默认就是排序好的,所以不用排序)。→牺牲空间换区时间

G:希尔排序:插入排序的升级版,第一次以lenth/2为间隔,对所有数据进行分组调序(一共lenth/2组)→第二次以lenth/4为间隔,对所有数据分组判断,当需要调序时,需要以lenth/4为间隔往前传递直到不再调序位置(因为前方序列已经是对的,所以到某一处不用再调序,也就不用往前推了)→第三次以lenth/8为间隔。。。→最后以1位间隔依次分组判断,以及往前传递。最后排序完成。

H:拓扑排序:是一种图排序方法,每个数据代表的是一种活动,即便是数字,也不是代表的数值大小比较。所有的数据可以构造出一个AOV网(即彼此相关联的拓扑结构),由AOV网确定出拓扑序列(而且不是唯一),但是能保证具有某种实际意义:如果按照拓扑序列中的顶点次序,在开始每一项活动时,能够保证它的所有前驱活动都已完成,从而使整个工程顺序进行,不会出现冲突的情况。

推荐阅读更多精彩内容