python面试题总结:
1、知乎
一、一些基础
1、命名规范
1,模块命名
(1)模块推荐使用小写命名,
(2)除非有很多字母,尽量不要用下划线
因为很多模块文件存与模块名称一致的类,模块采用小写,类采用首字母大写,这样就能区分开模块和类。
2,类命名
(1)类名使用驼峰(CamelCase)命名风格,首字母大写;
(2)私有类可用一个下划线开头。
3,函数命名
(1)函数名一律小写,如有多个单词,用下划线隔开
(2)类内部函数命名,用单下划线(_)开头(该函数可被继承访问)
(3)类内私有函数命名,用双下划线(__)开头(该函数不可被继承访问)
4,变量命令
(1)变量名推荐小写,如有多个单词,用下划线隔开
(2)类内部变量命名,用单下划线(_)开头(该变量可被继承访问)
(3)类内私有变量命名,用双下划线(__)开头(该变量不可被继承访问)
2、保留字
3、下划线开头的特殊含义
4、一些内置函数
type(a) # 返回变量a 的类型
id(b) # 返回变量b 的物理地址
5、转义符
6、布尔类型
7、类型转换
# 变量名用a表示
str(a)
chr(a)
int(a)
float(a)
ord(a)
int(x [,base ]) 将x转换为一个整数
long(x [,base ]) 将x转换为一个长整数
float(x ) 将x转换到一个浮点数
complex(real [,imag ]) 创建一个复数
str(x ) 将对象 x 转换为字符串
repr(x ) 将对象 x 转换为表达式字符串
eval(str ) 用来计算在字符串中的有效Python表达式,并返回一个对象
tuple(s ) 将序列 s 转换为一个元组
list(s ) 将序列 s 转换为一个列表
chr(x ) 将一个整数转换为一个字符
unichr(x ) 将一个整数转换为Unicode字符
#
ord(x ) 将一个字符转换为它的整数值
hex(x ) 将一个整数转换为一个十六进制字符串
oct(x ) 将一个整数转换为一个八进制字符串
8、input() 函数与split() 函数
注:这里指的是python3的用法
a = input() # 从键盘得到输入,为字符串类型
a = input('提示语') # 提示语必须是字符串格式
a = input().split() # split()通过指定分隔符对字符串进行切片,默认空格为分隔符, 返回为字符串数组
a = input().split(',', 1) # 按 ,分隔,分隔1次
a = int(input) # 转换成整型
a, b , c = map(int, input().split()) # 一行输入多个,以空格为分隔符, 都转成整形
# 注意:map()函数接受两个接收两个参数,一个是函数,一个是序列,map()将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
连接: input()
9、运算符
幂指数 **
求余 %
求整 //
异或 ^ # 相异 为1
取反 ~
左移位 <<
右移位 >>
除法 / # 浮点数运算可以写成 c = a / float(b)
10、跳转语句 break 、continue、pass
break # 结束所有循环
continue # 结束后面语句,继续下一个循环
pass # 占位操作
11、## 数据类型(6种)
- 数字: int、float、bool、complex(复数) 说明:其中bool是int的子类,True 和 False 可以和数字相加,
True==1、False==0
会返回 True ; complex(a,b) 表示 a + bj, 复数的实部 a 和虚部 b 都是浮点型 - 字符串:字符串用单引号 ’ 或双引号 " 括起来,同时使用反斜杠 \ 转义特殊字符; 与 C 字符串不同的是,Python 字符串不能被改变。向一个索引位置赋值,比如word[0] = 'm’会导致错误(字符串中的某个字符不能索引赋值)
- 列表: 列表中元素的类型可以不相同,它支持数字,字符串甚至可以包含列表(所谓嵌套)
- 元组: 元组(tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开
- 集合: 可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典
- 字典: 字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合
可变对象:列表、字典、字典
不可变对象: 数字、字符串、元组
二、序列(列表、元组、集合、字典、字符串)
分类 | 函数 | 符号 | 是否可变 | 是否有序 | 是否重复 |
---|---|---|---|---|---|
列表 | list() | [ 1,2,3] | 可变序列 | 有序:可以索引和切片 | 可重复 |
元组 | tuple() | (1,2,3) | 不可变序列只能对整体进行操作 | 可以索引和切片 | 可重复 |
集合 | set() | { 1,2,3} | 可变序列 | 无序:不可以索引和切片 | 不可重复 |
字典 | dict() | {‘a’:1,‘b’:2} | 可变序列 | 无序:不可以索引和切片 | 可重复 |
字符串 | str() | ''abcdef ‘’ | 不可变序列(不可对其中单个字符进行单独修改) | 有序:可以索引和切片 | 可重复 |
注:tuple() 只用于转换类型,里面放一个变量 ,不可用于新建
1、序列概述
1、集合和字典不支持索引、切片、相加、相乘操作
2、 切片
3、序列相加
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> print(a+b)
[1, 2, 3, 4, 5, 6] # 相当于把b中元素放到a中元素的后面
4、序列相乘
>>> a = [1,2,3]
>>> c = a*5
>>> print(c)
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3] # 相当于加了5次,即里面不断放入元素
5、in (检查序列成员)
6、## 其它内置函数(sorted)
# 排序函数
sorted(listA, reverse = True) # 默认升序,reverse = True 为降序
2、列表
1、创建列表
#
listA = []
#
listB = list(data) # 注: data 可以是函数 如 range(1,10)
例:
>>> print(list(range(1,10)))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
2、删除列表
del listA # 删除整个列表,释放内存,不常用
3、枚举:enumerate()方法
>>> for i, item in enumerate(a):
print(i,item) # 获取索引和元素值
0 1
1 2
2 3
4、合并列表:extend()
向listA中添加listB的所有元素
listA.extend(listB)
例:
>>> a = [1,2]
>>> b = [3,4,5]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4, 5]
>>>
5、删除元素 del和remove
#
del listA[0]
#
listA.remove(元素值)
6、## 统计元素出现的次数 count(x)、元素的下标index(x)
listA.count(a) # 统计A中 a元素的个数
》》升级版counter
# Counter() 统计不同元素及对应个数 ,记得加dict()函数才能 返回包含元素和对应数目的键值对字典
#(计数器,有点类似于计数器)通常用collections.Counter(xxx)
from collections import Counter
colors = ['red', 'blue', 'red', 'green', 'blue', 'blue']
c = Counter(colors)
print(c) # Counter( {'red': 2, 'blue': 3, 'green': 1})
print (dict(c)) # {'red': 2, 'blue': 3, 'green': 1} ,记得加dict()函数才能 返回包含元素和对应数目的键值对字典
listA.index(a) # 返回第一个元素a 的下标
7、## 排序:list对象 sort()函数和内置函数 sorted()函数
#
listA.sort() # 会改变 listA
#
listB = sorted(listA) # 可以创建一个新副本listB
# 注:reverse = True 表示为降序
8、列表推导式 : listA = [ i for i in range(20)]
>>> listA = [ i for i in range(20)]
>>> print(listA)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
9、创建二维数组
10、## 双端队列
import collections
d = collections.deque()
# 相应操作
d.append()
d.appendleft() # 在最左边添加一个元素
d.pop()
d.popleft()
# 实例
q1 = collections.deque()
print(q1) # deque([])
q = collections.deque([1,2,3])
print(q) # deque([1, 2, 3])
3、 元组 (tuple)
1、 与列表区别
2、zip()函数
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
>>>a = [1,2,3]
>>>b = [4,5,6]
>>>c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
4、字典
1、字典的一些特点
2、 通过映射来创建字典 zip()函数
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = dict(zip(a,b)) # a,b 不等长时,取短的
>>> print(c)
{1: 4, 2: 5, 3: 6}
3、访问字典的两种方法: dict[keys] 和 dict.get(keys)
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = dict(zip(a,b))
>>> print(c)
{1: 4, 2: 5, 3: 6}
>>> print(c[1]) # 通过键
4
>>> print(c.get(1)) # 通过get() 函数
4
4、## 遍历字典的 keys()、values()、items() 方法
Python3 字典 keys() 方法返回一个视图对象。
dict.keys()、dict.values() 和 dict.items() 返回的都是视图对象(view objects),提供了字典实体的动态视图,这就意味着字典改变,视图也会跟着变化。
视图对象不是列表,不支持索引,可以使用 list() 来转换为列表。
我们不能对视图对象进行任何的修改,因为字典的视图对象都是只读的。
注意:Python2.x 是直接返回列表
# c = {1: 4, 2: 5, 3: 6}
# 遍历键
>>> for key in c.keys():
print(key,' ', end='') # print函数默认有个end = '\n'
1 2 3
# 遍历值
>>> for value in c.values():
print(value,' ',end='')
4 5 6
# 遍历键和值
>>> for key, value in c.items():
print(key, value,' ',end='')
1 4
2 5
3 6
5、删除一个元素
del 字典名[‘键值’]
6、字典推导式(用推导式创建字典)
>>> a = {i:'你好' for i in range(4)}
>>> print(a)
{0: '你好', 1: '你好', 2: '你好', 3: '你好'}
5、集合
1、集合的创建:{ } 和 set()方法
#
set1 = {1,2, 3, 4}
#
set2 = set([1,2,3,4])
2、集合的添加与删除 set.add(元素)、set.pop()、remove(element)
set.add()
#set.pop() 是随机删除一个元素
#remove(element) 是删除指定元素
三、##字符串
1、字符串的常用操作
1、字符串之间的拼接 : +
用 A+B 拼接两个字符串,不能与其它类型拼接
2、截取(切片)
3、## 字符串的分割和合并: split() 和 join()
1)分割
split() 括号中可以填指定的分隔符,默认为空格等其它空字符
注: 返回值 为字符串列表
#
s_1 = 'a-b-ce-d'
s_2 = s_1.split('-')
print(s_2)
['a', 'b', 'ce', 'd']
2)合并
新字符串名 = 指定的分隔符.join(字符串类型的可迭代对象)
a = [1,2,3,4,5,6]
s3= [str(i) for i in a] # 元素为整数先转化为字符串类型
s4 ='-'.join(s3) # 分隔符为'-',合并对象为 列表S3
print(s4, type(s4))
1-2-3-4-5-6 <class 'str'>
4、字符串的检索cout()、find()、index()
a.cout(b) # 统计指定字符串b在a中出现的次数,不存在则返回0
a.find(b) # 返回b在a中首次出现的索引,没有返回-1
a.index(b) # 返回b在a中首次出现的索引, 没有则抛出异常
s_10 = 'abcdefadcc'
z = s_10.count('a')
print(z) # 2
5、字符串的大小写转换 lower(),upper()
6、## strip()去除字符串左右两边的空格和特殊字符(过滤)
strip()
lstrip()
rstrip()
#
s_3 = ' @acbd@c @ $ %'
print(s_3.strip('@$% ')) # 过滤前后@¥%和空格(记得空格也要放里面)
7、## 格式化输出字符串 % 和 format()函数
重点类型:s–字符串,c–字符,d–整数,f–浮点数
其中:.2f 表示保留两位小数
1)% 方法
s_6 = '输入:%s+%s 输出:%d'
s_7 = ('7','8',15) # 这里就是exp,必须使用元组
print(s_6%s_7)
print('输入:%s+%s 输出:%d'%('7','8',15)) # 输出的字符串和对应的参数用%分隔, 对应参数的必须使用元组
输入:7+8 输出:15
输入:7+8 输出:15
2)format()函数
{: s} 字符串 ;{:d}整数;{:f }浮点数
print(“xxx{: s}xxx{:d}xxx”.format(a,b))
s_4 = '输入:{:s}+{:s} 输出:{:d}' # 先定义模板,相关格式用{:s}之类的表示
s_5 = s_4.format('7', '8', 15) # 在使用format函数指定对应参数
print(s_5)
输入:7+8 输出:15
2、## 正则表达式
作用:正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
1、正则表达式规则
{}花括号为出现的次数
[] 中括号为可匹配的字符
例子:匹配ip地址(网址:https://regex101.com/)
2、## re模块实现正则表达式操作:re.match()、re.search()、re.findall()
re.match(pattern, string_1)
match必须严格匹配(头尾默认加了边界)。匹配返回match对象,没匹配返回None
re.search(pattern, string_1)
search 比较灵活(可以是字符串中的某个部分),返回第一个匹配的(包含在match对象中)
re.findall(pattern, string_1)
findall也是灵活匹配,且能返回所有匹配的字符串列表
import re
pattern = r'mr\w' # 注意:正则模板用原生字符串 即前面加 r
string_1 = '77mr4 mr8'
string_2 = 'mra'
# re.match()
match_1 = re.match(pattern, string_1)
match_2 = re.match(pattern, string_2)
print(match_1, '\n', match_2)
search_1 = re.search(pattern, string_1)
search_2 = re.search(pattern, string_2)
print(search_1, '\n', search_2)
findall_1 = re.findall(pattern, string_1)
findall_2 = re.findall(pattern, string_2)
print(findall_1, '\n', findall_2)
# 输出
None # match必须严格匹配(头尾默认加了边界)。没找到返回None
<_sre.SRE_Match object; span=(0, 3), match='mra'> # 匹配返回match对象,#pan是范围的意思,表示匹配字符串的索引位置
<_sre.SRE_Match object; span=(2, 5), match='mr4'> # search 比较灵活,返回第一个匹配的位置(包含在match对象中)
<_sre.SRE_Match object; span=(0, 3), match='mra'>
['mr4', 'mr8'] # findall的匹配也很灵活,且能返回所有匹配的字符串列表
['mra']
3、使用正则替换字符串 re.sub(pattern, req1,string )
import re
pattern = r'mr\w' # 注意:正则模板用原生字符串 即前面加 r
string_1 = '77mr4 mr8'
sub_1 = re.sub(pattern,'mr48',string_1)
print(sub_1) # 77mr48 mr48
4、##使用正则切割字符串 re.split(pattern,string) 返回字符串数组
split的升级版
import re
pattern = r'mr\w' # 注意:正则模板用原生字符串 即前面加 r
string_1 = '77mr4 mr8'
split_1 = re.split('mr',string_1)
print(split_1) # ['77', '4 ', '8']
四、函数
1、函数的创建和调用
1、创建和调用的基本方法(有无默认参数)
# 创建
def mySolution(a,b):
""" 注释功能和输入输出
:param a:
:param b:
:return: a+b
"""
c = a / b
return c
def mySolution_1(a, b, c = 5): # 带默认参数
'''
:param a:
:param b:
:param c: 默认值为5
:return:
'''
d = a * b + 5
return d
# 调用
print(mySolution(1, 3)) # 形参实参位置对应
print(mySolution(b = 1,a = 3)) # 使用关键字参数(可以位置不对应)
print(mySolution_1(2,3)) # c不填时就用其默认值
另外注意:定义函数时参数默认值要用不可变对象,(数组是可变对象)
2、## 可变参数 *prameter 以及 **parameter(输入的数量可以为任意长)
*parameter 把输入放到parameter元组中,实际输入形式:
**parameter 把输入放道parameter字典中,所以实际输入参数形式为:key = value 或者 (**定义好的字典)
例子:
def demo1(*pra):
for i in pra: # 实际得到一个pra元组
print(i)
# 调用
list1 = [1,2,3,'a']
demo1(*list1) # 注意这里传参时也要加上*
demo1('a','b','c')
输出
1
2
3
a
a
b
c
# *args,**kwargs
def solution(*args): # 输入变量放在元组args中
for c in args:
print(c)
# 调用两种输入方式
solution(1,2,3,4) # 直接输入变量
solution(*(1,2,3,4)) # 或者 *数组\*元组
def solution_2(**kwargs): # 关键字参数的显式赋值,保存到字典kwargs中
for key, value in kwargs.items():
print(key,value)
solution_2(a=1,b=2,c=3) # 关键字参数
solution_2(**{'a':1,'b':2,'c':3}) # **字典
3、return 函数
def demo2(n):
a = 0
b = 0
for i in range(n):
a = i + a
b = b - i
return a, b
re_1 = demo2(5)
print(re_1) # (10,-10) ,即多个返回值时放在元组当中
4、局部变量和全局变量
在函数内定义的变量就是局部变量,在函数外无法直接使用
全局变量的两种形式:
1)在函数体外声明
2)在函数体内 使用 global 关键字声明
5、## 隐式函数 (lambda)
re_2 = lambda r: r**2
print(re_2) # <function <lambda> at 0x000001E651704840>,直接使用返回的是一串地址
print(re_2(10)) # 必须像函数那样输入相应参数
s = lambda x,y : x**y
print(s(2,3)) # 括号中填相应参数
五、面向对象
1、面向对象概述
1、对象(一个实体:包含静态的属性和动态的行为)
对象是类的实例
2、类(封装了对象的属性和行为的载体)
类:具有相同属性和行为的一类实体被称为类
3、面向对象设计的三大特征
1)封装
2)继承
子类可以调用父类的属性和方法 : class B(A)
B继承A的属性和方法
3)多态
子类继承父类特征的同时,还具有自身独有的特性,可以实现不同的效果,这就是多态
2、类的定义与使用
1、定义类
2、创建类的实例(类定义好后要实例化才能创建对象供使用)
class Car:
"""
类的说明放这里
"""
pass
car = Car() # 实例化
print(car) # <__main__.Car object at 0x000001CDBE80A828> , 说明car是Car的实例
3、init() 方法
创建新实例,都会执行类中的 init() 方法
init中必须有self,它是指向实例本身的引用,用于访问类中的属性和方法。
4、类成员的创建和访问:成员包括实例方法和数据
1)实例方法(定义在类中的函数)
class YunSuan:
"""
类的说明
"""
def __init__(self):
self.a = 10
self.b = 5
def Add(self, a, b):
c = a + b
return c
def Sub(self, a, b):
return a - b
def Min(self, a, b):
return min(a, b)
ys = YunSuan() # 实例化
print(ys)
a = 2
b = 3
x = ys.Add(a, b) # 调用类的方法
y = ys.Sub(a, b) # 调用类的方法
print(x, y) # 5 -1
2)创建 数据数据(定义在类中的变量):分为类属性和实例属性
a、类属性
直接在类中、方法外定义,
调用时前面加 类名,如:ClassName.shuxing
b、实例属性
在__init__()方法中定义:格式为self.shuxing
调用时用 实例名.shuxing
例:
class YunSuan:
"""
类的说明
"""
# 类属性
jiahao = '+'
jianhao = '-'
def __init__(self):
# 实例属性
self.a = 10
self.b = 5
ys = YunSuan()
print(ys)
print('调用实例属性:'+ str(ys.a) + '\t' + str(ys.b)) # 调用实例属性:10 5
print('调用类属性:'+str(YunSuan.jiahao)) # 调用类属性:+
5、## 访问限制: 属性和方法前面添加 单下划线、双下划线、首尾双下划线
单下划线的被单独import无效
双下划线的不能直接被实例访问
3、@property (装饰器) 创建用于计算的属性
注:@property转换后的属性的不能被重新赋值
class YunSuan:
def __init__(self):
# 实例属性
self.a = 10
self.b = 5
@property # 装饰器,将方法转换成属性
def Max(self):
return max(self.a, self.b)
ys = YunSuan()
print('调用装饰器转换后的属性:'+ str(ys.Max) ) # Max被装饰器转换成了属性,调用时就计算好了,固不需要(),
输出
调用装饰器转换后的属性:10
4、 继承
1、继承的基本语法
class 子类名(父类名)
:区别就是这个括号中填父类名
然后子类实例可以调用父类中的属性和方法(一般是共有成员或保护成员,私有成员:双下划线的 子类 不可以调用)
子类的属性或者方法和父类重名时,调用的是子类自己的
class SuanFa:
m = 0
def jiafa(self,a,b):
return a+b
class SuanFa01(SuanFa):
m = 10 # 和父类属性重名
class SuanFa02(SuanFa):
n = 100 # 不重名
def jiafa(self,a,b): # 方法和父类重命
return a + 2*b
suanfa01 = SuanFa01()
suanfa02 = SuanFa02()
x = suanfa01.m # 10
y = suanfa01.jiafa(1,3) # 4
z = suanfa02.m # 0
w = suanfa02.jiafa(1,3) # 7
print(x,'\t',y,'\t',z,'\t',w)
# 输出:
10 4 0 7
2、方法重写
就是在子类中重新定义方法: 该方法和父类中的方法是重名的,调用时只会调用子类的方法
3、???定义子类时可以调用父类的 初始化方法
super().init()
六、模块
1、自定义模块
模块可以避免变量名和函数名 重名冲突
包可以避免模块名重名冲突
1、创建模块
2、## 导入模块
import 每次导入都要产生一个新的命名空间(字典的形式,为对象名字和对象之间的对应关系),而且会在新的命名空间中执行语句。在使用导入的模块中的方法时,必须每次都加上模块名前缀
from import 则是将模块中的定义导入到当前空间,所以每次使用时就不需要前缀,但是要注意不能重名,否则会覆盖
如果导入有问题,可以将模块的路径A添加到搜索路劲径sys.path中,但是只在当前窗口中有效: sys.path.append(A)
1、import
模块要和当前脚本处于同级目录下
2、from import
3、导入模块的路径问题
2、## 以主程序的形式运行
1、导入被执行时: name = 模块名称
2、 直接执行时: name = main
if name == ‘main’:
if __name__ == '__main__': # 这样被其它模块导入时,它下面的函数就不会被执行
运行时会将导入模块A运行一次,所以最好在A中将它的可执行语句,如 print函数 放在 if name == ‘main’:
3、包(package)
1、包结构
2、创建包
3、使用包
有三种形式,注意前缀
import 包名.模块名
前缀:包名.模块名
from 包名 import 模块名
前缀: 模块名
from 包名.模块名 import 成员名
只掉调用成员名
4、引用其它模块
1、标准模块
# 有待进一步研究
sys: sys.path()
time: time.time()
os
re: re.match(模式,string)
math
logging
2、第三方模块
七、异常处理与程序调试
1、异常概述
2、异常处理语句
1、## try 。。。except
2、try … except … else
没有异常时执行else
3、try … except … else … finally
无论是否又异常,最后都会执行finally中的语句
def chu_fa(a,b):
return a/b
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
if __name__ == '__main__':
try:
print(chu_fa(a, b))
except ZeroDivisionError as e:
print("出现异常:", e)
else:
print('顺利完成')
finally:
print("进行了一次除法操作")
输出:
请输入被除数:10
请输入除数:0
出现异常: division by zero
进行了一次除法操作
4、raise Error(reason)
def chu_fa(a,b):
if b == 0:
raise ZeroDivisionError("除数不能为0") # 抛出相关错误的自定义描述
c = a/b
return c
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
if __name__ == '__main__':
try:
print(chu_fa(a, b))
except ZeroDivisionError as e:
print("出现异常:", e)
else:
print('顺利完成')
finally:
print("进行了一次除法操作")
输出:
请输入被除数:10
请输入除数:0
出现异常: 除数不能为0 # 这个就是调用了 raise 中的描述
进行了一次除法操作
3、程序调试
4、## assert 断言
assert 条件表达式A,异常原因描述字符串
注意:A为真则什么都不做,A为假则抛出AssertionError 异常
AssertionError 异常可搭配try… except 使用
def chu_fa(a,b):
assert b != 0, '除数为0' # 注意是 条件为真什么都不做,条件为假则抛出异常
if b == 0:
raise ZeroDivisionError("除数不能为0") # 抛出相关错误的自定义描述
c = a/b
return c
if __name__ == '__main__':
a = int(input("请输入被除数:"))
b = int(input("请输入除数:"))
try:
print(chu_fa(a, b))
except AssertionError as d: # 断言异常
print("出现异常:", d)
except ZeroDivisionError as e:
print("出现异常:", e)
else:
print('顺利完成')
finally:
print("进行了一次除法操作")
# 输出:
请输入被除数:10
请输入除数:0
出现异常: 除数为0
进行了一次除法操作
八、文件及目录操作
1、基本文件操作
r 只能读 (带r的文件必须先存在)
r+ 可读可写 不会创建不存在的文件 从顶部开始写 会覆盖之前此位置的内容
w+ 可读可写 如果文件存在 则覆盖整个文件不存在则创建 //要close 之后才算完成写入
w 只能写 覆盖整个文件 不存在则创建
a 只能写 从文件底部添加内容 不存在则创建
a+ 可读可写 从文件顶部读取内容 从文件底部添加内容 不存在则创建
1、## 创建和打开文件 open
open(文件名或文件的路径名,模式)
# 默认为只读 r,模式记得加引号
2、关闭文件 close
# 示例:
"""new_file.txt:
123
456
789
abc
"""
file01 = open('new_file.txt', 'r+') # 同级目录不用添加路径, 读写形式打开,光标在起始
file02 = open('D:/nihao.txt', 'a+') # 其它的需要添加路径,这里用反斜杠避免转义;读写模式,光标在末尾
file02.write('\nwobuhao') # 写入
file01.seek(2) # 移动光标位置
string = file01.read(4) # 读取4个字符
string_1 = file01.readline() # 读取一行,返回字符串(当前光标开始的一行)
string_2 = file01.readlines() # 读取所有行(从当前光标开始),返回的是字符串列表,一行对应一个列表里的一个字符串元素
string_3 = file02.readline()
print(type(file01),file01)
print('读取4个字符:', string) # 3 后面有一个'\n'
print('读取一行,返回字符串:',string_1)
print('读取所有行,返回的是字符串列表:',string_2)
for str1 in string_2:
print(str1.strip()) # 过滤空字符
print("new_file.txt文件的内容:", string_1)
3、with open() as 变量:
执行完可以自动关闭文件
with open('with_file', 'r+') as file03:
strlist01 = file03.readlines()
file03.write('nihaoma\nwohenhao\nxiexie')
print(strlist01)
4、## 写 file.write()
一定是 ‘w’ 或 ‘a’ 模式下打开的文件才能写
5、## 读取 file.read()、readline()、readlines()
一定是 读 模式下:r 、r+ 才能使用
注意:readlines()
返回的是字符串数组,每个元素对应一行字符串
2、目录操作
os模块 负责 程序与操作系统的交互,提供了访问操作系统底层的接口
注意目录写法中 用双斜杠或者反斜杠、还可以在路径字符串前面加r 使用原生字符串
1、 os 和 os.path模块
1) os模块对目录的增删改查:
os.listdir(path) # 列出指定目录中的文件和目录
os.mkdir(path) # 创建(当文件已存在时,无法创建该文件)
os.makedirs(path1/path2) # 创建多级目录
os.rmdir(path) # 删除(只能删除空目录:里面不包含目录或者文件)
os.removedirs(path1/path2) # 删除多级目录
os.chdir(path) # 修改当前所在目录为指定目录
os.getcwd() # 返回当前文件所在地址
os.walk(path) # 遍历路径下的目录,一级一级保存在元组中
2)os.path模块的
最重要的: b = os.path.exists('D:/demo') # 是否存在,返回True或False
import os
a = os.path.abspath('10_mulu_2.py') # 输入相对路径,输出绝对路径
b = os.path.exists('D:/demo') # 是否存在,返回True或False
c = os.path.join("D:\\demo",'10_mulu_2.py') # 拼接目录和文件
d = os.path.splitext('10_mulu_2.py') # 分隔文件名和扩展名
e = os.path.basename(r'D:\pythonSelenium\pythonExcise\第十章_目录及文件操作\10_mulu_2.py') # 从路径中获取文件名
f = os.path.dirname(r'D:\pythonSelenium\pythonExcise\第十章_目录及文件操作\10_mulu_2.py') # 从路径中获取目录名
# 判断
x = os.path.isabs(r'D:\pythonSelenium\pythonExcise\第十章_目录及文件操作\10_mulu_2.py')
y = os.path.isdir('10_mulu_2.py')
z = os.path.isfile('10_mulu_2.py')
2、相对路径和绝对路径
相对路径:依赖于当前工作目录
绝对路径:不依赖于当前工作目录,是实际目录
绝对路径:
3、创建目录 os.mkdir()
5、删除目录 os.rmdir()
3、文件高级操作
1、## 删除文件 os.remove(‘nihao.txt’)
2、## 重命名文件和目录 os.rename(src,newname)
九、补充
1、sys模块
1、sys模块主要是用于提供对python解释器相关的操作
sys.path
sys.stdin.readline()
sys.stdout.write(xxx)
# 与解释器相关
import sys
"""
它是一个list.默然情况下python导入文件或者模块的话,
他会先在sys.path里找模块的路径。如果没有的话,程序就会报错。
"""
# 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
print(sys.path)
# 如果模块不在搜索路径,可以添加至搜索路径
# sys.path.append(xxx)
# 获取Python解释程序的版本信息
print(sys.version)
# 标准输入 sys.stdin
a = sys.stdin.readline() # 从标准输入读一行
# 标准输出 stdout.write
sys.stdout.write(a) # 屏幕输出a
2、拷贝 copy模块
赋值引用:完全传对象引用;a ,b 指向同个引用,等价
copy.copy:浅拷贝,只拷贝父对象,不拷贝父对象的子对象;即 子对象的引用相同,父对象相互独立
copy.deepcopy:深拷贝,拷贝父对象和子对象;父对象和子对象都独立
在浅拷贝时,拷贝出来的新对象的地址和原对象是不一样的,但是新对象里面的可变元素(如列表)的地址和原对象里的可变元素的地址是相同的,也就是说浅拷贝它拷贝的是浅层次的数据结构(不可变元素),对象里的可变元素作为深层次的数据结构并没有被拷贝到新地址里面去,而是和原对象里的可变元素指向同一个地址,所以在新对象或原对象里对这个可变元素做修改时,两个对象是同时改变的,但是深拷贝不会这样,这个是浅拷贝相对于深拷贝最根本的区别。
https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html
"""
1. python不允许程序员选择采用传值还是传引用。
Python参数传递采用的肯定是“传对象引用”的方式。
实际上,这种方式相当于传值和传引用的一种综合。
如果函数收到的是一个可变对象(比如字典或者列表)的引用,
就能修改对象的原始值——相当于通过“传引用”来传递对象。
如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,
就不能直接修改原始对象——相当于通过“传值'来传递对象。
2. 当人们复制列表或字典时,就复制了对象列表的引用,如果改变引用的值,则修改了原始的参数。
3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,
Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。
每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,
只有当引用计数为零时,才真正从内存中删除Python对象。
"""
import copy
a = [1, 2, 3, 4, ['a', 'b']] # 原始对象
b = a # 赋值,传对象的引用
c = copy.copy(a) # 对象拷贝,浅拷贝; c 和 a 是一个独立的对象,但他们的子对象还是指向统一对象(是引用)
d = copy.deepcopy(a) # 对象拷贝,深拷贝 ;深度拷贝, d 完全拷贝了父对象及其子对象,两者是完全独立的。
a.append(5) # 修改对象a
a[4].append('c') # 修改对象a中的['a', 'b']数组对象
print("修改原始对象后:",'a = ', a)
print("赋值引用:",'b = ', b)
print("拷贝:",'c = ', c)
print("深拷贝:",'d = ', d)
d = 1
e = d
d = 2 # d改变不会改变e,因为不可变对象相当于是传值
print("e=",e,";",'d=',d)
# 结果
修改原始对象后: a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
赋值引用: b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
拷贝: c = [1, 2, 3, 4, ['a', 'b', 'c']]
深拷贝: d = [1, 2, 3, 4, ['a', 'b']]
e= 1 ; d= 2
3、## Python中单下划线和双下划线分别是什么?
__name__
:Python的特殊方法名,确保Python系统中的名称不会跟用户自定义的名称发生冲突的方式。
_name:保护类型,只允许类和子类进行访问,可以用类的实例名进行访问,但不允许 from xx import *(全部导入不可以,局部导入可以),实际访问限制不高
__name:解释器用_classname__name来代替这个名字,以免与子类
中定义的名称产生冲突(会默认在前面加_classname,防止冲突)
4、自省函数 dir()、type()、id()
"""
dir() / type() / hasattr() / isinstance()
"""
# dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数对象的属性、方法列表。
print(dir())
print(dir(int)) # 返回对象类的方法和属性的字符串列表
# type() 返回对象的类型
print(type("2"))
# hasattr(对象,方法或属性名) 判断该对象中是否包含该成员
print(hasattr(int,'__bool__'))
# id() 查看变量的内存地址
5、数学计算
1)绝对值
d = abs(c)
2)平方根
import math
b = math.sqrt(a) # 返回浮点数
- 指数函数
c = pow(a,b)
6、new 和 init 以及 del
网址:https://www.cnblogs.com/shenxiaolin/p/9307496.html
1) __new__方法:类级别的方法
是在实例创建之前被调用的,因为它的任务就是创建实例然后返回该实例对象,是个静态方法。
返回: super( ).new(cls)
2)init
是当实例对象创建完成后被调用的,然后设置对象属性的一些初始值,通常用在初始化一个类实例的时候。是一个实例方法。
__new__先被调用,__init__后被调用,__new__的返回值(实例)将传递给__init__方法的第一个参数(self),然后__init__给这个实例设置一些参数。(一前一后,new有返回值,init没有)
3)del
事实上在编写程序时,如果之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(整个过程称为垃圾回收(简称GC))。
大多数情况下,Python 开发者不需要手动进行垃圾回收,因为 Python 有自动的垃圾回收机制(下面会讲),能自动将不需要使用的实例对象进行销毁。
无论是手动销毁,还是 Python 自动帮我们销毁,都会调用 del() 方法。举个例子:
class CLanguage:
def __init__(self):
print("调用 __init__() 方法构造对象")
def __del__(self):
print("调用__del__() 销毁对象,释放其空间")
clangs = CLanguage()
del clangs
程序运行结果为:
调用 init() 方法构造对象
调用__del__() 销毁对象,释放其空间
7、python异常处理(try语句含有return时,会不会执行finally)
结果:try中有return, else将不会执行,finally会执行。
8、如何实现封装(包括接口的理解)
接口应该是类里面提供给外部访问的部分函数,而类中其它函数或者属性都是通过私有化被隐藏起来无法被外部直接访问的。
想隐藏的细节:私有属性和私有方法,即在名字前 加双下划线;然后在接口函数中可以使用这些私有成员;然后外部只能通过接口函数来实现访问,而私有属性和方法则无法直接调用。
https://www.bilibili.com/read/cv8420120/
将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
比如我要设置名字:可以设置名字为私有变量不能直接访问修改,需要通过setname方法,同时在setname中添加了判断条件使之不能随意修改,不然就会报错
class Person:
def setname(self, name):
if len(name) < 5:
raise ValueError('名称长度必须小于5!')
self.__name = name # 满足条件才通过setname这个接口函数进行私有变量的修改
9、关于str和byte
bytes和str之间的异同
回到bytes和str的身上。bytes是一种比特流,它的存在形式是01010001110这种。我们无论是在写代码,还是阅读文章的过程中,肯定不会有人直接阅读这种比特流,它必须有一个编码方式,使得它变成有意义的比特流,而不是一堆晦涩难懂的01组合。因为编码方式的不同,对这个比特流的解读也会不同,对实际使用造成了很大的困扰。下面让我们看看Python是如何处理这一系列编码问题的:
>>> s = "中文"
>>> s
'中文'
>>> type(s)
<class 'str'>
>>> b = bytes(s, encoding='utf-8')
>>> b
b'\xe4\xb8\xad\xe6\x96\x87'
>>> type(b)
<class 'bytes'>
从例子可以看出,s是个字符串类型。Python有个内置函数bytes()可以将字符串str类型转换成bytes类型,b实际上是一串01的组合,但为了在ide环境中让我们相对直观的观察,它被表现成了b’\xe4\xb8\xad\xe6\x96\x87’这种形式,开头的b表示这是一个bytes类型。\xe4是十六进制的表示方式,它占用1个字节的长度,因此”中文“被编码成utf-8后,我们可以数得出一共用了6个字节,每个汉字占用3个,这印证了上面的论述。在使用内置函数bytes()的时候,必须明确encoding的参数,不可省略。(一个字节8位,相当于两位16进制)
10、字符大小写转换
1) 用内置函数
s.upper()
s.lower()
2) 使用chr和ord
c = ord("A") # a-z : 97-122; A-Z:65-90
a = ord('c') - ord('a')
b = chr(c+a)
print(b)
11、is 和 == 的区别
1) == 是比较两个对象的内容是否相等,即两个对象的“值“”是否相等,不管两者在内存中的引用地址是否一样。
2) is 比较的是两个实例对象是不是完全相同,它们是不是同一个对象,占用的内存地址是否相同。即is比较两个条件:1.内容相同。2.内存中地址相同
12、python 迭代器、生成器、装饰器
1、迭代器 iter() 和 next()
《简介》
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
迭代器有两个基本的方法:iter() 和 next()。 前者:创建迭代器对象, 后者:输出迭代器的下一个元素
字符串,列表或元组对象都可用于创建迭代器:
>>> list=[1,2,3,4]
>>> it = iter(list) # 创建迭代器对象
>>> print (next(it)) # 输出迭代器的下一个元素
1
>>> print (next(it))
2
《创建一个迭代器对象》
iter() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 next() 方法并通过 StopIteration 异常标识迭代的完成。
next() 方法(Python 2 里是 next())会返回下一个迭代器对象。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
2、生成器(yield )
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
一个带有 yield 的函数就是一个 generator,它和普通函数不同,生成一个 generator 看起来像函数调用,但不会执行任何函数代码,直到对其调用 next()(在 for 循环中会自动调用 next())才开始执行。虽然执行流程仍按函数的流程执行,但每执行到一个 yield 语句就会中断,并返回一个迭代值,下次执行时从 yield 的下一个语句继续执行。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
while True:
try:
print (next(f), end=" ")
except StopIteration:
sys.exit()
3、装饰器(@xxx)
1、理解+创建demo
# 定义装饰器函数(实现附加功能:统计函数运算时间)
def display_time(func): # 输入是一个函数f
def wrapper(*args): # 任意个变量,实际就是 被装饰函数f 的输入
t1 = time.time() # 这里记录时间,一个在函数func前,一个在func后,所以用装饰器定义函数是比较好的选择
res = func(*args) # 将保存变量输入f中后得到的值
t2 = time.time()
print('Tatol time : {:.4f}'.format(t2-t1)) # 做差得时间差
return res # 返回时间差
return wrapper # 返回wrapper函数
功能:可以给函数附加额外功能,代码更加简洁。
装饰器本质上是一个Python函数,
它可以让其它函数在不作任何变动的情况下增加额外功能,
装饰器的返回值也是一个函数对象。
它经常用于有切面需求的场景。
比如:插入日志、性能测试、事务处理、缓存、权限校验等。
有了装饰器我们就可以抽离出大量的与函数功能无关的雷同代码进行重用。
《demo1》
def decorator(func):
def wrapper(*args, **kwargs):
print('123')
return func(*args, **kwargs)
return wrapper
@decorator # 装饰
def say_hello():
print('同学你好')
say_hello() # 结果:123 同学你好
在这段代码中,我们将一个函数 say_hello 作为参数传入函数 decorator,返回一个 wrapper 函数并赋值到 say_hello_super,此时执行 say_hello_super 相当于执行 wrapper 函数。当我们执行 wrapper 函数时会先打印 123 再执行先前传入的 func 参数也就是 say_hello 函数。注意 wrapper 的 *args 与 **kwargs 参数,这是必须的, *args 表示所有的位置参数,**kwargs 表示所有的关键字参数。之后再将其传到 func函数中, 这样保证了能完全传递所有参数。在这里,decorator 这个函数就是一个装饰器,功能是在执行被装饰的函数之前打印 123。
《demo2》
import time
# 这里是一个有具体功能的函数
# 功能函数:判断是否为质数:质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
def is_prime(num):
if num < 2:
return False
elif num == 2:
return True
else:
for i in range(2, num):
if num % i == 0:
return False
return True
# 定义装饰器函数(实现附加功能:统计函数运算时间)
def display_time(func): # 输入是一个函数f
def wrapper(*args): # 任意个变量,实际就是 被装饰函数f 的输入
t1 = time.time() # 这里记录时间,一个在函数func前,一个在func后,所以用装饰器定义函数是比较好的选择
res = func(*args) # 将保存变量输入f中后得到的值
t2 = time.time()
print('Tatol time : {:.4f}'.format(t2-t1)) # 做差得时间差
return res
return wrapper # 这里返回子函数名
# 找出范围内有多少个质数,并且输出运算时间
@display_time # 使用定义好的装饰器
def count_prime_num(maxnum):
count = 0
for i in range(2,maxnum):
if is_prime(i): # 调用判断函数
count = 1 + count
return count
count = count_prime_num(10000)
2、内置装饰器(property、staticmethod 、classmethod )
property 装饰器用于类中的函数,使得我们可以像访问属性一样来获取一个函数的返回值。(访问时不用加扩号)
staticmethod 装饰器同样是用于类中的方法,这表示这个方法将会是一个静态方法,意味着该方法可以直接被调用无需实例化,但同样意味着它没有 self 参数,也无法访问实例化后的对象。
classmethod 依旧是用于类中的方法,这表示这个方法将会是一个类方法,意味着该方法可以直接被调用无需实例化,但同样意味着它没有 self 参数,也无法访问实例化后的对象。相对于 staticmethod 的区别在于它会接收一个指向类本身的 cls 参数。
13、常用模块(os,sys,random,time)
1、os模块,文件及目录操作:os.mkdir() #创建目录,os.rmdir() # 删除目录
2、sys模块,提供对python解释器相关的操作:
sys.path
sys.stdin.readline()
sys.stdout.write(xxx)
3、time模块,时间相关:time.time() # 时间戳, time.sleep() # 暂停
4、radom模块,随机
# 随机整数:
print random.randint(1,50)
# 随机选取0到100间的偶数:
print random.randrange(0, 101, 2)
# 随机浮点数:
print random.random()
print random.uniform(1, 10)
5、re模块,正则
14、面向对象和过程的区别和优点
1、面向对象与面向过程的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了;
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
2、举例说明
面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了许多步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。
功能上的统一保证了面向对象设计的可扩展性。比如要加入悔棋的功能,如果要改动面向过程的设计,那么从输入到判断到显示这一连串的步骤都要改动,甚至步骤之间的循序都要进行大规模调整。
3、面向过程与面向对象的优缺点
面向过程
优点:性能比面向对象高,因为类调用时需要实例化(比面向对象快的的一个原因),开销比较大,比较消耗资源;比如嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是重要的因素。(性能高,开销小)
缺点:没有面向对象易维护、易复用、易扩展
面向对象
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低
15、C、C++、Java、Python 语言
C 面向过程
C++、Java、Python 面向对象
Python和Java
开发周期。在开发周期方面,Python语言无疑具有较为明显的优势,一个重要的原因在于Python语言有丰富的“库”,Python程序员可以从“造轮子”中解放出来,从而把关注点放在业务逻辑的实现上,这会在很大程度上提升程序的开发效率。
执行效率。在执行效率方面,Java语言具有一定的优势。Java语言的特点就是稳定的性能表现和较强的扩展能力,这也是为什么大型互联网平台往往更愿意采用Java编写的重要原因。
应用场景:来说Python的应用领域主要在游戏开发、搜索引擎、图形图像处理、脚本开发等。+Java的应用领域主要是服务器开发,web开发和安卓开发等。+Python和Java都各有优点,应用的领域也不同。
C++的运行效率最快,Java次之,Python最慢;C++、Java是强类型的,Python弱类型;C++需要手动释放内存,java和python都有自己的垃圾回收机制。
为什么C++运行效率快
因为C跟C++是全部翻译,再执行的语言
Java与python、php、ruby、C#是边执行边翻译的语言,
那么既然C跟C++执行效率高运行快,那为什么还要Java、python等这些语言了,
因为后者可以实现跨平台,即在Windows与Linux下都可以去执行。
两者区别一:
编译型:全部翻译,再执行,C,C++
解释型:边执行边翻译,Java、python、C#、php、ruby等
区别二:
静态型:C、C++、Java等都属于静态型语言当编写源程序的时候,出现不符合语法的规范,就会提示错误,在编译时变量的数据类型即可确定。
动态型:JavaScript、Python、Ruby等是动态型语言,在编译阶段它不会判断代码是否符合规范,在运行的时候才会去判断。
16、判断路径是否存在、不存在则创建、相对路径写法
import os
path = "./results"
if not os.path.exists(path):
os.makedirs(path)
file = open(path+'/nihao.txt','w') # 路径为字符串,可以拼接
相对路径:
.\ 表示当前所在目录, …\ 表示当前所在目录的父目录,\表示根目录
十、数据库编程接口 (pymysql)
pyton连接数据库需要先安装pymysql模块:
pip install pymysql
安装完成后导入pymysql模块:import pymysql
python连接数据库主要分五个步骤:
step1:连接数据库
step2:创建游标对象
step3:对数据库进行增删改查
step4:关闭游标
step5:关闭连接
关于commit
在使用python操作mysql时,自动提交默认为off(事件里也是将自动提交关闭的)
(1)在以下语句中需要commit
update,delete,insert等修改表中数据的需要commit
(2)在以下语句中不需要commit
create,drop,alter等修改表结构的,就不需要commit,因为内部隐藏了commit
1、连接对象
1)获取对象
import pymysql
dbname = 'mrsoft' # 数据库名称,注意和连接名区分
#1、连接数据库(主机名,用户名,密码,数据库名,字符集(或者说编码格式))
conn = pymysql.connect(
host='localhost',
user='root',
password='Madan..06',
db= dbname,
charset='utf8',
# autocommit=True, # 如果插入数据, 是否自动提交? 和conn.commit()功能一致。
)
2)连接到对象的方法
3)游标对象
还有一个 fetchall() # 用于获取结果集的全部记录
# ****python, 必须有一个游标对象, 用来给数据库发送sql语句, 并执行的.
# 2. 创建游标对象
cur = conn.cursor()
cur.execute('select version()') # .execute 执行sql语句
data = cur.fetchone() # 查询结果集中的下一条记录
print(data)
2、增删改查
注意:增删改一定要commit才算有效,且commit之后无法rollback()
sql语句中的表达式参数可以用 %s 占位符,防止SQL注入
# # 3. 对于数据库进行增删改查
# 1). ************************创建数据表**********************************
#
# cur.execute('drop table if exists books;') # 如果表事先存在则删除, 表名:books
# try:
# create_sqli = """
# CREATE TABLE books(
# id int(8) not null auto_increment,
# name varchar(50) not null,
# category varchar(50) not null,
# price decimal(10,2) default null,
# publish_time date default null,
# primary key (id)
# )engine=innodb auto_increment=1 default charset=utf8;"""
# cur.execute(create_sqli)
# except Exception as e:
# print("创建数据表失败:", e)
# else:
# print("创建数据表成功;")
## 2). *********************插入数据****************************
# try:
# insert_sqli = "insert into books values('1','python01', 'python','20.0','2021-10-10');" # 第一列 id是自增的可以不用写
# cur.execute(insert_sqli) # 执行sql
# conn.commit() # 如果是插入数据, 一定要提交数据, 不然数据库中找不到要插入的数据;
# print("插入数据成功;")
# except Exception as e:
# conn.rollback() # 发生错误时回滚
# print("插入数据失败:", e)
# # 3). *********************插入多条数据****************************
# try:
# data = [('python01', 'python','20.0','2021-10-10'),
# ('python02', 'python','30.0','2021-10-10'),
# ('python03', 'python','40.0','2021-02-10'),
# ('python04', 'python','20.5','2021-07-10')]
# insert_sqli = "insert into books(name,category,price,publish_time) values(%s, %s ,%s ,%s);" # 使用占位符%s防止sql注入
# cur.executemany(insert_sqli, data )
# except Exception as e:
# print("插入多条数据失败:", e)
# else:
# # 如果是插入数据, 一定要提交数据, 不然数据库中找不到要插入的数据;
# conn.commit()
# print("插入多条数据成功;")
# # 4). **************************数据库查询*****************************
sqli = "select * from books where id > 1"
result = cur.execute("select * from books where id > %s",0) # 默认不返回查询结果集, 返回数据记录数。
print(result)
print(cur.fetchone()) # 1). 获取下一个查询结果集;
print(cur.fetchone())
print(cur.fetchone())
print(cur.fetchmany(4)) # 2). 获取制定个数个查询结果集;
# 查询到的数据为元组类型
# print(type(cur.fetchone()))
# print(type(cur.fetchmany(4)))
info = cur.fetchall() # 3). 获取所有的查询结果的剩余部分(从游标当前位置开始)
print(info)
print(len(info))
print(cur.rowcount) # 4). 返回执行sql语句影响的行数
## 6). 修改数据
cur.execute('update books set name = %s where id = %s', ('java',5)) # update table_name set xx= xx where xx=xx
cur.execute('select * from books')
conn.commit()
print(cur.fetchall())
## 7). 删除数据
cur.execute('delete from books where id = %s', 7) # delete from table_name where xx = xx
cur.execute('select * from books')
conn.commit() # 已经提交就不能被回滚
conn.rollback()
print(cur.fetchall())
print(cur.rowcount)
# # 5). 移动游标指针
# print(cur.fetchmany(3))
# print("正在移动指针到最开始......")
# cur.scroll(0, 'absolute')
# print(cur.fetchmany(3))
# print("正在移动指针到倒数第2个......")
# cur.fetchall() # 先移动到最后
# cur.scroll(-2, mode='relative') # 然后往后退两个
# print(cur.fetchall())
# # 4. 关闭游标
cur.close()
# # 5. 关闭连接
conn.close()
十一、多线程
https://www.runoob.com/python3/python3-multithreading.html