Python理论基础知识复习

Python简介与基础

Python控制结构

组合数据类型

综述

组合数据类型更能够将多个同类或不同类型组织起来,通过单一的表示使数据更有序、更容易。根据数据之间的关系,组合数据类型可以分为3类:序列类型、集合类型和映射类型。

  • 序列类型是一个元素向量,元素之间的存在先后关系,通过序号访问,元素之间不排他。
  • 集合类型是一个元素类型,元素之间无序,相同元素在集合中唯一存在。
  • 映射类型是键值数据项的组合,每个元素是一个键值对,没有顺序,键唯一存在。

    附:序列类型和映射类型是一类数据类型的总称,不是具体类型。

序列类型

序列类型通用函数

序列类型(元组,字符串,列表都可以使用以下操作)

操作符运算
x (not) in s是否在内,输出正误
s + t连接st,不是按索引求和
s * t (t * s)重复
s[i]索引
s[i:j:k]切片
len(s)求长
min/max(s)求最值(str比ASCII)
sum(s)求和
s.index(x)x第一次出现的索引
s.count(x)x出现总数
sorted(iter, key, reverse)返回新的排序后序列类型
reversed()返回倒序后迭代器,建议再套个list()
enumerate(A[, start=0])返回迭代器,套list()后形成索引与值的元组列表

​a = [1,2,3,4] b=a[::-1]这是切片,切片是得到了一个新的列表,属于浅拷贝,对a修改不影响b,反过来也是。

字符串

字符串是不可变类型,所以字符串方法不改变原字符串,而是生成新副本。

函数和处理方法描述
str(x)返回任意类型对应字符串形式
chr(x)十六进制/十进制Unicode转单字符
ord(x)单字符转Unicode,得到十进制数
hex(x)返回整数x对应16进制数小写形式字符串
oct(x)返回整数x对应8进制数小写形式字符串
bin(x)返回整数x对应2进制数小写形式字符串
str.lower()返回副本,全小写
str.upper()返回副本,全大写
str.split(sep=None)返回列表,str根据sep分隔,默认空格
str.count(s)数数
str.replace(old, new)返回副本,old都被改为new
str.center(width, fillchar)宽度不够就输出全部,居中,fillchar默认空格(可修改为单字符)
str.strip(chars)去掉str两侧chars列出的字符
str.join(iter)将iter(主体,一种组合数据类型)变量的

每一个元素后增加一个str字符串(客体)

a=' '.join(['1','2','3'])  #a = '1 2 3'
a=' '.join([1,2,3])        #出错

数值类型转换

#int(x) 
#str类int/int/float => int
int('12')     #输出12,支持str类int
int(12.34)    #输出12,支持float
int('101',2)  #输出5,进制转换必须str类int
int('12.34')  #出错
int('12g')    #出错
int(12g)      #出错
int(101,2)    #出错
int('101.5',2)#出错

#float(x) 
#int/str类 => float
float(12)
float('12')
float(12.0)
float('12.0') #都输出12.0

#str(x)
#int/float => str类
str(10.01)        #输出'10.01'
str(1010+101)     #输出'1111'
str('1010'+'101') #输出'1010101'

列表

是有序序列,但内部可以更改,列表无长度限制,元素类型可以不同,不需要预先定义长度。

列表创建方法如下:

a=[1010,'1010',[1010,'1010']]
a=list('由字符串生成一个字一个元素')
a=list() #空列表

由于类型可变

就有

ls[i]=k 在原列表修改某个元素

ls[i:j:k]=lt 在原列表一部分改为新列表

ls=[i for i in range(6)]
ls[1:5:2]=['a','b'] #如果个数不对会出错
print(ls) #输出[0, 'a', 2, 'b', 4, 5, 6]

del [i]/[i:j:k] 删除一部分

当然也有len(ls)ls.index(x)ls.count(x)x (not) in ls+/*min/max(x)list(x) 等方法操作

list(x) 将变量x转化为列表类型,可以是字符串、集合也可以是字典(但是形成的是键的列表)

列表的特殊函数与操作

由于列表可变,几乎所有方法不需要ls=ls.fn(x),因为原列表已经被改变。

如果写成l(或者是另外的a变量)=ls.fn(x),只会得到None

直接ls.fn(x)才是对的。

函数和处理方法描述
ls.append(x)在最后加元素
ls.insert(i, x)在第i位置加元素x
ls.clear()清空
ls.pop(i)取出并返回第i位置元素并删除,默认最后一个元素
ls.remove(x)删除第一次出现的元素x,不返回
ls.reverse()元素反转(类比序列方法reversed()
ls.sort(reverse=False, key=None)列表排序(类比序列方法sorted()
str.split(sep=None)返回列表,str根据sep分隔,默认空格
str.count(s)数数
ls.copy()例外,生成新列表,浅拷贝

元组

不可更改的序列类型(但是元组中可变的元素仍然是可以进行修改的,做字典的键的元组不能含可变的列表、字典、集合),元组可以实现的操作都可以由列表完成,如果不需要修改数据可以把列表换成元组类型,python对元组处理效率高。

元组创建方法如下:

a=(1, 2, 3)
a=1, 2, 3
a=(1, )
a=1,
a=tuple()
a=()
#以下错误,括号只能放一个序列类型
a=tuple(1, 2, 3)
#以下正确
a=tuple([1, 2, 3])  #a=[1, 2, 3]
a=tuple({2:3, 4:5})  #a=[2, 4]

当函数返回多个值,多个返回值以元组类型返回,实际上是返回一个数据类型。

def f(x):
    return x, x+1, x+2
print(type(f(1)))  #输出<calss 'tuple'>

集合

集合中的元素不可重复,元素类型只能是不可变数据类型(整数,浮点数,字符串,元组等),不能是列表,字典,集合。

集合可以进行数据去重操作。

集合元素间不能比较和排序。

空集合用set()表示,对比{}表示空字典

操作符运算
S-T差集
S&T交集
`ST`
S^T对称差分
可以使用S-=T进行增强操作,运算的同时更新S集合

集合类型常用的函数或方法

函数或方法描述
S.add(x)把x加到S中(类比列表L.append(x)
S.remove(x)移除x,不存在会产生KeyError异常
S.discard(x)移除x,不存在也不报错(与上对比)
S.clear()移除所有数据但不去除集合本身
S.pop()随即返回并删除这个元素来更新S,如果s为set()会产生异常
其他也有len(S)x (not) in SS.copy()(浅拷贝)等

字典

不可变组合类型、基本数据类型可以作为键,元组在各个元素不可变时可做键,列表、集合和其他字典不可做键。

对字典for i in d遍历时,i是字典的每一个键

字典函数和方法

操作符运算
d.keys()返回所有键
d.values()返回所有值
d.items()返回所有键值对
d.get(a key, default=)键存在返回相应值,

否则返回默认

增加新键值对

d.pop(a key, default=)键存在返回相应值

并删除键值对

否则返回默认

d.popitem()随机取出键值对,以元组返回并删除键值对
d.clear()成为空字典
del d[x]删除以x为键的键值对

注意:keys,values,items方法返回的是特殊的内部数据类型,想更好的使用返回数据最好利用list()转化成列表,键值对以元组类型储存在列表里。

字典与序列类型类似的通用操作

in 判断一个键是否在字典中

len(d)字典键值对数量

min/max(b) 返回最小最大的索引值(前提是字典中各个索引元素可以比较)

字典的索引

print(d[x]) #输出x对应的键
d[x] = 1 #修改字典键值对,也可以增加新键值对

字典创建方法如下:

a={'1':2, '3':4}
a=dict()
a={}
#错误方法
a={(1,2), (3,4)} #创建的是含两个元组的集合
#正确方法可使用dict(),这个括号里只能有一个大类,大类里有小类,每个小类两个元素(长为2)
a=dict(([1,2], [3,4]))
a=dict([((1,2),2), ((3,),4)])

深拷贝与浅拷贝

jjzz1234的博客

python中,变量与变量的值占用不同的内存。变量占用的内存,并非直接存储数值,而存储的是值在内存中的地址。

ls = ['中国','矿业','大学']
ls1 = ls           #ls1 = ls 实际上是ls1指向了ls指向的地址块,两者指向的是同一块地址区域,不是拷贝
print(ls1)         #输出ls = ['中国','矿业','大学']
ls.append('憨憨')   #对ls进行元素操作时,也是对ls1造成影响
print(ls1)         #输出['中国', '矿业', '大学', '憨憨']
ls2 = ls[:]        #利用切片,在内存中新建了一个列表,ls2指向这个新的列表,浅拷贝
print(ls2)         #输出ls = ['中国','矿业','大学', '憨憨']
ls.append('憨包')   #对ls的元素进行任何操作,都不会影响ls2的内容
print(ls2)          #输出ls = ['中国','矿业','大学', '憨憨']

a = 1 b= a这不是拷贝,赋值是多个变量指向同一个内存地址,内存的任一元素改变,所有变量都受影响

​a = [1,2,3,4] b=a[:]这是切片,切片是得到了一个新的列表,属于浅拷贝

浅拷贝x.copy()

对只有一层元素关系的列表进行测试:

ls = ['python','c','cpp']
ls1 = ls.copy()
print(id(ls),id(ls1))    #输出  2551633171528 2551633985416,可见二者指向的内存地址不同
ls.append('php')
ls1.append('java')
print(ls)            #输出 ['python', 'c', 'cpp', 'php'],对ls的append操作没有影响ls1
print(ls1)                      #输出 ['python', 'c', 'cpp', 'java'],对ls1的append操作没有影响ls

从以上结果可得:在copy完之后,新的列表指向新的内存地址,分别对列表的最后一位进行appen操作,结果互不影响。

对具有二层的元素的列表进行测试:

##对ls的第二个元素进行append操作
ls = ['德玛',['费欧娜','戴安娜'],'赵信']
ls1 = ls.copy()             
print(ls1)                                  #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
ls[1].append('莫甘娜')       #copy完成后对ls的第二个元素进行append操作
print(ls1)           #输出'德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信'],ls1发生了改变
print(id(ls[1]),id(ls1[1]))  #查看两者的ID,2202073060424 2202073060424

##对ls1的第二个元素进行操作
ls = ['德玛',['费欧娜','戴安娜'],'赵信']
ls1 = ls.copy()
print(ls)                           #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
ls1[1].append('莫甘娜')    #copy完成后对ls1的第二个元素进行append操作
print(ls)                       #输出'德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信'],ls发生了改变
print(id(ls[1]),id(ls1[1]))  #输出 2303581443144 2303581443144

从上边输出的结果来看,copy完成之后,分别对ls和ls1的中间元素进行append操作,对方的元素也会发生相应的改变。

结论:浅拷⻉, 只会拷⻉第⼀层内容,只拷贝第二层关系的内存地址,而第⼆层的内容不会拷贝,所以被称为浅拷贝。

深拷贝x.deepcopy()

深拷贝使用之前一定要先加载copy模块

import copy
new_ls = copy.deepcopy(ls)

实例:

#对ls进行二层操作
import copy
ls = ['德玛',['费欧娜','戴安娜'],'赵信']
ls1 = copy.deepcopy(ls)
ls[1].append('莫甘娜')
print(ls)   #输出['德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信']
print(ls1)  #输出['德玛', ['费欧娜', '戴安娜'], '赵信']

#对ls1进行二层操作
import copy
ls = ['德玛',['费欧娜','戴安娜'],'赵信']
ls1 = copy.deepcopy(ls)
ls1[1].append('莫甘娜')
print(ls)  #输出['德玛', ['费欧娜', '戴安娜'], '赵信']
print(ls1)  #输出['德玛', ['费欧娜', '戴安娜', '莫甘娜'], '赵信']

由以上结果可得:深拷贝是完完全全的复制,是创建一个完完全全的新的对象,新旧对象之间不会相互影响。不可变数据类型新旧列表指向同一个空间,可变类型新列表创建了新的空间

另附:

a = [1, 2]
a[1] = a   #对a列表的第二个元素进行修改成自己
print(a[1])  #输出为[1, [...]]
print(a)  #输出为[1, [...]]
print(id(a),id(a[1]))  #输出内存地址1191853053000 1191853053000  a与a[1]的内存地址一样
print(type(a[1]))  ##输出<class 'list'>

分析: a[1] 原来是int类型,在对a[1]进行修改操作时,会先把原来的指向剪断,因为赋值a,指向了自己,此时出现了数据上的死循环。

函数

参数

参数及其传递

#向函数传递信息
def greet_user(username):  #username是形参
    print("hello," + username + "!" )

greet_user('python')  #'python'是实参

在函数名中定义一个形参,函数调用时,给函数名中的形参传递实参。

传递实参的方法有:

  • 位置实参(按照基于实参的顺序关联到形参,有顺序)
  • 关键字参数(类似按照键值对,按照名字进行关联,无顺序问题)
  • 默认值参数(给形参进行固定值作为默认值,如果没有提供实参对默认值进行覆盖处理,则代入默认数值后运行函数)

    注意:

  • 两种传参方式可以混合使用,但使用时关键字参数必须位于位置参数之后

可变参数*args与**kwargs

fengmk2博客相关内容

def f(*args, **kwargs):
    print('args = ', args)
    print('kwargs = ', kwargs)
    print()

if __name__ == '__main__':
    f(1,2,3,4)
    f(a=1,b=2,c=3)
    f(1,2,3,4, a=1,b=2,c=3)
    f('a', 1, None, a=1, b='2', c=3)

输出结果是

args =  (1, 2, 3, 4)
kwargs =  {}

args =  ()
kwargs =  {'a': 1, 'c': 3, 'b': 2}

args =  (1, 2, 3, 4)
kwargs =  {'a': 1, 'c': 3, 'b': 2}

args =  ('a', 1, None)
kwargs =  {'a': 1, 'c': 3, 'b': '2'}

这是python中的两种可变参数。

  • *args表示任何多个无名参数,它是一个tuple
  • **kwargs表示关键字参数,它是一个dict
  • 同时使用*args**kwargs时,*args参数必须在**kwargs前,像f(a=1, b='2', c=3, a', 1, None)这样调用的话,会提示语法错误SyntaxError: non-keyword arg after keyword arg

等效的函数调用

函数调用时,无论是使用位置参数还是关键字参数、默认值参数,得到的结果都是一样的。

#一个名为harry的小狗
def describe_pet(pet_name,animal_type = 'dog'):
    函数省略
describe_pet(pet_name="harry")
describe_pet("harry")

两次使用describe_pet()函数的结果一致

全局变量和局部变量

  1. 这是两种不同的变量
  • 局部变量是函数内部的占位符,与全局变量可能重名但是不同
  • 函数运算结束后,局部变量被释放,不再进行储存
  • 可以使用global保留字,从而在函数内部使用全局变量
  1. 局部变量为组合数据类型且未创建,等同于全局变量
ls=['x', 'y']  #真实创建了一个ls全局变量列表
def f(n):
    ls.append(n)  #ls是列表类型,没有真实创建,等同于全局变量
    return  #加不加return都是一样的
f('z')  #全局变量被修改
print(ls)

以上输出为['x', 'y', 'z']

ls=['x', 'y']  #真实创建了一个ls全局变量列表
def f(n):
    ls = []  #ls是列表类型,真实创建,在这里ls是局部变量
    ls.append(n)
    return  #加不加return都是一样的
f('z')
print(ls)

以上输出为['x', 'y']

规则总结

  • 基本数据类型,无论是否重名,局部变量与全局变量不同
  • 可以通过global保留字在函数内部声明全局变量
  • 组合数据类型,如果局部变量未真实创建,则是全局变量

另附:

  • return在不带参数的情况下(或者没有写),默认返回None

文件

数据分析与爬虫

内库与三方库