python解释器:运行python代码的软件,主要目的就是将python代码翻译计算机硬件可以直接运行的二进制数据
python解释器类型
解释器下载与安装
集成环境Anaconda搭建
文件命名规范
注释
多行注释: “”“注释内容”""
单行注释: #
标准输出
print("输出内容") # 默认换行输出
print("输出内容") # 不换行输出
print('数据1','数据2') # 一次输出多个数据
标准输入
input("提示内容") # 从键盘输入一个信息到程序中
定义
性质
内置方法
字符串编码
*方法** | *描述* |
---|---|
code(编码方式) | 编码,将字符串转换成字节码 |
code(解码方式) | 解码,将字符串转换成字符串 |
在计算机中所有的信息最终都表示为一个二进制的字符串
在计算机种中,1 字节对应 8 位二进制数
1 字节可以组合出 256 种状态
256 中状态每一个都对应一个符号,就能表示 256 个字符
美国人制定了一套编码,用于描述英语中的字符和这 8 位二进制数的对应关系,这被称为 ASCII 码。
ASCII 码一共定义了 128 个字符
128 个字符只使用了 8 位二进制数中的后面 7 位,最前面的一位统一规定为 0
万国码Unicode:规定了世界上所有的字符都对应一个唯一的编号
UTF-8编码:对Unicode的具体实现,UTF-8规定了字符在电脑上的保存形式
可变长 可以使用 1 - 4 个字节表示一个字符 根据字符的不同变换长度
英文占1个字节,中文占3个字节。
UTF-8兼容ASCII码
转义字符
*转义符号** | *意义* |
---|---|
产生一个反斜杠符号() | |
产生一个单引号(‘) | |
产生一个双引号(“) | |
表示换行 | |
横向制表符 | |
ewline | 连续(当一行代码太长换行是使用) |
ther | 其他字符不转义,保留原有字符 |
概述
格式
列表的序列操作
列表的内置方法
dir(list) 查看列表的所有内置方法
help(list.方法名) 查看该方法的帮助文档
增加操作
删除操作
查找操作
排序
深拷贝与浅拷贝
列表推导式
定义与性质
使用{}包裹,一个key对应一个value,key和value之间使用:,一对kev,value就是一个数据,数据和数据之间使用逗号隔开.
格式: {key:value,key:value}
字典是项目开发过程中使用频率最高的一个组合数据类型。它用于存放具有映射关系的数据.
使用 dict()创建空字典,dict创建字典的三种方式
dict({key:value})
dict([(key,value),(key,value)])
dict(key=value,key=value)
字典的key:只能是不可变类型
字典中的值可以重复,但是key是不能重复的
字典的操作方法
setdefault(key,default_value) 指定key和value,如果key存在什么都不改变
pop(key) 弹出,返回并删除指定键对应的值
popitem() 随机弹出一个键值对
clear() 清空字典
del 删除整个字典,或者通过字典的key删除对应键值对;Python内置方法,不是字典独有的方法;
update({key:value}) 传递一个字典,如果key相同则覆盖,没有的key则添加
get(key, default) 以键取值,如果指定键不存在,默认返回None,可以指定返回内容
key 通过指定的key找对应的值 dict[‘key’]
keys() 以列表返回一个字典所有的键
values() 以列表返回字典中的所有值
items() 返回字典键值呈元组形式的格式
通过key获取数据和get获取数据的区别:如果key不存在,使用key获取会报错,使用get 不会报错 默认返回None 可以设置默认的返回值
集合的声明格式
性质
内置方法
双集合操作
列表: 数据量过大时不建议使用列表存储数据,取数据效率会比较低,推荐使用字典
格式:[] ,list
有序的,可以修改的,可以重复的,可以是不同类型
元组:
格式:(),tuple()
有序的,不可以修改,可以重复,可以是不同类型的数据
集合:
格式: set() ,set
无序,无法修改集合中的某一个元素,里面的数据是不重复,可以存不同类型的数据
字典:
格式:{},dict
key-value形式,无序, key不能重复,value可以重复,value可以是不同类型的,key必须是不可变类型的数据
type(1)
type("见覅额及")
函数 | 说明 |
---|---|
int(x) | 将x转换成 整型 |
float(x) | 将x转换成 浮点型 |
bool(x) | 将x转换成 布尔类型 |
str(x) | 将x转换成 字符串类型 |
chr() | 将一个整数按照utf-8编码表,转换成一个字符 |
eval() | 计算字符串中有效的python表达式 |
bool转int
int(False) # 结果是: 0
int(True) # 结果是: 1
float转int,直接将小数点后面的数删除
int(1.23) # 结果是: 1
bool转float
float(True) # 结果是: 1.0
float(Flse) # 结果是: 0.0
int转float
float(1) # 结果是: 1.0
float(30) # 结果是: 30.0
str转float,只能转纯整数型或纯浮点数值型字符串
float('123') # 结果是: 123.0
float("1.3") # 结果是: 1.3
float("积分") # 报错
把二进制数按权展开、相加即得十进制数
例如: 1010计算方式
1 ∗ 2 3 + 0 ∗ 2 2 + 1 ∗ 2 1 + 0 ∗ 2 0 1*2^3+0*2^2+1*2^1+0*2^0 1∗23+0∗22+1∗21+0∗20
函数 | 说明 |
---|---|
hex(int) | 将10进制转换成 16进制 |
oct(int) | 将10进制转换成 8进制 |
bin(int) | 将10进制转换成 2进制 |
int(str,指定的进制) | 将指定进制的字符串转换成 十进制数据 |
操作符号 | 描述 |
---|---|
+ | 加法运算符当两边都是数值时我们做加法运算如果两边都是字符串,做字符串拼接 |
- | 减法运算符 |
* | 乘法运算符两边都是数值做乘法运算粮油一遍是字符串,做字符串的复制 |
/ | 除法运算符 |
% | 取模数运算符 |
// | 整除运算符(不会四舍五入) |
** | 幂运算符,求指数运算 |
数值类型的混合运算中,类型自动升级: 会现将被操作的对象(数值)转换成,复杂度高的操作对象(数值),然后做运算 ,最终结果是,复杂度高的这个类型
复杂度优先级: bool
操作符号 | 描述 |
---|---|
+= | 自加运算,加法运算的优化版本 |
-= | 同上 |
*= | 同上 |
/= | 同上 |
%= | 同上 |
//= | 同上 |
**= | 同上 |
操作符号 | 描述 |
---|---|
> | 判断符号左侧的数据是否大于右侧的数据 |
>= | 判断符号左侧的数据是否大于等于右侧数据 |
< | 判断符号左侧的数据是否小于右侧的数据 |
<= | 判断符号左侧的数据是否小于等于右侧数据 |
== | 判断符号两侧的数据是否相等 |
!= | 判断符号两侧的数据是否不相等 |
比较运算符:数据等值比较,返回****布尔类型****的结果
| 操作符号 | 描述 |
| -------- | ---------------------------------------- |
| and | 符号两边的条件都为真(True),结果为True |
| or | 符号两边的条件都为假(False),结果为False |
| not | 符号右侧的条件,取反 |
| and | 两边为真则为真 | 其他都为假 |
| ---- | -------------- | ------------ |
| or | 两边都为假则假 | 其他都是真 |
| not | 为真结果为假 | 为假结果为真 |
优先级:or
可通过加()提升优先级
and: 如果第一个值为假 则直接输出假的值
1 and 2 —> 2
1 and 0 ---->0
0 and 1 ---->0
or: 两边有一个为真则为真,如果第一个值为真值,直接返回第一个值
0 or 1 —> 1
1 or 3 —> 1
单分支
if 条件表达式: # 只有条件表达式成立才会执行程序体
程序体
条件表达式后面一定要加 ==:==号分支内的代码段必须使用 缩进
双分支
if 条件表达式:
真区间代码段
else:
假区间代码段
条件表达式为真 执行真区间代码, 当条件表达式不成立 执行假区间代码段
多分支
if 条件表达式1:
代码段1
elif 条件表达式2:
代码段2
elif 条件3:
代码段3
else:
else代码段
判断第一个条件是否成立,如果成立则执行代码段1
如果不成立,继续判断第二个条件,如果第二个条件成立,执行代码段2,如果不成立继续向下面的条件进行判断
如果条件都不成立,执行else中的代码
else可以省略不写
嵌套分支, 分支当中嵌套分支
if 条件表达式1:
if 条件表达式2:
代码段2
else:
else 区间代码
三元表达式
格式: 变量 = 条件为真返回的结果 if 判断条件 else 条件为假返回的结果
result = "合格" if s >= 60 else "不合格"
格式
while 条件表达式:
循环的代码段
判断条件表达式是否成立,成立我们执行循环体中的代码,执行完之后不会结束,而是再次进行条件判断,如果成功继续执行循环体,当条件不成立时,循环就不在执行了
死循环
while True:
循环体代码
条件一直为真的循环,死循环,永真循环,一般情况配合break来去终止循序
循环嵌套
while 条件表达式:
while 条件表达式:
代码段
外层循环一次,内存循环需要循环结束,才能能会外层循环
for循环与while循环的区别
for循环代码格式
def 函数名([形参]):
“””注释说明”””
函数中的代码
[return] # 可有可无
形参: 定义函数时,在()中传入的
实参: 调用函数时,在()中写入的
实参和形参位置一一对应
格式
def 函数名(参数1, 参数2)
代码块
函数名(数据1, 数据2)
关键字参数
默认值参数
可变参数(*args, **kwargs)
函数自己调用自己,我们称之为递归函数
递归函数必须留有出口, 不然会报错
递归的层级 最大996
递归函数的原理: 利用压栈操作
缺点: 消耗内存, 效率比较低
优点: 逻辑直观
例如: 计算100之内的和
def sum_num(num=100):
if num == 0:
return 0
return num+sum_num(num-1)
概述
访问命名空间
命名空间加载顺序
命名空间的查找顺序
概述
内层作用域访问外层作用域的顺序
L–>E–>G–>B
*内层作用中可以访问,外层作用域当中数据*
*在外层作用域中,不能访问内层作用域中的数据*
在 Python 中,模块(module),类(class)、函数(def、lambda)会产生新的作用域
条件判断(if……else)、循环语句(for x in data)、异常捕捉不会产生作用域
在分支,循环,异常处理中声明的变量,作为范围是属于当前作用域的
abs() 绝对值函数
max() 最大值函数
map() 映射函数
filter() 过滤函数
用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表
该函数接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判断 , 然后返回 True 或 False,最后将返回 True 的元素放到新列表中
例如: 将列表lst=[1,2,3,4,5,6,7,8,0] 过滤出所有的偶数
In [24]: lst=[1,2,3,4,5,6,7,8,0]
In [25]: def fun(item):
...: if item%2 == 0:
...: return True
...:
In [26]: filter(fun,lst)
Out[26]:
In [27]: list(filter(fun, lst))
Out[27]: [2, 4, 6, 8, 0]
zip() 函数
接受任意多个可迭代对象作为参数 , 将对象中对应的元素打包成一个 tuple
返回一个可迭代的 zip 对象 . 这个可迭代对象可以使用循环的方式列出其元素
若多个可迭代对象的长度不一致 , 则所返回的列表与长度最短的可迭代对象相同
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ey5GOWZI-1598969697157)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200819194514705.png)]
案例: 通过t1=(“a”,”b”),t2=(“c”,”d”) 生成[{“a”:”c”},{“b”:”d”}]
t1 = ("a","b")
t2 = ("c","d")
res = list(zip(t1,t2))
def fun(item):
d = dict()
d[item[0]] = item[1]
return d
print(list(map(fun,res)))
匿名函数的定义使用lambda
本质为一个函数,没有名字的函数,针对简单函数提供的一种简洁的操作语法
语法格式
变量 = lambda [参数1,参数2…] : 表达式
参数:可选,通常以逗号分隔的变量表达式形式,也就是位置参数
注意 : 表达式中不能包含 循环,return , 可以包含 if…else… 语句(三元表达式)
表达式计算的结果直接返回
匿名函数用处: 一般配合高阶函数使用
优点: 代码简洁,
缺点: 可读性差难于理解, 不推荐使用
案例: 使用filter函数过滤所有的奇数 lst = [1,2,3,4,5,6,7,8,9,10]
In [8]: list(filter(lambda x : x%2==0, lst))
Out[8]: [2, 4, 6, 8, 10]
lambda 表达式也会产生一个新的局部作用域。在 def 定义的函数中嵌套 labmbda 表达式能够看到所有 def 定义的函数中可用的变量
# 例1
def make_actions():
acts = []
for i in range(5):
acts.append(lambda x: i ** x)
return acts
funcs = make_actions()
print(funcs[0](2)) # 16
print(funcs[1](2)) # 16
print(funcs[2](2)) # 16
# 例2
def make_actions():
acts = []
for i in range(5):
acts.append(lambda x, y=1: i ** x)
return acts
funcs = make_actions()
print(funcs[0](2)) # 0
print(funcs[1](2)) # 1
print(funcs[2](2)) # 4
概述
闭包函数的必要条件
闭包函数的执行
def fun():
name = "liming"
def inner():
print(name)
age = 12
return name, age
return inner
if __name__ == '__main__':
# 调用外层函数 fun , 把内层函数inner返回给inner_function变量
# inner只是赋值给了inner_function, 没有被调用
# 注意此时name依然存在,没有被释放, 因为内层函数引用了name的值,
# 且内层函数赋值给了全局变量inner_function
inner_function = fun() # 相当于 inner_function = inner
# 调用内层函数inner
print(inner_function()) # 相当于 inner()
闭包的作用
应用场景:
在项目开发中可以使用闭包函数,对程序进行扩展
例如: 检测某个函数的执行时间
import time
def execution_time(func):
def inner():
start_time = time.time()
func()
end_time = time.time()
print(f'函数执行共用时{end_time-start_time}')
return inner
def program():
print("这是个一程序")
time.sleep(2)
print("执行结束")
if __name__ == '__main__':
# 调用闭包的外层函数,传入要检测的函数, 将内层函数inner返回给inner_function
inner_function = execution_time(program)
# 调用inner_function, 即inner函数
inner_function()
概述
作用
格式
@装饰器名称
被装饰的函数
def outer(func):
def inner(*args, **kwargs):
# 被装饰函数之前执行的代码
ret = func(*args, **kwargs) # 被装饰的函数
# 被装饰函数之后执行的代码
return ret
return inner
@outer
def function(*args, **kwargs):
pass
案例1: 修改年龄(带参数的装饰器)
def outer(fun):
def inner(name, age):
print(f"修改前的年龄{age}")
age -= 2
fun(name, age)
return inner
@outer # 相当于 change_age = outer(change_age) 即把inner赋值给change_age
def change_age(name, age):
print(f"我是{name}, 今年{age}岁")
if __name__ == '__main__':
change_age("李明", 20)
案例2: 测试程序执行时间( 带返回值的装饰器)
import time
def outer(func):
def inner(*args, **kwargs):
start_time = time.time()
ret = func(*args, **kwargs) # 被装饰的函数
end_time = time.time()
print(f'函数执行共用时{end_time-start_time}')
return ret
return inner
@outer
def function():
print("这是个一程序")
time.sleep(2)
print("执行结束")
return "ok"
if __name__ == '__main__':
ret = function()
print(ret)
绝对引入
当引入一个模块时,python解析器对模块位置的搜索顺序是
我们导入的范围也可以通过修改sys.path这个列表获得暂时的修改。例如通过 sys.path.append()添加目录,导入额外目录的模块。
列表是有序的,当搜索的过程当中,在第一个路径下搜索到了,就停止搜索。而且sys.path第一个路 径是脚本的当前路径,所以禁止大家讲自己的脚本命名成模块的名称。因此需要注意的是:自己模块命名的时候不能和系统的模块名称相同
基本引入方式
import 模块名
import 模块名,模块名
给模块起别名
格式: import 模块名 as 别名
直接引入模块中的内容
from 模块名 import 指定功能
from 模块名 import 功能1,功能2
from 模块名 import * (不推荐)
相对引入
相对引入必须给路径
格式
格式:
from . import 模块名
from . import 模块名 as 别名
from .模块名 import 具体内容
注意:从当前文件夹下导入 注意启动文件时必须要带路径
python -m 文件夹.要执行的python文件名
包 (package),程序包的简称,在 Python 中就是一个文件夹,通过文件夹管理 Python
模块的操作方式
将不同功能的模块放到不同的文件夹中去管理,这个文件夹就是我们的程序包
python中的包和普通的文件夹不同,Python中标准的包,包含了一个__init__.py的文件
一般__init__.py这个模块成为包声明模块
绝对引入
基本引入方式[推荐]
起别名
直接引入包
格式: import 包名
注意: 需要修改引入包文件夹下的 init.py文件
指定哪些模块可以被引入
一次性引入指定包中所有的模块
格式: from 包名 import *
注意: 修改包下的__init__.py文件
1方案:添加 from . import 需要导入的模块
2方案:添加 all = [“模块名”] 引入导入的模块
相对引入
格式: from .包名 import 模块名
注意:需要在命令行项目同级目录下执行 python -m 项目名.主文件名
备注:当前包被其他模块通过 import 引入使用时,init.py 中的代码会自动执行
name 属性:
如果当前文件 仅仅作为python文件执行,name 的值 “mian”
面向对象
面向对象就是我们说的 面向对象编程(Object Oriented Programming,OOP):
就是一种编程****思想****,解决问题的一种思路
面向对象,解决问题时关注的不是解决问题的步骤和过程,关注的是参与解决问题的对象,以及他们的行为
优点: 生活的还原度高,可以表示生活中所有的事物,描述每种类型的事物的****特征*和*行为**** 可以解决较为复杂的问题,功能的拓展性非常好
缺点: 在还原某些场景时,没有直接去解决问题,而是首先表示这些参与的对象类型,开始编写代码时较为复杂,准备时间较长. 功能的稳定性相对不足 面向对象效率要低于面向过程
适用场景: 对软件功能的扩展性要求高,但是稳定性要求一般的项目
面向过程
面向过程和面向对象的区别
Python中提供了一个关键字 class 来声明一个类
基本语法:
class 类名:
“””类的文档注释”””
def __init__(self,name):
“””声明属性的方法”””
# 自定义属性: 固定语法
self.name = name
def study(self):
“””方法文档注释”””
print(f“””{self.name}正在学习中..”””)
类的声明规则:
封装
定义
属性的封装方法(私有化属性)
class Person:
def __init__(self,name,gender,gae):
self.name=name # 公共属性
self._gender = gender #受保护属性:约定私有属性,规范上要求不要直接访问
self.__age = age # 私有属性: 语法上不能通过属性名称直接访问
私有属性可以访问: 对像名._类名__属性名
面试题: 请解释一下为什么python中面向对象开发时,两个下划线开头的属性不能直接访问,编写代码就是为了来运算的,不能访问还有什么意义
属性的访问方法
属性私有化之后, 只能在当前类内部访问, 为了数据的可用性,一般回提供私有访问属性的操作方法
语法格式
获取__name属性的方法
def get_name(self,name): #get_属性名()...
return self.__name
修改__name属性方法
def set_name(self,name): #set_属性名()...
self.__name = name
添加访问限制
外界通过set/get方法访问数据时, 可以给get/set添加设置访问条件
添加set_age属性的方法:
def set_age(self, age)
if 判断是否合法:
self.__age = age
return '非法数据要进行的操作'
添加get_name属性方法:
def get_name(self):
if 判断是否有权限
return self.__name
return "没有权限要进行的操作"
总结:
封装拓展: 自定义属性
继承
定义: 面向对象的三大特性之一, 主要体现了基于类的代码复用, 通过继承关系可以关联两个类
基本语法:
class Father:
“””父类”””
....
class Son(Father):
“””子类”””
....
调用父类中的初始化方法, 子类中编写初始化方法, 父类中的方法不会直接调用, 必需手动调用
def __init__(self,name,age,gender,level):
# 初始化父类方法
super().__init__(name,age,gender)
方法的覆盖/方法的重写
继承体现了开发原则中的里氏代换原则,所有出现父类的地方否可以使用子类进行替换
继承的特征:
单继承: 一个类只能继承一个父类的方式, 一个父类可以被多个子类继承
多继承: 一个子类继承多个父类的方式
语法格式
class Case(A,B,C):
pass
存在的问题: 一个子类继承多个父类时, 该子类继承类所有的父类方法, 但是如果其中多个父类拥有同名的方法会出现一些问题
例如:
class A:
def say(self):
print("A")
class B:
def say(self):
print("B")
class C(A, B):
pass
c = C()
c.say() # 结果是 A
多继承模式下继承顺序, 使用了广度优先的查询原则
python提供了 mro()方法用于确定继承关系中属性和方法的查询操作顺序
案例:
class F:
def say(self):
print("我是F")
class A(F):
def say(self):
super().say()
print("我是A")
class B(F):
def say(self):
super().say()
print("我是B")
class C(A,B):
def say(self):
super().say()
print("我是C")
c = C()
c.say() # 结果是什么 B A F C
# 可以通过 类名.mro() 方法查看继承的顺序
多态
封装:
学会操作语法即可,能看懂什么样的操作方式是封装
两个下划线开头,对属性或者方法进行封装操作
给私有属性提供访问方法
封装实际项目中,开发应用程序时很少些,编写通用底层模块时使用比较多
继承:
多态
概述
实例属性
声明
实例属性的声明,包含在类型中的 init() 初始化方法中,使用 self 关键字将属性绑定到当前对象上
例如:
def __init__(self,title,content):
"""实例属性"""
self.title = title
self.content = content
访问
实例属性在类型内部可以通过self关键字引用, 在类型外部可以通过对象的引用变量访问和修改
例如:
class Article:
def __init__(self,title,content):
"""实例属性"""
self.title = title
self.content = content
def save(self):
print(f"{self.title}正在保存")
article = Article("标题","内容..")
print(article.title)
类属性
声明
类属性声明在类型的内部, 方法的外部
例如:
class Article:
# 文章最大字数限制
content_max_size = 120
访问
类属性能被当前类型的所有对象访问, 或者能直接通过类名称访问
例如:
# 对象名访问
print(article.content_max_size)
# 类名访问
print(Article.content_max_size)
修改
总结:
类属性:
当前类的属性
声明位置:在类的内部,方法的外面
访问数据:当前类型名称 当前类创建的所有对象
修改数据:通过当前类名去修改
实例属性:
当前实例的属性
声明位置: 声明在__init__(self)中
访问数据: 只能被当前对象访问
修改数据:只能被当前对象修改
*魔法方法* | *描述* |
---|---|
hasattr(obj, name) | 判断是否包含名称为name的属性 |
setattr(obj, name, value) | 给名称为name的属性设置value数据 |
getattr(obj, name) | 获取名称为name的属性的具体数据 |
delattr(obj, name) | 删除名称为name的属性 |
In [4]: class A:
...: def __init__(self, name, age):
...: self.name = name
...: self.age = age
...: def say(self):
...: print("are you see")
...:
In [5]: a = A('张三', 19)
In [6]: hasattr(a, 'age')
Out[6]: True
In [7]: getattr(a, 'age')
Out[7]: 19
In [8]: setattr(a, 'age', 20)
In [9]: a.age
Out[9]: 20
In [10]: delattr(a, 'age')
In [11]: a.age
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
----> 1 a.age
AttributeError: 'A' object has no attribute 'age'
设计模式概述: 是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
是软件开发人员在软件开发过程中面临的一般问题的解决方案, 常见的设计模式有23 种
定义
基本语法
以类为例, 重复创建同一个对象
class MyData:
__ins = None
def __new__(cls, *args, **kwargs):
if not cls.__ins:
cls.__ins = objects.__new__(cls)
return cls.__ins
当我们创建对象时, 创建出来的对象都是同一个对象
定义
基本语法
class Motorbike:
def __init__(self):
self.brand = "摩托车"
def run(self):
print(f"开始我喜爱的{self.brand}车")
class Minibus:
def __init__(self):
self.brand = "面包车"
def run(self):
print(f"开始我喜爱的{self.brand}车")
class Sedan:
def __init__(self):
self.brand = "小轿车"
def run(self):
print(f"开始我喜爱的{self.brand}车")
# 定义工厂类
class Factory:
def buy_vehicle(selfm,brand):
if brand == 1:
return Motorbike()
elif brand == 2:
return Minibus()
elif brand == 3:
return Sedan()
else:
return "没有你需要的车"
factory = Factory()
# 根据传递的参数来选择创建不同的对象
moto = factory.buy_vehicle(1)
moto.run()
python操作文件
读取操作:
写入操作
with语法
将文件的操作步骤进行优化处理,不需要手动关闭
基本语法
with open(filename, '读写方式', encoding='编码格式') as f:
操作文件
csv文件读写
python自带csv模块, 可以对csv文件进行读写操作
基本语法
import csv
# 向文件写入数据: csv.writer对象
with open(文件,mode=”w”,encode=””) as f:
# 获取writer对象
writer = csv.writer(f)
# 写入一行数据 列表类型
writer.writerow(lst)
# 写入多行数据 二维列表
writer.writerows(写入多行数据)
# 读取数据: reader对象
with open(文件,mode=’r,’,encode=””) as f:
# 获取reader对象
reader = csv.reader(f)
# 打印读取的文件
for i in reader:
print(i)
乱码
*方法* | *描述* |
---|---|
os.rename(old,new) | 重命名文件 |
os.remove(filepath) | 删除文件 |
os.mkdir(path) | 创建目录 |
os.makedirs(path) | 创建多级目录 |
os.remdir(path) | 删除目录,目录必须为空 |
os.removedirs(path) | 删除多级空目录 |
os.getcwd() | 获取当前工作路径 |
os.listdir() | 默认获取当前目录下文件列表,通过传参可以指定路径 |
os.chdir(path) | 切换所在路径 |
In [12]: import os
In [13]: os.cpu_count()
Out[13]: 2
In [14]: os.system('python')
Python 3.5.2 (default, Apr 16 2020, 17:47:17)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
Out[14]: 0
In [15]: ls
app_private_key.pem ch08www/ mod_wsgi-4.6.4/ shop/
app_public_key.pem code/ mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz wechat.py
In [16]: os.rename('./wechat.py', 'wechet.py')
In [17]: ls
app_private_key.pem ch08www/ mod_wsgi-4.6.4/ shop/
app_public_key.pem code/ mongodb-linux-x86_64-ubuntu1604-4.2.8.tgz wechet.py
os.path.exits(path) | 判断文件是否存在 |
---|---|
os.path.isfile(path) | 判断是否是文件 |
os.path.isdir(path) | 判断是否是目录 |
os.path.abspath(相对路径) | 获取绝对路径 |
os.path.isabs(path) | 判断是否是绝对路径 |
os.path.basename(path) | 获取路径中的最后一部分内容 |
os.path.dirname(path) | 获取父目录部分 |
os.path.getsize(path) | 获取文件大小 返回的是字节 |
os.path.join(path1, path2) | 对两个路径进行拼接 |
概述
常见异常
异常处理
捕获单个异常
语法格式
try:
...代码...
....
except 异常类型:
...处理异常的代码...
程序从上往下执行,先执行try中的代码,如果代码报错,不会据需向下执行,而是执行except中的代码, 如果try中的代码俺没有报错,except中的代码不会执行
捕获多个异常
语法格式
多分支结构:
try:
...代码...
....
except 异常类型1:
...处理异常的代码...
except 异常类型2:
异常类型2处理代码
except 异常类型3:
异常捕获3
.......
程序从上往下执行,先执行try中的代码,如果代码没有报错,except代码都不会执行
如果try代码出错了,程序会依次和except中的异常类型比较,执行对应异常类型中的处理程序,其他except不在执行,如果都不符合,程序抛出异常终止.
根据不同的异常,单独处理
元组结构:
try:
代码
except(异常1,异常2,异常3) as 别名:
捕获异常
try只要异常,只要异常类型符合元组中的某一个类型,直接执行异常捕获,
捕获所有异常
语法格式
try:
执行的代码
except:
执行异常
# except后面不写异常类型, 表示可以捕获所有异常信息
或者
try:
执行的代码
except Exception:
执行异常
# Exception 是所有异常的父异常,try抛出的异常,Exceptio都能捕获
else格式
try:
执行的代码
except 异常类型 as 变量名:
执行异常
....
else:
...代码...
try…finally 格式
try:
执行的代码
except 异常类型 as 变量名:
执行异常
....
finally:
...代码...
在实际业务中我们可以根据用户需求和实际情况手动抛出异常
python中提供了Exception类 ,来实例化异常
格式 | 描述 |
---|---|
raise Exception(“异常提示信息”) | 当程序执行到raise 时,会自动的触发异常,让程序结束 |
我们也可以根据系统提供的Exception类 自定义自己的异常类
class name(Exception):
def __init__(self):
pass
def __str__(self):
return “异常提示信息”
正在运行的一个程序就是一个进程
程序只有一个, 进程可以有多个
进程是系统进行资源分配的最小单位, 每一个进程都有自己的独立的内存和资源
是程序执行的最小单位
进程和进程之间相互独立, 资源不共享
线程是进程中的一个执行线路,或者是流程
一个进程中至少有一个主线程, 可以包含多个线程
线程是任务调度的最小单位, 程序真正执行的时候,调用的是线程
多线程之间共享进程资源,相对于进程来说线程更节省资源
进程之间的切换重量级, 线程之间的切换轻量级
import threading
import time
def dance():
for i in range(3):
time.sleep(1)
print("=====唱歌======")
def song():
for i in range(3):
time.sleep(1)
print("=====跳舞======")
if __name__ == '__main__':
t1 = threading.Thread(target=dance)
t2 = threading.Thread(target=song)
t1.start()
t2.start()
import threading
import time
def dance(name):
for i in range(3):
time.sleep(1)
print(f"====={name}唱歌======")
def song(name):
for i in range(3):
time.sleep(1)
print(f"====={name}跳舞======")
if __name__ == '__main__':
t1 = threading.Thread(target=dance, args=('laoeang',))
t2 = threading.Thread(target=song, args=('xiaoli',))
t1.start()
t2.start()
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name):
super().__init__()
self.name = name
def run(self):
print(f"{self.name}唱了一首歌")
time.sleep(1)
if __name__ == "__main__":
t1 = MyThread("xiaowang")
t2 = MyThread("xiaoli")
t1.start()
t2.start()
getName() 获取线程的名称
setName() 设置线程的名称
注意: 在继承的方式中, 会和name属性冲突, 传参时避免使用name属性名
isAlive/is_alive(): 返回当前线程的状态, 如果正在执行返回True, 如果没有执行或者执行结束返回False
import threading
import time
class MyThread(threading.Thread):
def __init__(self, username):
super().__init__()
self.username = username
def run(self):
print(f"{self.username}唱了一首歌")
time.sleep(1)
if __name__ == "__main__":
t1 = MyThread("xiaowang")
t2 = MyThread("xiaoli")
# 获取t1和t2的线程的名字
print(t1.getName())
print(t2.getName())
# 判断t1是否活着
print(t1.is_alive())
t1.start()
print()
print(t1.is_alive())
t2.start()
# 设置t1的名字
t1.setName("t1")
print()
print(t1.getName())
# 输出
Thread-1
Thread-2
False
xiaowang唱了一首歌
True
xiaoli唱了一首歌
t1
[Finished in 1.1s]
等待其他线程执行完成后主线程才会继续执行,
可以设置等待时间timeout, 如果超过改时间,主线程不会等待
import threading
import time
def func1():
time.sleep(1)
print("我是线程 t1")
def func2():
time.sleep(1)
print("我是线程 t2")
if __name__ == '__main__':
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t1.join()
t2.start()
print("我是主线程")
当我们的主线程执行结束, 不管守护进程是否执行结束,都强制终止
守护线程的设置一定是在开启线程之前
import threading
import time
def func1():
time.sleep(2)
print("我是线程 t1")
def func2():
time.sleep(1)
print("我是线程 t2")
if __name__ == '__main__':
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.setDaemon(True)
t1.start()
t2.start()
print("我是主线程")
# t1没有被输出, t1的等待时长较长, 主线程执行结束, t1还没执行完
多线程开发时, 共享全局变量, 会带来资源的竞争, 也就是出现了数据的不安全
产生原因: 多个线程同时访问同一个资源, 我们没有对数据进行保护, 造成数据破坏, 导致我们的线程的结果不可预期, 这种现象称为: 数据不安全
解决方法: 同步处理, 加锁
例如: 售票系统
import threading
import time
tackets = 10
def func():
global tackets
while tackets > 0:
tackets -= 1
time.sleep(0.1)
print(f"窗口1售出了一张票, 还剩{tackets}张")
def func1():
global tackets
while tackets > 0:
tackets -= 1
time.sleep(0.1)
print(f"窗口1售出了一张票, 还剩{tackets}张")
if __name__ == '__main__':
t1 = threading.Thread(target=func)
t2 = threading.Thread(target=func1)
t1.start()
t2.start()
某一个线程需要修改数据前, 现将其锁定, 此时资源属于锁定状态, 其他线程是不能对这个数据进行操作的, 直到当前线程将锁释放, 其他线程将当前数据锁定, 进行操作,操作完成释放锁,
每一次只能有一个线程进行写入操作, 从而保证数据的安全, 但是会牺牲效率
threading.Lock() 实现锁
acquire() 锁定
release() 释放
优点: 确保了某段关键代码只能由一个线程从头到尾完整的执行
缺点: 阻止了多线程并发执行, 包含锁的某段代码实际上只能以单线程模式执行, 效率大大降低了
例如: 多人卖票窗口
import threading
import time
tackets = 1000
def func(name):
global tackets
while tackets > 1:
if lock.acquire():
tackets -= 1
if tackets < 0: # 判断票数, 防止多卖
break
time.sleep(0.1)
print(f"{name}售出了一张票, 还剩{tackets}张")
lock.release()
if __name__ == '__main__':
lock = threading.Lock()
t1 = threading.Thread(target=func, args=("t1",))
t2 = threading.Thread(target=func, args=("t2",))
t3 = threading.Thread(target=func, args=("t3",))
t1.start()
t2.start()
t3.start()
由于可以存在多个锁, 不同的线程持有不同的锁,并试图获取对方持有的锁时, 可能会造成死锁
在多个线程共享资源的时候, 如果两个线程分别占有一部分资源, 并且同时等待对方资源, 就会造成死锁现象
锁嵌套也会造成死锁
非全局变量不需要加锁
对于全局变量,在多线程中要注意数据错乱现象
在多线程开发中,全局变量是多个线程都共享的数据,而局部变量是各自线程的,是非共享的
import threading
import time
def func1():
print("func1")
if lock1.acquire():
print("t1锁上了")
time.sleep(0.1)
if lock2.acquire(): # 此时会阻塞, 因为这个已经被fun2抢先上锁了
print("t2锁上了")
lock2.release()
print("t2释放")
lock1.release()
print("t1释放")
def func2():
print("func2")
if lock2.acquire():
print("t2锁上了")
time.sleep(0.1)
if lock1.acquire(): # 此时会阻塞, 因为这个已经被fun2抢先上锁了
print("t1锁上了")
lock2.release()
print("t1释放")
lock1.release()
print("t2释放")
if __name__ == '__main__':
lock1 = threading.Lock()
lock2 = threading.Lock()
t1 = threading.Thread(target=func1)
t2 = threading.Thread(target=func2)
t1.start()
t2.start()
队列
python中的 queue模块中提供了同步的\数据安全的队列类,
FIFO 先入先出队列
LIFO 后入先出队列
PriorityQueue 优先级队列
这些队列都实现了锁, 能够在多线程中直接使用, 可以使用队列来实现线程间的同步
python2 和 python 队列的区别
from Queue import Queue # python2
from queue import Queue # python3
基本使用
from queue import Queue
# 先入先出
q = Queue() # 声明一个先进先出队列
# q.empty() 检测是否为空
# q.full() 检测是否存满 满了返回True
# q.qsize() 获取队列中数据的个数
# q.put() 存放数据
# q.get() 获取数据 如果数据不存在 程序阻塞
# q.get_nowait() 获取数据不等待
# q = Queue(maxsize=3) # 声明指定长度的队列
# 优先级队列
import queue
q = ProprityQueue()
q = queue.PriorityQueue()
q.put((1,'123'))
# 先入后出
q = queue.LeftQueue()
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题
该模式通过平衡生产者线程和消费线程的工作能力来提高程序的整体处理数据的速度
为什么要使用生产者和消费者模式?
什么是生产者消费者模式?
案例: 包子铺
import threading
import queue
import time
num = 0
# 生产者线程
def func1(name):
global num
while True:
num += 1
q.put(f"{num}号包子")
print(f"{name}完成{num}号包子")
# 消费者线程
def func2(name):
while True:
res = q.get()
print(f"{name}获取了{res},并一口吃了这个包子")
time.sleep(0.1)
if __name__ == '__main__':
q = queue.Queue(10)
t1 = threading.Thread(target=func1, args=("王大厨",))
t2 = threading.Thread(target=func1, args=("李大厨",))
t3 = threading.Thread(target=func2, args=("小王",))
t1.start()
t2.start()
t3.start()
在多线程环境下,每个线程都有自己的数据。一个线程使用自己的局部变量比使用全局变量好,因为局部变量只有线程自己能看见,不会影响其他线程,而全局变量的修改必须加锁, 加锁会导致效率变低
使用局部变量: 如果函数有多层函数调用,在最里层函数需要使用这个数据,中间函数的调用过程都必须传参数
threadLocal可以解决以上问题
一个threadLocal变量虽然是全局变量, 但每个线程都只能读写自己线程的独立副本, 互不干扰, threadLocal解决了参数在一个线程中各个函数之间互相传递的问题
正则表达式: 也称为规则表达式, 英文名称Regular Expression, 专门用于进行文本检索、匹配、替代等操作的一种技术。正则表达式是一种独立的技术, 并不是某种编程语言独有的
元字符 | 描述 |
---|---|
\ | 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\n”匹配\n。“\n”匹配换行符。序列“\”匹配“\”而“(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。 |
^ | 匹配输入字行首。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。 |
$ | 匹配输入行尾。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。 |
* | 匹配前面的子表达式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价于{0,1}。 |
{ n} | n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。 |
{ n,} | n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。 |
{ n,m} | m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。 |
.点 | 匹配除“\n”和"\r"之外的任何单个字符。要匹配包括“\n”和"\r"在内的任何字符,请使用像“[\s\S]”的模式。 |
(pattern) | 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“(”或“)”。 |
(?:pattern) | 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。 |
(?=pattern) | 非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。 |
(?<=pattern) | 非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。*python的正则表达式没有完全按照正则表达式规范实现,所以一些高级特性建议使用其他语言如java、scala等 |
(? | 非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(? |
x|y | 匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[z|f]ood”则匹配“zood”或“food”。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”任一字符。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身. |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。 |
\b | 匹配一个单词的边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”;“\b1_”可以匹配“1_23”中的“1_”,但不能匹配“21_3”中的“1_”。 |
\B | 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。 |
\d | 匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持 |
\D | 匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持 |
\f | 匹配一个换页符。等价于\x0c和\cL。 |
\n | 匹配一个换行符。等价于\x0a和\cJ。 |
\r | 匹配一个回车符。等价于\x0d和\cM。 |
\s | 匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。 |
\S | 匹配任何可见字符。等价于[^ \f\n\r\t\v]。 |
\t | 匹配一个制表符。等价于\x09和\cI。 |
\v | 匹配一个垂直制表符。等价于\x0b和\cK。 |
\w | 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。 |
\W | 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。 |
\xn | 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“\x41”匹配“A”。“\x041”则等价于“\x04&1”。正则表达式中可以使用ASCII编码。 |
*num* | 匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。 |
*n* | 标识一个八进制转义值或一个向后引用。如果*n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n*为一个八进制转义值。 |
*nm* | 标识一个八进制转义值或一个向后引用。如果*nm之前至少有nm个获得子表达式,则nm为向后引用。如果*nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则*nm将匹配八进制转义值nm*。 |
*nml* | 如果n为八进制数字(0-7),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
\un | 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,\u00A9匹配版权符号(©)。 |
\p{P} | 小写 p 是 property 的意思,表示 Unicode 属性,用于 Unicode 正表达式的前缀。中括号内的“P”表示Unicode 字符集七个字符属性之一:标点字符。其他六个属性:L:字母;M:标记符号(一般不会单独出现);Z:分隔符(比如空格、换行等);S:符号(比如数学符号、货币符号等);N:数字(比如阿拉伯数字、罗马数字等);C:其他字符。*注:此语法部分语言不支持,例:javascript。 |
<> | 匹配词(word)的开始(<)和结束(>)。例如正则表达式 |
( ) | 将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。 |
| | 将两个匹配条件进行逻辑“或”(or)运算。例如正则表达式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:这个元字符不是所有的软件都支持的。 |
贪婪模式:正则表达式匹配的一种模式,速度快,但是匹配的内容会从字符串两头向中间搜索匹配,一次尽可能多的匹配符合条件的字符串,一旦匹配选中,就不继续向字符串中间搜索了.
懒惰模式:从目标字符串按照顺序从头到位进行检索匹配,尽可能的检索到最小范围的匹配结果,语法结构是在贪婪模式的表达式后面加上一个符号?即可
正则表达式中加?和不加?的区别
什么是迭代对象
什么是迭代器
迭代器的方法
迭代器特点
只定义一个迭代器
python中一边循环, 一边计算的机制, 成为生成器, 生成器本质就是迭代器
为什么要使用生成器
创建生成器的两种格式
生成器表达式
生成器函数
def func():
print("开始")
yield 1
print("第二个")
yield 2
生成器函数执行结束后会得到一个生成器返回值,并不会执行函数体, 使用next()之后才会执行函数体, 并且获得返回值
send() 获取下一个值得结果, 和next()基本一样, 但是在获取下一个值的时候给上一个yield位置传递一个数据
yield form 循环遍历容器类型
for i in range(4):
yield
等价于
yield from range(4)
软件测试是一种实际输出与预期输出之间的审核或者比较过程。
单元测试
单元测试中核心概念
unittest 使用步骤
(1)导入unittest模块,被测文件或者其中的类
(2)创建一个测试类,被继承unittest.TestCase
(3)重写setUp和tearDown方法(如果有初始化条件和结束条件)
(4)定义测试函数,函数名以test_开头。测试用例
(5)调用unittset.main()方法运行测试用例--------无此方法也是可以运行
断言Assert----结果对比的函数
设置断言,当一条测试用例执行失败,不会影响其他测试用例的执行
*Method*** | *Checks that* | *New In* |
---|---|---|
sertEqual(a,b):相等 | a == b | |
sertNotEqual(a,b) | a != b | |
sertTrue(x) | bool(x) is True | |
sertFalse(x) | bool(x) is False | |
sertIs(a,b) | a is b:判断是否是同一对象(id(a)) | 3.1 |
serNottIs(a,b) | a is not b | 3.1 |
sertIsNone(x) | x is None | 3.1 |
sertIsNotNone(x) | x is not None | 3.1 |
sertIn(a,b):a是否在b中 | a in b | 3.1 |
sertNotIn(a,b) | a not in b | 3.1 |
sertIsInstance(a,b):实例对象 | isInstance(a,b) | 3.2 |
sertNotIsInstance(a,b) | not isInstance(a,b) | 3.2 |
Python2中的异常处理语法
try:
...
except Exception, e:
...
python3中异常处理语法
try:
...
except Exception as e:
...
操作系统简称OS是架构在硬件基础上的系统软件, 主要用于管理计算机资源和软件资源的计算机程序, 操作系统的主要职责就是调度硬件资源和CPU、内存、硬盘等完成软件程序的数据运算, 同时调度输入设备、输出设备完成和用户之间的交互过程
命令的基本格式: 命令 【-选项】【参数】
帮助命令
系统常见命令:
clear: 清屏, 快捷方式:ctrl+l
ls:用于查看指定路径下的文件
pwd:用于打印展示当前目录所在的路径
cd : 用于在命令行切换不同的路径
ifconfig : linux系统中查看网卡网路信息的命令
poweroff:关机命令
reboot:立即重启计算机
shutdown:关机命令
grep:用于过滤搜索特定字符,常配合管道命令使用
|:管道
find:查找文件
echo :用于在界面上显示后续的提示信息, 经常用来和定向符>一起使用创建文件
文件操作命令
文件操作命令,主要用于文件/目录的管理,包含文件的创建、重命名以及删除,文件夹的创建,重命名以及删除,文件/目录的复制、剪切等
文件内容查看命令
cat 查看文件内容
head 头部浏览,查看文本文件头部内容,默认查看10行
tail 查看文本文件尾部内容, 默认查看10行
more 分页查看
more file 分页查看文件能容
more +n file 设定从第n行开始显示file内容
more +/string file 从包含string的前两行开始显示
述 |
---|
下滚动一页内容 |
向上滚动一页内容 |
下滚动一行内容 |
退出浏览 |
展示当前行号 |
展示当前文件名和当前行号 |
less 分页浏览文件内容, 类似more命令
less file 分页浏览file
less -N file 分页浏览file,并展示行号
less -m file 分页浏览file, 并显示百分比
描述 |
---|
向前滚动一页 |
向后滚动一页 |
向前滚动一行 |
向后滚动一行 |
移动到最后一行 |
移动到第一行 |
ng |
ng |
退出 |
sort 排序浏览, 将以默认的方式将文本文件的第一列以ASCII码的次序排列, 默认升序
sed 是一个流式编辑器功能非常强大
打印包含string字符的行
sed -n "/string/p" file
获取指定行内容
sed -n '1,5p' file # 打印第1-5行内容
sed -n "3,5{=;p}" file # 打印第3-5行, 并且打印行号
sed -n "10p" file # 打印第十行内容
压缩命令
压缩解压缩在操作系统中一般称之为文件归档,也就是按照某种指定格式将文件整理出来
tar:可以将多个文件打包成一个文件,也可以将打包的文件拆分为多个文件
-c 创建归档文件(用于归档)
-x 解压(用于解压)
-v 显示归档过程(可选)
-f 指定文件(必须写,必须写在其他参数后面)
-t 查看归档文件中所有文件(了解)
-z 是指定解压缩的方式为 gzip 的编码方式 解压缩文件
-J 指定解压缩方式为xz 的编码方式 解压缩文件
tar -cvf target.tar file1 file2 :将多个文件打包成target.tar文件
tar -tvf target.tar:查看target.tar包文件中包含的文件列表
tar -xvf target.tar: 将target.tar包中的文件释放到当前目录
gzip:按照比例将文件进行压缩的命令, 通常和tar归档命令一起使用,有tar归档,gzip将这个归档的文件进行整理
bzip2:用于文件压缩操作的常见命令
zip : 用于通用压缩,主要和windows操作系统平台之间的通用压缩格式
xz: 命令也是一个文件打包压缩时经常遇到的命令,经常和tar命令一起使用
权限管理命令
用户管理命令
系统管理命令
软件管理命令
突发性任务 atd 临时性的一次性的,只执行一次
查看任务是否启动
systemctl status atd
编辑突发任务
min: 分钟
days : 天
17:00 2020-9-5 指定年月日和时分去执行任务
例如:
at now+1min 一分钟后执行
at 15:00 下午3点执行
快捷键
定时任务 crontab
周期性循环执行, 一般用于定期删除日志和备份文件,定期爬取数据
查看服务有没有启动
crontab -u root -e
格式
* * * * * 要执行的命令
六个*分别代表 分 时 日 月 周
分钟: 0-59
时: 0-23
月: 1-12
周: 0-7 0和7都代表周日
/ 代表频率
, 离散的数据
如果定时任务执行的脚本有输出,或者脚本有异常,我们在终端是看不到信息的,在/var/spool/mail目录下对应用户的文件中,可以看到输出信息和异常信息
案例
每天的8:00执行一次 2.py
0 8 * * * python 2.py
每年的五月一日 10:05 执行一次 2.py
5 10 1 5 * python 3.py
每天的三点和六点各执行一次2.py
0 3,6 * * * python 2.py
每天的3点,4点,5点各执行一次2.py
0 3-5 * * * python 2.py
每天的8:20,9:20,10:20 各执行一次2.py
20 8-10 * * * python 2.py
每天的3,4,5点 没五分钟各执行一次2.py
60/5 3-5 * * * python 2.py
每周的周一 10点执行一次2.py
0 10 * * 1 python 2.py
命令模式: vim打开文件进入的模式就是命令模式, 其他模式按ESC键进入命令模式
*按键* | *描述* |
---|---|
x | 删除当前光标所在的字符,相当于delete【常用】 |
X | 删除光标前面一个字符,相当于backspace |
dd | 删除光标所在行【常用】 |
ndd | n为数字,连续删除光标后n行【常用】 |
yy | 复制光标所在行【常用】 |
nyy | n为数字,复制光标所在的向下n行 |
p | 将已复制的数据在光标下一行粘贴 |
P | 将已复制的数据在光标上一行粘贴 |
u | 复原前一个动作 |
G | 移动到这个档案的最后一行【常用】 |
gg | 移动到这个档案的第一行【常用】 |
n回车 | n 为数字。光标向下移动 n 行【常用】 |
插入模式: 插入模式一般也称为输入模式, 在命令模式下按i, a …等进入输入模式
按键 | 描述 |
---|---|
a | 光标后面插入字符 |
A | 行尾插入字符 |
i | 光标前面插入 |
I | 行首插入字符 |
o | 光标下一行输入字符 |
O | 光标上一行输入字符 |
底线模式: 底线模式也称末行模式,在命令模式下,按 shift+: 进入底线模式,可以进行文件的保存,退出,搜索等操作
指令 | 描述 |
---|---|
:w | 保存文件 |
:w! | 强制保存文件 |
:q | 不保存退出文件 |
:q! | 不保存并强制退出文件 |
:wq | 保存并退出文件 |
:wq! | 强制保存并退出文件 |
:set nu | 显示行号 |
:set nonu | 取消行号 |
centos通常会自动分配ip地址,不需要我们自己配置,但是自动分配会导致Ip地址动态变化
在开发环境中,通常不需要自动配置, 通过修改配置文件的方式,指定ip地址以及网络配置
使用 ifconfig 查看网卡信息
编辑配置文件/etc/sysconfig/network-scripts/ifcfg-ens33, 使用管理员权限
编辑配置文件/etc/sysconfig/network-scripts/ifcfg-ens33: ( 每个人的最后一个文件可能不太一样)
[python@localhost network-scripts]$ sudo vim /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=dhcp
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=6298ef16-d306-499a-8d81-c5afcffff260
DEVICE=ens33
ONBOOT=yes
~
修改自动分配ip为静态分配
在VMware虚拟机中点击 编辑—>虚拟网络编辑器
![image-20200906140704711](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9mYW5nZ2Fvc2hhbmcub3NzLWNuLWJlaWppbmcuYWxpeXVuY3MuY29tL2ltZy9pbWFnZS0yMDIwMDkwNjE0MDcwNDcxMS5wbmc?x-oss-process=image/format,png)
在打开的虚拟网络编辑器中点击 VMbet8 NAT模式
点击NAT设置,
在弹出的NAT设置中,找到网关IP复制下来, 然后关闭
点击DHCP设置
在弹出的DNCP设置中, 查看起始IP地址和结束IP地址,
在第一步打开的配置文件最后添加:
IPADDR=192.168.48.168 #这个IP地址在起始IP地址的最后三位数和结束IP地址的最后三位数之间, 前面的数字是一样的,根据自己的写
DNS1=114.114.114.114 #添加DNS解析,也可以自己在网上收
DNS2=8.8.8.8 #这个是谷歌的DNS解析,可以两个都写,也可以写一个
GATEWAY=192.168.48.2 #这个是第六步中网关IP地址
完整的配置如下:
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static # 静态配置IP
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=6298ef16-d306-499a-8d81-c5afcffff260
DEVICE=ens33
ONBOOT=yes
IPADDR=192.168.48.168 # 静态IP地址
DNS1=114.114.114.114 # DNS解析
DNS2=8.8.8.8 # 备用DNS
GATEWAY=192.168.48.2 # 网关
最后,重启网络配置, 使上面的配置生效
systemctl restart network
查看sshd是否启动
systemctl status sshd
scp : 主要用于远程文件传输
从本地向服务端上传文件
scp 本机文件的路径 用户名@服务端ip:/要上传的路径
从服务端下载文件到本地
scp 用户名@服务端ip:/下载的文件路径 本机文件的路径
如果要下载文件夹或上传文件夹加 -r 参数
在客户端生成密钥对
ssh-keygen -t rsa
将生成的密钥对上传到服务器
ssh-copy-id 用户名@服务器ip地址
免密码登录命令:
ssh -i 本地私钥路径 用户名@ip地址
shell编程就是通过终端编写的脚本程序,辅助开发人员完成命令的工程自动化操作
shell编程语言是一个解释性执行的编程语言
变量就是一个标识符, 有特殊的意义
由数字字母下划线组成, 不能以数字开头
变量必须先声明, 后使用
变量名不要使用特殊符号, 不要以$开头, 不能以关键字命名
在使用变量的时候后面不能直接跟字母
声明变量的格式
案例:
read -p '请输入账号:' username
read -p '请输入密码:' password
echo "您的账号是$username"
echo "您的密码是$pwd"
name="李四"
echo "I am ${name}abc"
if : 选择结构
单分支基本语法
if 条件
then
要执行的代码块
fi
双分支语法结构
if 条件1;then
条件为真时要执行的代码块
else
条件不为真时要执行的代码块
fi
多分支
if 条件1;then
条件1为真实执行的代码
elif 条件2;then
条件2为真实要执行的代码
else
条件都不成立时要执行的代码
fi
-e | 判断文件是否存在if [ -e 文件路径 ] |
---|---|
-d | 判断是否是文件夹if [ -d 文件路径 ] |
-f | 判断是否文件if [ -f 文件路径 ] |
-r | 判断文件是否是可读 |
-w | 判断文件时都是可写的 |
-x | 判断文件是否可执行 |
案例: 给定一个路径判断路径是否存在, 存在判断是否是文件夹,是文件夹执行备份,不存在创建该目录
#!/bin/sh
bpath="/root/"
cd $bpath
if [ -d './back' ]
then
echo "开始执行备份"
cp -r ./back ./back.bak
else
echo "目录不存在,创建目录"
mkdir back
fi
=/== | 判断两个字符是否相等[ $a = $b ] |
---|---|
!= | 判断两个字符是否不想等 |
-z | 判断字符串长度是否为0 如果为0返回true[ -z $变量 ] |
-n | 判断字符串是否不为空 不为空返回true[ -n “$变量” ] |
案例:1. 根据用户输入的选项, 判断不是就退出程序
#!/bin/sh
read -p "请输入用户名:" username
read -p '请输入密码' pwd
if [ $username = '1' ];then
echo "登录"
elif [ $username = '2' ];then
echo "注册"
elif [ $username = '3' ];then
echo "退出"
else
echo "没有这个选项"
fi
案例: 2. 提示用户输入用户名判断是否为空
#!/bin/sh
read -p "请输入用户名:" username
read -p '请输入密码' pwd
if [ -z $username ];then
echo "您的账号为空"
else
echo "你的账号没用问题"
fi
-eq | = [ $a -eq $2 ] |
---|---|
-gt | > |
-lt | < |
-ge | >= (( $a >= $b )) |
-le | <= |
-ne | != |
案例:
#!/bin/sh
if [ 1 -eq 1];then
echo "ok"
fi
if ((1 == 1));then
echo 'ok'
fi
if ((1 > 2));then
echo "ok"
fi
&& | 并且关系 and [[]] |
---|---|
-a | 并且关系 [] |
|| | 或者关系 or |
-o | 或者关系 |
! | 取反 |
案例: 判断用户名和密码是否正确
#!/bin/sh
read -p "请输入账号" username
read -s -p "请输入密码" pwd
if [ $username = "zs" -a $pwd = 'admin' ];then
echo "账号密码正确"
fi
if [[ $username = "zs" && $pwd = 'admin' ]];then
echo 'ok'
fi
基本语法格式
case 变量 in
值1|值2)
要执行的代码
;;
值3|值4)
只要执行的代码
;;
*)
上面的条件都不成立的时候执行
esac
案例
#!/bin/bash
read -p "请选择您的选项1)登录.2)注册" msg
case $msg in
1)
echo "登录"
;;
2)
echo "注册"
;;
*)
echo "您输入的选项不存在"
esac
for循环格式
for 临时变量 in 数据
do
循环体
done
#!/bin/sh
ips='127.0.0.1 192.168.48.1 10.10.123.137'
for i in $ips
do
echo $i
sleep 1
done
while循环格式
while 条件
do
循环体
done
存储一组数据的容器
格式
# 方式一
function 函数名(){
代码段
}
# 方式二
函数名(){
函数中的代码段
}
函数的调用
函数名
函数执行需要传参,不要在函数的后面的括号中,添加形参,shell中函数的参数有自己的传递方式
# 函数的传参
函数名 参数1 参数2 参数3
# 接受参数的方式
$0 接受当前文件名称
$1 接受到的第一个参数
$2 接受到的第二个参数
${10} 10以上的参数需要加{}
$@ 表示接受到的所有参数 “1” “2”
$* 接受到的所有参数 “1 2 ..”
$# 表示接受的参数个数
案例:
#!/bin/sh
function test(){
echo -n $1
echo -n $2
echo ${10}
}
test 你好 啊 a d f g h j o p
# 结果是 你好啊p
使用shell脚本备份指定目录下的所有日志文件
用户要指定一个路径
判断用户输入的路径存在不存在
将当前路径下的要备份的日志 打成tar包, tar包名字以当前的日期命名
判断一下当前路径中是与有 back目录
如果目录存在 我们将tar包移动到back目录下
如果目录不存在创建目录
#!/bin/sh
# 检测用户输入的参数
if [ $# -ne 1 ];then
echo "您的参数不合法,需要传递一个参数(备份的路径)"
exit
fi
# 判断用户输入的地址存是否是文件夹
if [ ! -e $1 ];then
echo "您输入的路径不存在"
exit
fi
if [ ! -d $1 ];then
echo "您输入的不是一个目录"
exit
fi
# 可以打tar包
bname=back_`date +%Y_%m_%d`.tar
# 打包
cd $1
tar -cf $bname ./*.log
# 判断当前路径下有没有back目录
#if [ -d ./back ];then
# mv $bname ./back/
#else
# mkdir ./back
# mv $bname ./back/
#fi
if [ ! -d ./back ];then
mkdir ./back
fi
mv $bname ./back
使用ssh连接, 需要配置密钥
本地用户配置
git config -global user.name '自己的名字'
git config -global user.name '自己的邮箱'
进入到版本仓库目录
创建1.py文件并编写内容
执行git status 查看当前版本库中所有文件的状态
git add 添加文件到暂存区
git push 将代码推送到远程仓库, 方便其他开发人员下载开发
git diff 查看新增的代码对于那些文件做了修改
git log/reflog 查看提交李四信息
代码回滚
git reset --hard 版本号
git提供了分支操作,通过不同的分支,完成不同的功能,将不同的分支可以合并到一个完成的产品中
分支的操作
查看当前版本库所有的分支
git branch
添加一个新的分支
git branch
切换分支
git checkout
删除一个分支
git branch -d
合并分支
git merge 分支名
分支冲突
创建本地仓库
git init
本地仓库关联远程仓库
git remote add origin 仓库地址
同步仓库信息
git remote --rebase origin master
移除指定连接
git remote remove origin
sql语法规则
;
结尾连接数据库
如果需要使用mysqlDBMS软件,先连接在登陆
完整连接方式
mysql -uroot -P3306 -hlocalhost -p
本机连接登录
mysql -uroot -p
操作库
查看当前mysql中所有的数据库
SHOW DATABASES;
创建数据库
CREATE DATABASE 库名 CHARSET=utf8;
切换数据库
USE 库名;
查看当前所在的库
SELECT DATABASE()
删除数据库
DROP DATABASE 库名;
表操作
查看当前库中所有的表
SHOW TABLES;
创建表
CREATE TABLE 表名(字段1 类型,字段2 字段类型...)CHARSET=UTF8MB4;
查看建表语句
SHOW CREATE TABLE 表名;
查看表结构
DESC 表名;
删除表
DROP TABLE 表名;
表结构操作
添加字段
ALTER TABLE 表名 ADD 字段名 类型 [约束];
ALTER ABLE 表名 ADD 字段名 类型 [约束] FIRST; # 在最前面添加
ALTER TABLE 表名 ADD 字段名 类型 [约束] AFTER 指定字段名; # 在指定字段名后添加
修改字段
modify: 只能修改字段类型和约束
ALTER TABLE 表名 MODIFY 字段名 类型 约束;
change : 既可以修改字段名也可以修改字段类型和约束
ALTER TABLE 表名 change 字段名 新字段名 类型 约束
只改名字类型和约束要原样写
若果改类型字段名和新字段名一样
删除字段
ALTER TABLE 表名 DROP 字段名
重命名数据表
ALTER TABLE 表名 RENAME AS 新表明;
数值类型
int 4字节
TINYINT 1字节
FLOAT 4字节 float(6,2)
DECIMAL decimal(6,2)
字符串类型
CHAR 定长字符串
VARCHAR 变长字符串
TEXT 文本 # 不能设置默认值
时间日期
DATE 年-月-日
TIME 时:分:秒
datetime: 年-月-日 时:分:秒
not null 非空约束
default 设置默认值
unsigned 无符号(只能存正数)
primary key 主键约束 唯一且不能为空
auto_increment 自增约束 一般配合主键使用
unique 唯一约束 数据唯一 可以为空
foreign key 外键约束,用来描述一对多关系的,保证两张表的统一性
增加数据
单条数据
INSERT INTO 表名(字段名1,字段2...) VALUES(值1,值2....);
多条数据
INSERT INTO 表名(字段名1,字段2...) VALUES(值1,值2....),(),()...;
删除数据
全表删除
TRUNCATE 表名 # 删除表中所有数据,并重置自增
指定条件删除
DELETE FROM 表名 WHERE 条件;
注意: 删除时必须添加where条件,如果不加就会被全部删除
修改数据
格式
UPDATE 表名 set 字段名=值 where 条件;
注意: update 更新数据必须添加where条件,如果不添加所有的数据都被修改
查询数据
查询全表数据
SELECT * from 表名;
where条件查询
SELECT * from 表名 WHRER 条件;
多条件查询
select * from 表名 where 条件1 and 条件2 ;
select * from 表名 where 条件1 or 条件2;
空值查询
select * from 表名 where 字段名 is null;
select * from 表名 where 字段名 is not null;
范围查询
select * from 表名 where 字段名 between 开始值 and 结束值;
in查询
select * from 表名 where 字段名 in (值1,值2,值3....);
模糊查询
_ : 1位任意字符
%: 任意位的任意字符
select * from 表名 where 字段名 like ‘%/_’;
聚合查询
count()用于计数
sum() 求和
avg() 求平均值
max()求最大值
min()求最小值
分组查询
select * from 表名 [where] group by 字段名 having 条件;
having类似于where, 但是where不能写在分组后面
having专门是用于筛选/过滤分组后的数据
分组查询可能会遇到错误,需要在配置文件中添加
```
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGIN
```
配置完成后重启服务
排序查询
select * from 表名 [where 条件 group by 字段名] order by 字段名 asc/desc;
asc 升序
desc 降序
分页查询
select * from 表名 [where 条件 group by 字段名 order by 字段名 asc/desc] limit 跳过前几条数据,取多少条数据
查询语句执行流
数据去重
select distinct 字段名 from 表名 [where ];
一对一: 一张表的一条数据,对应另一张表的一条数据
例如:
用户表:
create table user(
id int unsigned auto_increment primary key,
name varchar(10)
)charset=utf8;
用户详情表:
create table user_info(
id int unsigned auto_increment primary key,
gender int,
phone char(13),
length varchar(10),
u_id int unsigned,
foreign key(u_id) references user(id)
)charset=utf8;
一对多: 一张表的一条数据,对应另一张表的多条数据
例如:
父亲表:
create table parent(
id int unsigned auto_increment primary key,
name varchar(10)
)charset=utf8;
孩子表:
create table child(
id int unsigned auto_increment primary key,
name varchar(10),
gender int,
p_id int unsigned,
foreign key(p_id) references parent(id)
)charset=utf8;
多对多: 一张表的多条数据, 对应另一张表的多条数据
例如:
学生:
create table students(
id int unsigned auto_increment primary key,
name varchar(10)
)charset=utf8;
老师:
create table teacher(
id int unsigned auto_increment primary key,
name varchar(10)
)charset=utf8;
关系表:
create table stu_tea(
s_id int unsigned,
t_id int unsigned,
foreign key(s_id) references students(id),
foreign key(t_id) references teacher(id)
)charset=utf8;
嵌套查询: 将一个查询语句作为另一个查询语句条件去使用
格式:
select * from 表名 where 字段名 in (select 字段 from 表名);
关联查询
where关联查询, 通过where去关联外键
只能关联两张有关联的数据
格式:
select * from 表1,表2 where 关联条件
链接查询
内连接
select * from 表1 inner join 表2 on 关联条件 where 条件;
左外连接查询
select * from 左表 left join 右表 on 关联条件 where 条件;
右外连接
select * from 右表 left join 左表 on 关联条件 where 条件;
概述
将一组有序的增删改操作,当做一个独立的执行单元,如果这一组操作中有一个执行失败,整个事务则失败,自动执行回滚操作,当这一组操作都执行成功的情况下,事务则成功
数据库引擎
数据库引擎是数据库底层构架的核心负责底层数据持久化和软件交互的序列化操作, 核验过程以及交互过程,通过数据库的存储引擎完成创建,查询,更新和删除操作,当我们访问和数据库数据是都是通过数据库引擎去访问数据文件
事务的特性
事务在操作过程中,为了保证数据的批量操作过程中数据的安全性, 指定了一些事务本身必备的特性
事务并发问题: 在不考虑隔离性的情况下,可能会出现以下三种情况
事务的隔离级别
Read Uncommitted(读未提交)
只对修改数据的并发操作做限制, 一个事务不能修改其他事物正在修改的数据,但可以读取其他事物中尚未提交的修改,这些修改如果未被提交,将成为脏数据
解决的问题: 可能会出现 脏读 不可重复读 幻读
案例:
A开启事务
B开启事务
A更新数据,不提交
B查看数据,发现A未提交的数据
此时如果A回滚事务,B在查看B,B数据发生了变化,这种就是脏读
Read committed(读已提交)
只允许读取已经被提交的数据,如果一个事务修改了某行数据且尚未提交,而第二个事务要读取这行数据的话,那么是不允许的,读取的是未提交前的数据,防止脏读的出现,但是可能会出现不可重复读问题
解决问题: 避免脏读
案例:
A开启事务
B开启事务
A更新数据,未提交
B查看数据并查询不到A事务更新的数据,解决了脏读问题
A提交事务
B在查看,发现两次查询到的数据不一样,出现了不可重复读
repeatable read(可重复读)
读取期间其他事物不允许更新,就是在开始读取数据时,不在允许修改操作,那么在此事务提交前,其他任何事务的修改都会被阻塞
解决问题: 可以避免 脏读 和 不可重复读
案例:
A开启事务
B开启事务
A更新数据,未提交
B查看不到A更新的数据
A提交事务
B再次查看,和上次产看到的数据一样 避免的不可重复读
Serializable(可串行化)
所有事务必须串行化执行,只要事务在对表进行查询,那么在此事务提交前,任何其他事务的修改都会被阻塞
最高隔离级别
案例:
A开启事务
B开始事务
A更新数据
B查看数据时会 阻塞
隔离级别越高,效率越低
事务操作
设置事务隔离级别
set session transaction isolation level 隔开级别(上面四个)
开启一个事务
begin;
提交一个事务
commit;
回滚一个事务
rollback;
定义
种类
优缺点
索引的操作
添加索引
alter table 表名 add 索引类型 [索引名](字段名) # 用于表建好之后添加
查看索引
show index from 表名
删除索引
drop index 索引名 on 表名
索引的实现
BTree 索引(B-Tree 或 B+Tree 索引),Hash 索引,full-index 全文索引,R-Tree 索引,但是 MySQL 的 InnoDB 数据库引擎,只支持 B+Tree 索引。
定义
视图操作
创建视图
create view 视图名 as sql查询语句
使用视图
select * from 视图名;
查看视图
show table status where comment='view';
删除视图
drop view 视图名;
视图中的数据依赖源表当源表中的数据发生变化时,视图中的数据也会发生变化.
如果源表中的数据删除了,视图中的数据也没了
视图的优缺点
也称为触发程序,它的执行不是由程序调用,也不是手工启动,而是****由事件来触发****
当对一个表进行操作(****insert,delete, update****)时就会激活它执行
创建触发器
CREATE TRIGGER 触发器的名字 触发时机 事件 ON 表名 FOR EACH ROW
BEGIN
要执行的SQL语句
END;
应用:数据备份,当我们去uname中删除数据时,将删除的数据备份.
1.创建用于备份数据的表 表结构和uname表一样
create table 表名 as select * from 表名 where 1=2;
添加数据:
insert into 表名 as select * from 表名;
2.创建触发器
create trigger t_del_uname before delete on uname for each row
begin
insert into uname_ack values(old.id,old.name,old.age,old.gender,old.phone);
end;
查看触发器
SELECT * FROM INFORMATION_SCHEMA.TRIGGERS;
删除触发器
DROP TRIGGER 触发器名字
在删除事件触发器内部使用 old 可以获取,要删除数据的值
在添加事件触发器内使用new 可以获取我们新添加数据的值
添加用户
create user '用户名'@'来源地' identified by '密码';
案例: 创建一个用户ls可以在任意来源地登录
create user 'ls'@'%' identified by '密码';
创建一个用户在指定地址登录
create user 'ls'@'IP地址' identified by '密码';
创建一个用户在指定ip段登录
create user 'ls'@'10.10.123.%' identified by '密码'
删除用户
drop user '用户名'@'来源地';
授权操作
GRANT 权限 ON 库名.表名 TO ‘用户名’@’来源地’
权限回收
REVOKE UPDATE ON *.* FROM ‘用户名’@’密码’
修改密码
先查看mysql库中的user表中 ,用户是否有密码
select * from user where user="用户名"\G;
如果有密码需要先将密码重置为空
update user set authentication_string="" where user="用户名" and host=”来源地”;
重新设置新的密码
alter user "用户名"@"来源地" identified by '新密码';
密码丢失处理
停止mysql服务, 管理员权限打开命令行窗口输入
net stop mysql
创建一个SQL文件,将修改的密码命令添加到.txt文件中
alter user 'root'@"密码" identified by '新的密码';
启动服务器,使用mysqld命令附带 --init-file参数执行命令
mysqld --init-file="创建.txt文件的绝对路劲" --console
一组完成特定功能的SQL语句集,存储过程在数据库中,经过一次编译后调用时不需要再次编译, 将业务逻辑存储到数据库中
业务流程直接封装保存到存储过程中并不友好,业务分布在数据库和代码两个地方后期维护很麻烦,所以目前我们的数据库只用来做存储数据, 业务都放在代码中去处理.
基础语法
CREATE PROCEDURE 存储过程的名字()
begin
具体的sql语句
end;
call 存储过程的名字() # 调用
基本案例:
CREATE PROCEDURE testa()
begin
SELECT * FROM user_back;
end;
-- 调用存储过程
CALL testa()
存储过程中的变量
-- 存储过程变量
CREATE PROCEDURE testb()
begin
-- 声明变量
DECLARE username varchar(32) default ‘1’;
DECLARE newphone varchar(32);
-- 给变量赋值
set username='我是大娃';
SELECT phone into newphone FROM user_back WHERE name="大娃";
-- 查看变量中的数据
SELECT username,newphone;
end;
参数
in 输入 调用存储过程时,传递进去的参数
out 输出 out 存储过程输出给用户的参数,返回的只能是一个变量
inout 输入和输出
案例:
-- 存储过程的返回值
CREATE PROCEDURE test2(out res int)
BEGIN
-- 获取user_back表中平均年龄
SELECT avg(age) into res FROM user_back;
select res;
END;
CALL test2(@num);
select @num;
--- inout 参数
CREATE PROCEDURE test3(inout res int)
BEGIN
-- 获取user_back表中平均年龄
SELECT avg(age) into res FROM user_back;
select res;
END;
CALL test3(@num);
select @num;
--- in 参数
CREATE PROCEDURE test4(in res int)
BEGIN
-- 获取user_back表中平均年龄
SELECT avg(age) into res FROM user_back;
select res;
END;
set @num=2;
CALL test4(@num);
select @num;
流程处理
if 选择结构基本语法
格式:
if 条件
then
sql语句;
end if;
case when语句
格式:
case 变量
when 值1 then
sql语句;
when 值2 then
sql语句;
else
sql语句;
end case;
where循环
while 条件 do
sql语句
改变初始值
end while;
loop循环 不需要设置初始值
MY_LOOP:loop
sql语句
leave MY_LOOP
end loop;
内置函数
concat(s1,s2...) 字符串连接
length(str) 获取字符串长度
abs(x) 绝对值
round(x,y) 四舍五入
now() 获取当前时间
unix_timestamp(date) 返回指定时间的时间戳
date_format(data,str) 将指定时间格式化
from_unixtime(时间戳) 将时间戳转换为格式化时间
datediff(date,date) 返回时间间隔天数
database() 查看当前所在的库名
version() 返回版本号
user() 返回当前登录用户名
inet_aton(ip) 返回表示ip的数字
inet_ntoa(数值) 返回数字对应的ip
md5(str) 返回字符串MD5加密的结果
pip install pymysql
导入模
import pymysql
连接数据库
connect = pymysql.connnect(
host="数据库主机ip地址",
user="数据库登录用户名",
passsword="登录密码",
database='要链接的库',
port="数据库端口号",
charset="使用指定编码链接数据库"
)
获取游标
cursor = connect.cursor()
执行SQL语句
ret = cursor.execute()
获取结果
result = cursor.fetchall()
退出
cousor.close()
connet.close()