python高级_review

迭代器,生成器

  • 迭代器,能被for遍历的对象,叫迭代对象
  • 实际上,真正被迭代的是一个迭代器
  • 可迭代对象能生成迭代器,实际上是一个调用了__iter__()和__next__()方法的对象(python2是__iter())
  • 特点:保存执行流程就行了,不用将遍历的数据都存储起来,节省(内存)空间

  • 例子:

斐波那契数列迭代器
class FibIterator(object):
    def __init__(self, n):
        # 要生成的数的个数
        self.n = n
        # 当前生成到第几个数了
        self.current = 0
        # 初始的两个数
        self.num1 = 0
        self.num2 = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.n:
            num = self.num1
            self.num1, self.num2 = self.num2, self.num1+self.num2
            self.current+=1
            return num
        else:
            raise StopIteration
  • 除了for 循环,能调用迭代对象的还有:list();turple()

    • li = list(FibIterator(10))
    • turple = turple(FibIterator(10))

    • 生成器是一种特殊的迭代器

    • 使用了 关键字 :yield
    • 语法更简便
    • 创建生成器方法2:将列表生成式的[]改为()

    • 使用了yield关键字的函数就是生成器

    协程

    • 又称微线程,纤程
    • 是耗费资源量最小的一种实现多任务的方式
    • 通俗地讲就是在一个函数执行过程中有耗时操作的时候,会跳转执行其他的函数,执行一会再执行其他函数或者原来的函数,在各个函数间进行流转执行的机制。

    • yield就可以实现协程

 import time

def work1():
    while True:
        print("我在扫地。。。。。。")
        yield
        time.sleep(0.5)


def work2():
    while True:
        print("我在拖地。。。。。..............")
        yield
        time.sleep(0.5)



w1 = work1()
w2 = work2()

while True:
    next(w1)
    next(w2)
  • greenlet

    • 一个可以完成协程处理任务的模块
    • sudo pip3 install greenlet

      扫描二维码关注公众号,回复: 999908 查看本文章
    • 使用方法

  import time
from greenlet import greenlet
def work1():
    while True:
        print "扫地。。。"
        time.sleep(0.5)
        g2.switch()

def work2():
    while True:
        print "拖地。。。。。。。。。"
        time.sleep(0.5)
        g1.switch()

g1 = greenlet(work1)
g2 = greenlet(work2)


g1.switch()

  • gevent

    • greenlet依然需要手动切换,还是比较麻烦,解决这和个问题,就使用gevent模块
    • gevent模块将greenlet内部的原理还是使用greenlet,只是在遇到耗时IO操作(文件操作,网络操作)的时候不用手动.switch()切换了,而是可以自动切换
    • 需要搭配monkey.patchall()使用

    • 示例:


 import gevent
from gevent import monkey
import time

monkey.patch_all()


def work1():
    while True:
        print "扫地。。。"
        time.sleep(0.5)


def work2():
    while True:
        print "tuodi.........."
        time.sleep(0.5)


gevent.joinall([
    gevent.spawn(work1),
    gevent.spawn(work2),
])

## 进程,线程,协程之间的联系和不同点

  • 一个老板发现市场上布娃娃好卖,于是打算开一家布娃娃生产厂,于是开始开开始联系设备供应厂商,原料供应商,租场地,建厂房,安装设备机器,因为资金有限,就建了一个厂房,开了一条流水线,招了一些工人。就运行起来了。做了一段时间,供不应求,于是老板又在厂房里开了一条流水线。生意越来越好,两条变四条,厂房撑不下了,于是又在厂房旁边建了一个新的厂房,新的流水线,新的员工。生意蒸蒸日上,但是成本却在增加,为了进一步降低成本,提高生产效率,老板发现员工的操作是一个改善的好地方,他让让员工在自己手头没活的时候,不要闲着,去做一些其他的事情。生产效率将进一步增加,很快,老板成了当地有名的企业家。

  • 以上的例子中,工厂就是进程,流水线就是线程,员工就是协程。

  • 在多任务处理情境中,进程是资源分配的基本单位,是最耗费系统资源的,一般小的任务不建议开启多进程。

  • 线程是时间片轮转机制,系统调用的基本单位,资源消耗一般,效率一般,线程之间可以共享全局变量,线程间信息传递比较方便。
  • 协程其实是线程内部的函数间的跳转机制,所以叫做微线程嘛,是资源消耗最小,效率最高的一种多任务方式。因为是在线程内的,所以使用场景比较窄,适合处理一些小的功能间多任务。
  • 正常工作中,很据具体需求场景来选择是使用进程/线程/协程。一般情况下,进程用于大的完整一些的任务,如一个app,聊天软件;线程用于app内的多个任务执行,如网易云音乐里的下载,播放功能可以理解成两个两个线程,协程就是线程里任务的切换,如在播放音乐的时候,没网的卡顿的时候播放已经下载到本地的音乐。

    正则表达式:

  • 一种对字符串进行匹配查找的工具
  • 匹配规则
    • 单个字符匹配:.;[];\d;\D;\s;\S;\w;\W;
    • 匹配多个字符:*;+;?:{m},{m,n}
    • 匹配开头结尾:^;$
    • 匹配分组:|;(ab);\num;(?P);(?P=)
  • 匹配后处理方法
    • match():从头匹配,第一个
    • search():从任意位置匹配,匹配第一个
    • findall():从任意位置匹配,匹配所有,返回一个列表
    • sub(a,b,str):将在str中符合规则a的所有内容替换为b,返回替换后的整个字符串
    • 注意sub中的b也可以是一个函数
    • split(r’字符’,str):以字符为断点,将str切分,返回切分后的字符碎片组成的列表
  • 注意点

    • 在规则前加r,即r’匹配规则’;原生字符
    • *;+;?;{m,n} ,默认是贪婪的,能匹配多少就匹配多少
    • 在*;+;?;{m,n},的后面加上?就使贪婪变成了非贪婪(匹配尽量少)
  • 一般使用re模块的步骤

 # 导入re模块
 import re
 # 生成一个pattern
 pattern = re.compile(r'规则')
 # 处理匹配到pattern的字符
 res = pattern.方法名(str),如res = pattern.match("michael")

http协议

  • 超文本传输协议,web请求响应的一种协议
  • 请求,响应
  • 请求:以请求http://www.baidu.com 为例

    • 请求头,请求体
    • 请求头:

    “`
    GET / HTTP/1.1
    Host: www.baidu.com
    Connection: keep-alive
    Cache-Control: max-age=0
    Upgrade-Insecure-Requests: 1
    。。。
    GET 表示请求方式,除了GET,常用的还是有POST。其他的还有PUT,DELETE,OPTION..

/ 表示url地址
HTTP/1.1 表示协议的版本

下面的 aaa:bbb 表示请求的配置信息

如果是POST请求会有请求体
“`

  • 响应

    • 响应头,响应体

    “`
    HTTP/1.1 200 OK
    Bdpagetype: 2
    Bdqid: 0xd13ad2820000db3b
    Cache-Control: private
    Connection: Keep-Alive
    Content-Encoding: gzip
    Content-Type: text/html;charset=utf-8
    。。。

<响应体>

其中,第一行,HTTP/1.1表示协议版本, 200 表示状态吗, ok 表示状态信息,下面的aaa:bbb 表示服务器的配置或者状态信息

响应体就是HTML页面
“`

  • 一个完整的页面请求过程,如:http://www.baidu.com
    • 浏览器输入URL,浏览器生成请求报文-》域名解析服务器找到ip->将请求报文传给百度的服务器-》服务器解析请求报文,将需要返回的内容按照http协议打包成响应报文-》返回给浏览器-》浏览器解析响应报文-》将界面展现歘来

GIL全局锁

  • 在线程执行之前需要先获取GIL,保证同一时间只能有一个线程运行,运行完了释放GIL,其他线程运行,继续获取。
  • 龟叔声明,GIL跟python没有半毛钱关系,是由于历史原因,Cpython解释器里带的,因为依赖多,无法移除而已。
  • 那多任务怎么办?其实当IO操作引起阻塞前,可以先释放GIL,其他线程执行,然后再获取继续执行,python3使用计时器(执行时间达到阀值后,释放GIL;python2使用tickets,计数打法哦100,释放)
  • 多任务中,多进程,利用多核,没有影响。
  • 多线程的话,因为遇到IO阻塞会释放GIL,所以跟单线程的阻塞相比,是会有效率的提升的。
  • 如果就是觉得慢,可以不用python编写相关代码,用的更底层的C/C++等

深拷贝,浅拷贝

  • 浅拷贝,只复制了对象的顶层结构
    • 三种方式:1:直接赋值;2:import copy; copy.copy(); 3:[:]
    • 字典的内置方法.copy,是一个浅拷贝
    • 对于不可变类型,使用浅拷贝方法,copy.copy(),是引用原变量的地址,和直接赋值是一样的效果
  • 深拷贝,是对一个对象的递归拷贝,拷贝到底
    import copy ; copy.deepcopy()

私有化

  • XX:公有变量
  • _xx:from XXX import *,禁止导入的变量
  • __XX:私有变量,只有子类内部可以调用
  • __XX__:魔法对象,如__all__,不要自己造
  • xx_,用于避免与python关键字冲突

import导入模块

  • import sys
  • sys.path:import搜索模块的所有路径,列表
  • sys.path.append()/insert(0,xx):可以往这个列表里添加搜索路径
  • b导入一个模块a,使用的过程中,a模块的内容改变了,b中需要重新导入模块a,使用 import a 没有作用, 要使用 : from imp import reload ; reload(a)

再议封装,继承,多态

  • 封装:把可以完成一个功能的代码放在一起,有自己的独有变量和方法,需要实现这个功能的时候,就实例化它拿来用。对比不封装,全局变量加函数,最然也能完成相同的功能,但是当进行多任务时,就会出现资源争夺问题,封装后的代码就不会.而且代码看起来简洁明了。
  • 简单的说 1:使得变量和方法的使用更加灵活,安全 2:代码逻辑简洁明了

  • 继承:父类基本功能,子类特殊功能

    • 特点:
    • 大大节俭了代码量
  • 多态:父类定义方法,子类重写,调用父类的方法,完成不同的功能。

    • 举 系统类 app类 pycharm类 chrome类 的列子
    • linux对象调用安装app.install方法(app类的方法),可以完成pycharm类的安装方法和chrome的安装方法。

父类名.方法 vs super().父类方法

  • 单继承一样
  • 多继承,父类名.方法会执行多次,super().父类方法只会执行同名的第一父类的该方法

类属性,实例属性

  • 定义有所区别,本质区别是内存中的保存位置不同

    • 类属性属于类对象
    • 实例属性属于实例对象
    • 类属性在内存中值保存一份
    • 实例属性在每个实例对象中都保留一份
  • 应用场景

    • 通过类创建示例对象时,如果每个实例对象都需要相同的属性,那么就定义使用类属性,否则使用实例属性
    • 如:飞机大战游戏中的子弹,有一些固有属性,如类型:玩家子弹,实例子弹都会使用这个类属性,每个实例也会有自己的属性,color,damage等

静态方法,类方法,实例方法

  • 都是方法,完成某些功能
  • 内存中存储的位置也相同,都存储在类对象中
  • 不同点在调用调用方式上
    • 类方法是类对象来调用的,调用时,将自己以cls参数的形式当参数导入
    • 实例方法是实例对象来调用的,调用时,将自己以self参数的形式导入
    • 静态方法,类对象和示例对象都可以来调用的,没有固定参数

 class TestMethods(object):
    @classmethod
    def class_method(cls):
        print ("this is class method")

    def normal_method(self):
        print ("this is normal method")

    @staticmethod
    def static_method():
        print ("this is static method")


if __name__ == '__main__':
    test1 = TestMethods()
    # 类对象调用类方法
    TestMethods.class_method()

    # 实例对象调用实例方法
    test1.normal_method()

    # 类对象和实例对象调用静态方法
    TestMethods.static_method()
    test1.static_method()

    # 实例对象调用类方法,能执行,但不这样用,因为参数不一样
    test1.class_method()

    # 类对象调用哪个实例方法,不可以调用,会报错,因为实例方法,需要默认传入一个实例对象的参数
    TestMethods.normal_method()

property属性

  • 是一个装饰器
  • 完成的功能是,在调用property装置器装饰的方法时,可以像调用属性一样,直接用对象名.方法名,会直接返回方法return的结果
  • 示例:京东网页,每页显示的内容,开始的上品SKU,star和结束的SKU,end可以写成两个被property装饰器 装饰的方法,然后方法里return计算结果(根据请求页数和每页显示SKU数目计算),就可以像调用属性一样调用start和end方法

  • 用法提升

    • property实际上有三个装饰器,一个是获取返回值的@property;一个设置值的@函数名.setter,还有一个是删除值的@函数名.deleter
    • 以上用法只有新式类中有
    • 当我们需要的变量是需要被计算后才能使用的时候,可以在代码先计算后再使用,但是为了,让代码更简明,封装性更好,可以在类中使用property属性,完成变量的内部计算。然后像调用更改,删除正常变量一样用它就好。
class PropertyUse(object):
    def __init__(self):
        self.original_price = 100
        self.discount = 0.8

    @property
    def price(self):
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self):
        del self.original_price


if __name__ == '__main__':
    property_use = PropertyUse()
    # 调用price.setter装饰的方法,完成赋值
    property_use.price = 20

    # 调用property装饰的方法,返回price.setter赋值的值
    price = property_use.price
    print(price)

    # 调用price.deleter装饰的方法,
    del property_use.price

    print(property_use.price)
    # 报错,没有这个变量
  • property除了以装饰器的形式使用,也可以以类属性的方式使用
  class PropertyUse(object):
    def __init__(self):
        self.original_price = 100
        self.discount = 0.8

    def get_price(self):
        new_price = self.original_price * self.discount
        return new_price

    def set_price(self, value):
        self.original_price = value

    def del_price(self):
        del self.original_price

    price = property(get_price, set_price, del_price, 'lalala德玛西亚')
# 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
# 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
# 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
# 第四个参数是字符串,调用 对象.属性.__doc__ ,此参数是该属性的描述信息

if __name__ == '__main__':
    property_use = PropertyUse()
    # 输出折后的价格
    print (property_use.price)

    # 修改原价
    property_use.price = 20
    print(property_use.price)

    print(property_use.price.__doc__)


    • Django 框架中request.POST就是使用的类属性的方式创建的属性
  • 综上

    • property属性是一个能让编程人员更简单直观的调用变量的一种方式
    • 使用方式有装饰器和类属性两种
    • *装饰器方式,新式类和经典类不一样,经典类只能使用@property,新式类可以使用@property,也可以使用@类名.setter和@类名.deleter

    魔法属性/方法

  • 是python中内置的有特殊特性的,在恰当时候使用的属性/方法

    • 1.__doc__:表示类的表述信息
    class TestMagicMethod(object):
    """ 这是类的描述性信息"""
    pass
    
    if __name__ == '__main__':
    test1 = TestMagicMethod()
    print(test1.__doc__)
    
    • 2.__module__ 和 __class__
    • __module__表示当前操作的对象在那个模块
    • __class__表示当前操作的对象的类是什么

    • 3.__init__:示例对象的初始化

    • 4.__del__:删除对象时使用。 python的解释器有垃圾回收机制,实际上是计数器-1,当计数器=0是,对象被从存储器上真正删除。解释器的垃圾回收机制是会在恰当的时候自动触发的

    • 5.__call__:对象后面加括号,执行的方法,注意是对象后面加(),而不是类(),后者是实例化对象

    class TestCallMagicMethod(object):
    def __call__(self, *args, **kwargs):
        print("this is __call__ method")
    
    
    if __name__ == '__main__':
    test1 = TestCallMagicMethod()
    test1()
    
    • 6.__dict__:类或者对象中的所有属性/方法

    • 7.__str__:一个类定义了一个__str__方法,当打印这个类的实例对象,会返回这个方法的返回值

    • 8.__getitem__,__setitem__, __delitem__:给对象设置,获取,删除key-value值,如字典。

    class Foo(object):
    def __getitem__(self, key):
     print('__getitem__', key)
    
    def __setitem__(self, key, value):
     print('__setitem__', key, value)
    
    def __delitem__(self, key):
     print('__delitem__', key)
    
    
    obj = Foo()
    result = obj['k1'] # 自动触发执行 __getitem__
    obj['k2'] = 'laowang' # 自动触发执行 __setitem__
    del obj['k1'] # 自动触发执行 __delitem__
    
  • 9.__getslice__, __setslice__, __delslice__:如列表的切片操作

class Foo(object):
  def __getslice__(self, i, j):
    print('__getslice__', i, j)

  def __setslice__(self, i, j, sequence):
    print('__setslice__', i, j)

  def __delslice__(self, i, j):
    print('__delslice__', i, j)

obj = Foo()
obj[-1:1] # 自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] # 自动触发执行 __setslice__
del obj[0:2] # 自动触发执行 __delslice__

with

# 任务:打开一个file文件,写入一段文字

# 方式1:
f = open(file, 'w')
f.write('fadsfds')
f.close()

# 方式2:
with open (file, 'w') as f:
  f.write("adfasdf")
  • 文件的使用步骤是:打开,读写,关闭,比较繁琐,使用with关键字,就不需要执行 .close()了
  • with 关键字用于监护啊资源操作的后续清除操作,是try/finally的替代方法,实现原理建立在上下文管理器之上
    • 上下文管理器(实现了enter()和exit()的对象)

数据库

  • 数据库是现在存储数据的方式

RDBMS

  • 常用的数据库类型有关系型数据库和非关系型数据库
  • 关系型数据库是建立在关系模型基础上的数据库,简单的说,就是数据之间遵循一定的放在一起,如excel表中的学生信息,列(字段):学生名,科目,成绩 行(数据):一个班所有学生的成绩信息

  • 关系型数据库有:

    • oracle:大型,安全,服务好,收费
    • mysql:好用且免费
    • ms sql server:微软
    • sqlite:轻量级,主要用在移动平台
  • 结构:

    这里写图片描述

SQL

  • 结构化查询语言,一种用来操作RDBMS的语言,完成对数据库的增删改查任务。除了增删改查,还能完成事务处理,指针控制,数据控制等任务。

  • 目标:

    • 熟练掌握SQL的增删改查
    • 在python中对数据库进行数据的增删改查

mysql

  • MySQL是一种RDNMS,由瑞典MySQL AB公司开发–>Sun公司–>Oracle,目前属于Oracle公司

  • 特点:

    • 使用C,C++编写,速度快
    • 多种编译器测试,保证源代码的可移植性
    • 支持多种操作系统linux,Windows,Macos,Solaris。。。
    • 为多种语言提供api:c,c++,python,java,prel,php,Ruby,Eiffel等。。。
    • 支持多线程,快
    • 提供多语言支持,gbk,utf-8等
    • 提供多种数据库链接途径:TCP/IP,ODBC,JDBC等
    • 使用标准的SQL,对数据库进行操作
    • 开源,免费!

数据库

  • 一个数据库就是一个完整的业务单元的所有数据,包含有关于这个业务单元的所有表
  • 每个表有字段和数据行组成

    • 字段:由字段类型和约束条件两部分组成
  • 字段类型:大蜗牛使用打壳,小蜗牛使用小壳。不同的数据,因为大小不同,分的空间应该根据数据类型而定
  • 常用数据类型:整数:int,bit;小数:decimal;字符串:char,varchar;日期:date,time,datatime;枚举:enum
  • 约束:对此字段的数据在数据类型的基础上进行进一步的控制,约束。
  • 主要有:主键(primary key):唯一标示数据表的每一条数据
  • 非空(not null):此字段不允许填写空格
  • 唯一(unique):此字段不允许重复
  • 默认(default):不填写使用默认值,填写了,使用填写的
  • 外键(foreign key):关系字段,用来关系其他表,进行连表查询

操作

  • 数据库操作:

    • 查询数据库信息:show databases;
    • 选择数据库:use 数据库名,如use python
    • 创建数据库:create database 数据库名 charset=XX; ,如create database python charset=utf-8;
    • 删除数据库:drop database 数据库名;如drop database python;
  • 数据表操作:

    • 创建表:create table 表名(字段名 数据类型 约束1 约束2 。。。),如 create table subjects (id int primary key not null auto_increment, name varchar(20) default "coding");
    • 删除表:drop table 表名;如 drop table subjects;
    • 查询所有表:show tables;
    • 查询表创建语句(查询创建的详细信息):show create table 表名;,如show create table subjects;
    • 查询表结构:desc 表名;,如 desc subjects;
    • 修改表结构-添加字段:alter table 表名 add 新字段名 字段数据类型 约束1 约束2…; 如 alter table subjects add major bool default True;
    • 修改表结构-删除字段:alter table 表名 drop 字段名; 如 alter table subjects drop majors;
    • 修改表结构-修改字段(重新设置):alter table 表名 change 字段名 新字段名 字段数据类型 约束1 约束2 …; 如 alter table subjects change major majors bool default True;
    • 修改表结构-修改字段(只修改约束):alter table 表名 modify 字段名 约束1 约束2 …; 如alter table subjects modify majors bool default True not null;
  • 数据操作(增删改查,cdur)

    • 增:insert into 表名 values(字段1值,字段2值,…);,如insert into classes values(1,"实验"); ,如果是多行插入,values后面就跟多个元组,每个元组,代表一行数据,如insert into classes values(2,"实验2"),(3,"实验3")
    • 删:delete from 表名 where 条件; 如 delete from classes where id = 1;
    • 改:update 表名 set 字段名1=新值 字段名2=新值 where 条件;如 update classes set name="实验1" where id=1;
    • 查:select 字段名/*(全部数据) from 表名;如select * from classes
  • 数据库的备份及恢复

    • 备份:mysqldump关键字,格式(退出数据库):mysqldump -uroot -p 数据库名 > 路径,如mysqldump -uroot -p > ~/Desktop/school_data.sql
    • 恢复(需要先登录数据库建好新数据库):mysql -uroot -p 新数据库名 < 文件路径,如 mysql -uroot -pmysql school_info < ~/Desktop/school_data.sql

数据库设计

  • 三范式

    • 原子性:每一个字段都分到不能在为止。如,表联系人,姓名,性别,电话,电话就不遵循原子性,因为现在很多人不是一个电话(公司电话,私人电话,私密电话。。)
    • 必须有主键,其他键必须依赖主键。举例子,Orderdetail表(order_id,product_id,count, discount,single_price),一个订单可能不止一种商品,order_id不能作为其他所有字段的主键,不符合第二范式
    • 其他所有字段必须直接依赖主键,不能存在传递依赖的主键的情况。如上面的例子,single_price字段依赖product_id,然后product_id依赖order_id,如果只将order_id作为主键,就会出现传递依赖的情况,这就不符合第三范式了。
  • 三范式是一种推荐的设计表结构原则,在实际的设计表过程中,是在实际的需求场景下,以满足近期以适当的远期需求为目标的,一般情况下遵守三范式原则。但是如果有特殊的需求,同样可以反范式的情况。以实际需求为准。比如性别字段,一般设计为enum类型(男,女),设计之初觉得够用了。但是facebook确哟50几种性别。哪怕一开始设计好的表结构,当时符合需求,随着需求的演进和变化,也会发生一定的变化的。但是,作为数据库设计人员,一开始就应该考虑周全,避免后期出现大量的不必要的麻烦。

  • E-R模型

    • E,entry,实体,就代数据库表,R,relationship,关系,数据库表之间的关系
    • 数据库的表之间的关系也是数据,需要用字段或者表表示出来
    • 数据库表之间的关系有三种
    • 一对一(学生基本信息表,学生扩展信息表);一对多(班级表,学生表);多对多(科目表,学生表)

    • 一对一,关系字段在常用的表中定义;一对多,关系字段在多的一方定义;多对多,新建表用来存储关系

查询进阶

  • 一般查询
    • 查询所有:select * from 表名;
    • 查询指定字段:select 列1,列2,... from 表名
    • 使用as给字段或者表名起别名:select is as 序号, name as 名字, gender as 性别 from 表名select s.id, s.name,s.gender from students as s
    • 消除重复行: select distinct 列1,列2... from 表名
  • 条件查询
    • 结构select * from 表名 where 条件
    • where后面支持多种运算符:比较:>,<,=;逻辑:and,or,not;模糊查询:like(%:表示任意多个任意字符,_表示一个任意字符);范围查询:in, between…and…;空判断:is null, is not null
    • 优先级:高-低:小括号-》not->比较运算符-》逻辑运算符
  • 排序
    • 语法:select * from 表名 order by 列1 asc|desc [,列1 asc|desc,...]
    • 先按照列1排序,列1中相同的,按照列2排序,以此类推
    • asc升序,默认,desc 降序
  • 聚合函数
    • 快速得到统计数据
    • 总数:如,查询学生表的数据总数,select count(*) from students;
    • 最大值:如,查询女生编号最大的值select max(id) from students where gender=2;
    • 最小值:如,查询未删除的学生的最小编号:select min(id) from students where is_delete=0;
    • 求和:如,查询男生的总年龄:select sum(age) from students where genger=1
    • 平均值:如,查询未删除女生编号的平均值:select avg(id) from students where gender=2 and is_delete=0
  • 分组
    • 将查询到的数据按照一个或者多个字段进行分组,字段值相同的为一组
    • 如,将查询到的所有学生数据按照性别分组:select gender from students group by gender
    • group by + group_concat():将分组后的每组的左右指定信息输出
    • 如,将学生按照年龄分组,并且把每组的所有人员姓名输出:select gender, group_concat(name) from students group by gender
    • group by + 集合函数:分组后,使用函数计算每组中某一个字段
    • 如,将学生按照性别分组,计算每组的年龄的平均值:select gender, avg(age) from students group by gender;
    • group by + having:分组后指定一些条件后输出,和where用法相同,只是只跟在group by 之后
    • 如,学生表按性别分组,输出每一组中平均年龄大于20岁的人的姓名:select gender,group_concat(name) from students group by gender having avg(age)>20;
  • 获取部分行
    • 数据量过大,只查看一部分
    • 格式:select * from 表名 limit start, count (查询的结果放在列表里,从start索引值开始,查看count条)
    • 如,查看学生表中前5条数据:select * from students limit 0,5;
    • 分页查询:已知每页数据m条,现在需要查询第n页的数据:(1.总数据数a;2:之前页的数据数:(n-1)m ;3.则第n页的第一条数据索引值为(n-1)m-1)
    • select * from students limit (n-1)m-1, m
  • 连表查询:内连接,左连接,右连接
    • 语法:select * from 表1 inner/left/right join 表2 on 表1.列=表2.列
    • 查询学生姓名及班级名称
    • select s.name,c.name from students as s inner join classes as c on s.class_id = c.id;
    • 使用左连接查询班级表及学生表
    • select * from students as s left join classes as c on s.class_id = c.id;
    • 使用右连接查询班级表及学生表
    • select * from students as s right join classes as c on s.class_id = c.id;
  • 自关联
    • 一个表的字段关联表本身的另一个字段
    • 用于:区域表:省,市,区
  • 子查询

    • 一个select语句中,嵌套另一个select语句,被嵌套的select查询语句,是子查询语句,作为主查询语句的条件或者数据源
    • 如:查询年龄大于平均年龄的学生信息
    • select * from students where age > (select avg(age) from students);
  • 完整的select语句:

    • select distinct * from 表名 where 条件 group by … having … order by … limit start, count;
    • 执行顺序为:from 表名-》where->group by->select distinct->having->order by ->limit start,count

    • 实际使用中,只会使用一部分

python中使用 MySQL

  • 步骤:

    • 导入模块:from pymysql import *
    • 创建connection对象:conn = connect(参数列表)
    • 创建cursor:cs1 = conn.cuisor()
    • 执行命令:cs1.execute(sql语句)
    • 提交命令:conn.commit()
    • 关闭cursor和connection对象:cs1.close() ,conn.close()
  • sql注入

    • cursor直接执行sql语句,如果被截取,然后加上其他语句,就被删库了
    • 解决办法:cursor对象传入的sql语句以参数的形式传入(字符串,占位符)
    • 如:count = cs1.execute('select * from goods where name=%s', params).参数在执行语句外定义,这样执行的sql语句就只会执行这一条,不会发生被截断加入删库语句等危险情况。

视图

  • 问题:复杂的查询,需要改一些查询语句,许多地方都要改,麻烦。解决办法–视图
  • 视图是一条select语句执行后返回的结果集
  • 是对若干张表的引用,形成的一张虚表
  • 可以理解为一个函数,需要使用的时候,调用即可

  • 使用步骤

    • 定义视图:create view 视图名称 as select 语句;
    • 查看视图:show tables
    • 使用视图:select * from 视图名
    • 删除视图:drop view 视图名
  • 视图的作用:

    • 提高复杂查询语句的重用性,就像一个函数
    • 可以对数据库进行重构,缺不影响程序的运行
    • 安全
    • 快捷

事务

  • 场景:A转账给B 500元,需要三步:检查A账户余额>=500;A账户余额-500;B账户余额+500,如果在执行到第二部,服务器爆炸了,怎么办?
  • 事务机制可以处理以上及类似问题。
  • 事务:是一个操作序列,要么都执行,要么都不执行。全荣才荣,一损俱损。
  • 四大特性:

    • 原子性:每一个事务都是最小的一个执行单元,不管内部有几步。
    • 一致性:没有提交,不会执行。对于每一个事务都是一样。
    • 隔离性:每一个事务在没提交之前,对其他事务,是不可见的。
    • 持久性: 一旦提交,就会永久性保存到数据库。
  • mysql中表的引擎要用innodb类型,能使用事务,因为innodb支持事务机制。除了innodb,mysql中还有ISAM,MyISAM,BLACKHOLE引擎

  • 使用步骤:

    • 查看表的详细信息,查看引擎是否为innodb:show create table students
    • 开启事务:begin;或者 start transaction
    • 执行sql语句
    • 提交事务:commit;
    • 回滚事务:rollback;
  • 注意:

    • 修改数据的命令会自动触发事务,包括:insert, update, delete
    • 既然内置,为什么还要手动开启?因为可以一次执行多个修改命令。

索引

  • 索引是对数据表中所有数据的引用指针的集合。是表文件内容的一部分。
  • 字典查字,在目录里找偏旁部首,逐渐缩小查找范围,找到字的响应页数,找到字。索引就是一个表所有数据的目录。用于快速查找到其中的目标数据。
  • 原理是:逐渐缩小查找范围,锁定目标,范围太大,就拆分范围数据,将存储的数据分成若干块,先在所有的块中找到数据可能在块,然后忽略其他块,直接在这一块里找。

  • 使用步骤

    • 查看索引:show index from 表名;
    • 创建索引:create index 索引名称 on 表名(字段名称(长度))
    • 删除索引:drop index 索引名称 on 表名
  • 测试:比较查询一条没加索引和加了索引的数据所用的时间

    • 开启运行时间检测:set profiling=1;
    • 查看执行的时间:show profiles;
  • 注意:

    • 虽然建立索引会加快查询速度,但也不应该建立太多索引
    • 1.因为建立索引会占用磁盘空间,建立过多的索引,会占用过多的磁盘空间;
    • 2.会影响更新和插入的速度,因为更新的时候,每个索引文件也要更新。
    • 一般比较耗时的常用的查询字段再建立索引,不常用的不需要建立

账户管理

  • 给据不同的用户,授予不同的权限,对所有的用户权限进行添加,删除,改动等操作
  • mysql账户等级体系:

    • 服务实例级账户:root,拥有数据库所有权限
    • 数据库级账户:对特定数据库拥有增删改查等权限
    • 数据表级账户:对特定数据表拥有增删改查等权限
    • 字段级的账户:对某些表的特定字段拥有增删改查等权限
    • 存储程序级账户:对存储程序进行增删改查等权限
  • 账户操作:

  • 1.创建账户
    • grant 权限列表 on 数据库 to '用户名'@'访问主机' identified by ‘密码’ ;
      • 常用的权限包括:create,alter,drop, insert, update, delete,select
    • 如果授予所有权限,权限列表可以写:all privileges
    • 以上命令需要先使用root账户登录后,方能使用
    • ‘访问主机’,localhost表示只有本机可以访问,%表示任意主机都可以访问,其他主机使用其他主机的IP即可
  • 2.修改权限
    • grant 权限名称 on 数据库 to 账户名@主机 with grant option;
  • 3.修改密码
    • update user set authentication_string=password('新密码') where user='用户名';
    • 注意修改完成后要刷新权限
    • flush privileges
  • 4.删除账户
    • drop user '用户名'@‘主机’

mysql主从配置

  • 定义
    • 两个mysql服务器,一个设置为主服务器master,一个设置为从服务器slave,这种配置mysql数据库的方式,叫做mysql主从配置
  • 为什么用
    • 提升读写效率。读写分离,两台服务器的抗压能力的都可以提升,客户端的读写速度会加快
    • 数据安全。一台服务器挂了,无论是主还是从,还有另一台服务器,存储着完整的数据
    • 提升主服务器性能。主服务器上生成的数据,可以在从服务器上分析。
  • 原理
    • 二进制日志机制
    • 主服务器上的所有操作,都会生成二进制的日志文件。这个二进制日志文件会被传到从服务器上,从新执行一遍,从而保证了从服务器和主服务器数据的一致性
  • 实现步骤

    • 1.转移初始数据。将主服务器上的所有数据dump出,先导入到从服务器
    • 2.主服务器配置。设置主服务器的二进制日志文件配置,配置一个独立的ID,创建一个专门用来复制主服务器数据的账户
    • 3.从服务器配置。在从服务器上配置一个独立的ID,配置从服务器要连接的主服务器的IP地址和登陆授权,二进制文件名和位置
  • 详细步骤:

    • 1.导出主服务器的所有数据库数据:mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql
    • 2.在从服务器上,将数据库数据导入:mysql –uroot –pmysql < master_db.sql
    • 3.配置主服务器:
    • 3.1编辑mysqld的配置文件,设置log_bin 和 server_id
    • sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

    这里写图片描述

    • 3.2重启mysql服务:sudo service mysql restart
    • 3.3重新登陆主服务器,创建用于从服务器同步数据用的账户
    • mysql –uroot –pmysql;GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave'; ; FLUSH PRIVILEGES;
    • 3.4获取主服务器的二进制日志信息:SHOW MASTER STATUS;
    • 4.配置从服务器:在从服务器上配置一个独立的ID,配置从服务器要连接的主服务器的IP地址和登陆授权,二进制文件名和位置

闭包,装饰器

闭包

  • 外层函数套内层函数,外层函数返回内层函数的引用,外层函数有参数
def 外层函数的名称()
  def 内层函数的名称()
    pass
  return 内层函数的引用
  • 例子:换算汇率
  • 作用:可以保持一个值一段时间

装饰器

  • 就是一个闭包
def set_fun(func):
  print('装饰器外部函数执行')
  def call_fun(*args,**kwargs)
    print('装饰器内部函数执行')
    func()
  return call_fun
  • 核心思想是:在不改变原先函数的情况下,给该函数增加新功能

  • 使用步骤:1:自定义一个装饰器 2.使用语法糖装饰在需要装饰的函数上

  • 使用场景:

    • 计算函数的执行时间
    • 统计方法被执行了多少次
    • 权限验证
  • 不同的装饰器装饰同一个函数的执行顺序

    • 秋裤大法:先穿后脱,先外后内

mini框架及wsigi协议

  • mini框架是自己写的一个web框架,用来处理动态页面访问

    • 服务器用来返回静态页面,web框架返回动态请求页面
    • 但是有问题:更换服务器不方便,需要重写很多代码
  • wsigi协议:解决上面的问题

    • wisigi协议是web框架和服务器之间的约定遵守的规则
    • 每一个web框架和服务器都要遵守这样的规则
    • 那么在更换web框架的时候,就会很方便,不需要更改代码,因为大家都遵守了wsigi协议
    def application(environ, start_response):
    start_response('200 ok', [('Content-Type', 'text/html')])
    return 'Hello World'
    
    其中:
    environ是 http服务器给mini框架传数据
    start_response是给httpf服务器传数据
    return是返回数据给http服务器
  • webmini框架路由分发

    • 通过一个url地址,找到一个执行函数,不同的url会匹配不同的执行函数
    • 分发的原理是三层函数嵌套的装饰器
  • webmini框架对数据库的操作
    • 步骤:
    • 连接数据库,生成执行器
    • 确定SQL语句(重点)crud,使用执行器进行执行
    • 提交执行结果
    • 将获取的到的数据替换到需要返回页面中的模板
    • 关闭执行器和数据库对象

日志

  • 日志就是程序在运行过程中的一些状态信息
  • 日志的级别:

    • critical:程序本身不运行
    • error:错误信息,程序不能正常运行了
    • warning:程序在未来或者某些状况下可能会出现问题(跟踪信息只能跟踪到这了)
    • info:正厂执行的状态信息
    • debug :详细的执行信息
  • 使用:

  • 输出到控制台:

    
    # 导入模块
    
    import logging
    
    
    # 配置参数
    
    logging.basicConfig(level=logging.WARNING, format=%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s)
    
    
    # 开始使用log功能
    
    logging.info('这是logging info message')
    logging.debug('这是logging debug message')
    logging.warning('这是logging warning message')
    logging.error('这是logging error message')
    logging.critical('这是logging critical message')
    
    
    # 注意:输出到控制台,最高级别也就是warning了,error和critical是输不出的
    
    
  • 输出到文件中

    
    # 导入模块
    
    import logging
    
    
    # 配置
    
    logging.basicConfig(level=logging.WARNING, filename='log文件存储路径,如:./log.txt',filemode='w',format='%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s')
    
    
    # 使用模块
    
    logging.info('这是logging info message')
    logging.debug('这是logging debug message')
    logging.warning('这是logging warning message')
    logging.error('这是logging error message')
    logging.critical('这是logging critical message')
    
    
  • 工作中工具类的使用

    
    # 导入模块
    
    import logging
    
    
    # 创建一个logger
    
    logger = logging.getlogger()
    logger.setLevel(logging,INFO) # log等级总开关
    
    
    # 创建一个handler,用于写入日志文件
    
    logfile='./log.txt'
    fh=logging.FileHandler(logfile, mode='a')# open的打开模式这里可以参考
    fh.setLevel(logging.DEBUG) # 输出到file的log等级的开关
    
    
    # 再创建一个handler,用于输出到控制台
    
    ch=logging.StreamHandler()
    ch.setLevel(logging.WARNING) # 输出到console的log等级的开关
    
    
    # 定义handler的输出格式
    
    formater = logging.Formatter("%(asctime)s-%(filename)s[line:%(lineno)d]-%(levelname)s:%(message)s")
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    
    
    # 将logger添加到handler里面
    
    logger.addHandler(fh)
    logger.addHandler(ch)
    
    
    # 日志记录
    
    logging.info('这是 loggging info message')  
    logging.debug('这是 loggging debug message')  
    logging.warning('这是 loggging a warning message')  
    logging.error('这是 an loggging error message')  
    logging.critical('这是 loggging critical message')
    
    
  • 工作中的使用场景

    • 使用在try语句中
    • 在exception下使用日志打印error级别,如连接mysql失败
    • 如果是超出预期的代码,可以使用warning,如页面找不到

猜你喜欢

转载自blog.csdn.net/michael_cool/article/details/80327877