Python学习总结

1.学习python目的,了解

1.1 为什么要学python?
    -朋友推荐
    -了解
      - 简单易学
      - 生态圈比较强大
      - 发展趋势:人工智能、数据分析

1.2 谈谈你对Python(解释型语言、弱类型语言)和其他语言的区别?   一、编译型语言:一次性,将全部的程序编译成二进制文件,然后在运行。(c,c
++ ,go)     优点:运行速度快。     缺点:开发效率低,不能跨平台。   二、解释型语言:当你的程序运行时,一行一行的解释,并运行。(python , PHP)     优点:调试代码很方便,开发效率高,并且可以跨平台。     缺点:运行速度慢。     混合型:(C#,Java) 开发效率非常高,Python有非常强大的第三方库 高级语言--Python语言编写程序的时候,无需考虑诸如如何管理你的程序使用的内存一类的底层细节 可移植性--Python程序无需修改就几乎可以在市场上所有的系统平台上运行 可扩展性--可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们。 可嵌入性--可以把Python嵌入你的C/C++程序,从而向你的程序用户提供脚本功能。

2.基础

字符串

字符串是一个有序的字符的集合,用于存储和表示基本的文件信息

  字符串特性:

    1、只能存放一个值

    2、不可变

    3、按照从左到右的顺序定义字符集和,索引从0开始有序访问

  定义方法:a='qwe'

字符串常用方法:

s1='abc             '
s2='**********abc*******'
print(s1.strip(' '))
print(s2.strip('*'))
输出结果:
abc
abc

 .capitalize()       首字母大写
s1='abcdef'
print(s1.capitalize())
执行结果
Abcdef
  .upper        所有字母大写
s1='abcdef'
print(s1.upper())
输出结果
ABCDEF
  .lower         所以字母小写
s1='ABCdef'
print(s1.lower())
输出结果
abcdef
  .center(30,'#')     宽度为30个字符,S1居中显示,不够30个用#补满
s1='ABCdef'
print(s1.center(30,'#'))
输出结果
############ABCdef############
  .count('n')       统计某个字符出现了几次
s1='aaaABCdaaefaa'
print(s1.count('a'))
输出结果
7
  count('n',x,y) 统计x到y中有几个n
s1='aaaABCdaaefaa'
print(s1.count('a',0,8))
输出结果
4
  .endswith(‘x’)    判断是否以x结尾
s1='aaaABCdaaefaa'
print(s1.endswith('a'))
执行结果
True
  .startswith(‘x’)    判断是否以x开头
s1='aaaABCdaaefaa'
print(s1.startswith('b'))    
执行结果
False                #括号内的b换成a就会是True
  .find()       找出某个字母所在的值
s1='aaaABCdaaefaa'
print(s1.find('C'))
执行结果
5
  .format()      格式化字符串

msg1='Name:{},age:{},sex:{}'
print(msg1)
print(msg1.format('egon',18,'male'))
msg2='Name:{0},age:{1},sex:{0}'
print(msg2.format('aaaaaaaaaaaaaaaaa','bbbbbbbbbbbbbb'))
msg3='Name:{x},age:{y},sex:{z}'
print(msg3.format(y=18,x='egon',z='male'))
输出结果:
Name:{},age:{},sex:{}
Name:egon,age:18,sex:male
Name:aaaaaaaaaaaaaaaaa,age:bbbbbbbbbbbbbb,sex:aaaaaaaaaaaaaaaaa
Name:egon,age:18,sex:male

  .index(‘x’)    查看x在第几位
s1='aaaABCdaaefaa'
print(s1.index('d'))
执行结果
6
  .isdigit()      判断变量是不是数字
s1='aaaABCdaaefaa'
print(s1.isdigit())
执行结果
False            #很显然S1不是数字,如果是数字执行结果会是True
  .replace()       替换字符 

s1='aaaABCdaaefaa'
print(s1.replace('a','G'))
执行结果
GGGABCdGGefGG      #把a替换成G

s1='aaaABCdaaefaa'
print(s1.replace('a','G',2))
执行结果
GGaABCdaaefaa        #第二个数字指定a替换几次
复制代码
  .split()         分割
msg='/etc/a.txt|365|get'
print(msg.split('|'))
执行结果
['/etc/a.txt', '365', 'get']
  .islower()     判断字符串是否全部小写
s1='aaaABCdaaefaa'
print(s1.islower())
执行结果
False
  .isspace()     判断是否全都是空格
s2='                     '
print(s2.isspace())
执行结果
True
  .istitle()     判断首字母是否大写
s1='aaaABC'
print(s1.istitle())
执行结果
False
  .ljust(10,‘*’)     总共十个字符左对齐不够用*填充
s1='aaaABC'
print(s1.ljust(10,'*'))
执行结果
aaaABC****
  .rjust                              相反,右对齐
  执行结果****aaaABC
字符串方法

列表

特性:list中的元素可以随意删除增加且list的id和type不会改变,ist是一种可变类型.列表中的所有元素可以是 int 可以是 str 也可以是list(子列表).list中的值是有序的。

列表操作方法

定义列表:li = [11,22,33,44,55,66]

  取值:通过索引
    print (li[1])
切片

  li =[11,22,33,44,55,66]
  print(l[1:5])
  追加
  li.append()     向后追加元素
  插入
  li.insert(1,‘SB’)          在指定索引的位置插入值
  删除
  li.pop()          移除最后一个值    a=.pop() 在原列表中移除掉最后一个元素并赋值给a
  显示索引位置
  li.index()     获取指定元素的索引位置
  包含
  print(11 in l)
  其他
  .count()     查看有元素出现的次数
  .extend()     批量添加元素
  .remove()     移除某个元素
  .reverse()     把所有元素顺序倒过来,反转
  .sort()     排序
  del 列表名[1]     删除索引指向的元素
   #字符串——>数字    int(字符串)
列表操作

字典

  {花括号}    dict          可变类型,key不可变,value可变

  字典定义的基本形式:key:value
  定义字典需要注意:key必须是不可变类型,或者说是可hash类型
  字典的取值,字典是无序的,不可用索引
  字典的取值需要打印key
字典应用方法
#字典的常用方法

#定义字典
d={'x':1,'y':12222}

#长度
 len(d)

#新增
 d['x']=2
 print(d)

#遍历
print(d.items())
 for item in d.items(): #[('x', 1), ('y', 12222)]
     print(item)         #以元组的形式取出键值对
 for k,v in d.items():   #解压键值对
     print(k,v)
 print(d.keys())              # 获取所有的key
 print(d.values())              # 获取所有的values
 print(d.itmes())          #获取所有的元素

查找
 print(d.get('y'))
 print(d.get('y','找不到'))
 print(d.get('e','找不到'))

删除键值对
 d.pop('x')
 print(d)

随机删除键值对
 print(d.popitem())
 print(d)

清除元素
 d.clear()
print(d)

#快速产生字典
 d1={}
 d2=dict()
 d3=dict(x=1,y=2,z=3)
 d4=dict({'x':1,'y':2,'z':3})
 d5=dict([('x',1),('y',2),('z',3)])
 d6={}.fromkeys(['name','age'],None) #把key的值都设置成None,用于创建初始的字典
 print(d1,d2,d3,d4,d5,d6)

#更新字典元素,覆盖
 d={'name':'alex'}
 d1={'name':'alexsb','age':50}
 d.update(d1)
 print(d)
字典方法

元组

特性:元组内的所有元素不能更改,元素可以是任意数据类型

元组中可以包含list,元组中的list中的元素是可以更改的.当然list中也可以有元组.

定义元组

  name_tuple = ('alex','eric')
  索引
  print(name_tuple[0])
  len
  print(name_tuple[len(name_tuple)-1])
  切片
  print(name_tuple[0:1])
  for
  for i  in name_tuple:
       print(i)
  count:计算元素出现的个数
  print(name_tupel.count('alex'))
  index:获取指定元素的索引位置
  print(name_tupel.index('alex'))
元组操作

集合

作用:去重,关系运算

#定义集合:
 #集合内的元素必须的唯一的
#集合内的元素必须是可hash(不可变)的
#集合是无序的
 s={'sam',123,'sam'}
print(s,type(s))
#循环
 s={'1',1,(1,2),'a'}
 for i in s:
     print(i)
#关系运算
 python_l={'egon','alex','铁蛋','老王'}
 linux_l={'alex','铁蛋','矮跟','欧德博爱'}
 #取共同部分:交集
 print(python_l & linux_l)
# #取老男孩所有报名学生:并集
 print(python_l | linux_l)
 #取只报名了python和只报名了linux的学生:差集
 print(python_l - linux_l)
 print(linux_l - python_l)
# #取没有同时报名python和linux的学生:对称差集
 print(python_l ^ linux_l)

#集合方法
 python_l={'egon','alex','铁蛋','老王'}
 linux_l={'alex','铁蛋','矮跟','欧德博爱'}

 print(python_l.difference(linux_l))#python -linux
 print(python_l.intersection(linux_l))#交集
 print(python_l.union(linux_l))#并集
 print(python_l.symmetric_difference(linux_l))#对称差集

 python_l={'egon','alex','铁蛋','老王'}
 linux_l={'alex','铁蛋','矮跟','欧德博爱'}
 python_l.difference_update(linux_l)
 print(python_l)  #对称差集并更新

 s1={'a',1}
 s2={'a','b',2}

 s1.update(s2)
 print(s1)               #把S2的内容更新到S1里

 s1={1,2}
 s2={1,2,3}
 print(s1.issubset(s2))#子集
 print(s2.issuperset(s1))#父集

 s1={'a',1}
 s1.add(1)
 print(s1)       #添加元素,元素存在不修改

 s1.discard('a')   #删除元素,元素不存在也不报错
 s1.discard('b')
 print(s1)

 s1.remove('nnnnnn')     #删除元素,元素不存在就报错
 print(s1)

 s1={'a',1,'b','c','d'}
 print(s1.pop())           #.pop随机删除
 print(s1)

 s1={1,2,'a'}
 s2={1,2,3}
print(s1.intersection(s2))  #判断是否有交集,有则返回值
print(s1.isdisjoint(s2))   #判断是否没有交集,有则返回False

 s1={'a','b'}
 s2={'c','d'}
 print(s1.isdisjoint(s2))    #没有交集返回True
集合方法

深浅拷贝

在Python中对象的赋值其实就是对象的引用。当创建一个对象,把它赋值给另一个变量的时候,python并没有拷贝这个对象,只是拷贝了这个对象的引用而已。

浅拷贝:拷贝了最外围的对象本身,内部的元素都只是拷贝了一个引用而已。也就是,把对象复制一遍,但是该对象中引用的其他对象我不复制

深拷贝:外围和内部元素都进行了拷贝对象本身,而不是引用。也就是,把对象复制一遍,并且该对象中引用的其他对象我也复制。

###############################

浅拷贝copy ,第一层创建的是新的内存地址,而从第二层开始,指向的都是同一个内存地址,所以,对于第二层以及更深的层数来说,与原内存地址不变。

l1 = [1,[22,33,44],3,4,]
l2 = l1.copy()
l1[1].append('55')

print(l1,id(l1),id(l1[1]))      #[1, [22, 33, 44, '55'], 3, 4] 1787518244744 1787518244808
print(l2,id(l2),id(l2[1]))        #[1, [22, 33, 44, '55'], 3, 4] 1787518244616 1787518244808
############
l1[1].append("cao")
print(l1)   #[1, [22, 33, 44, '55', 'cao'], 3, 4]
print(l2)  #[1, [22, 33, 44, '55', 'cao'], 3, 4]

#########################
l1[0] = "chao"
print(l1)   #['chao', [22, 33, 44, '55'], 3, 4]
print(l2)  #[1, [22, 33, 44, '55'], 3, 4]
浅拷贝示例

深拷贝deepcopy,两个是完全独立的,改变任意一个的任何元素(无论多少层),另一个绝对不改变。

import copy
l1 = [1,[22,33,44],3,4,]
l2 = copy.deepcopy(l1)

print(id(l1[1]))
print(id(l2[1]))
print("="*20)

l1[0] = 111
print(l1)
print(l2)
print("="*20)

l1[1].append('barry')
print(l1)
print(l2)

############
1742824920520
====================
[111, [22, 33, 44], 3, 4]
[1, [22, 33, 44], 3, 4]
====================
[111, [22, 33, 44, 'barry'], 3, 4]
[1, [22, 33, 44], 3, 4]
深拷贝示例

 

函数

- 函数参数传递的是什么?
                    引用(传的是地址)

函数的优点:1.代码重用

      2.保持一致性,易于维护

      3.可扩展性好

 
注意坑:传值为列表,可变类型
 

 

lambda表达式:

 

闭包

def foo():
    m=3
    n=5
    def bar():
        a=4
        return m+n+a
    return bar
  
>>>bar =  foo()
>>>bar()


说明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。

在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。
简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。
闭包的意义与应用:延迟计算:
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域 
#应用领域:延迟计算(原来我们是传参,现在我们是包起来)
装饰器就是闭包函数的一种应用场景

 

常见内置函数:

- map - filter

map()函数接收两个参数,一个是函数,一个是可迭代对象,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
def mul(x):
    return x*x

n=[1,2,3,4,5]
res=list(map(mul,n))
print(res)  #[1, 4, 9, 16, 25]

filter()函数接收一个函数 f 和一个list,这个函数 f 的作用是对每个元素进行判断,返回 True或 False,
filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的新list。
def is_odd(x):
    return x % 2 == 1

v=list(filter(is_odd, [1, 4, 6, 7, 9, 12, 17]))
print(v)  #[1, 7, 9, 17]
View Code

- 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)]
>>> zip(*zipped)          # 与 zip 相反,可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]
View Code

- reduce

reduce() 函数会对参数序列中元素进行累积。

用传给reduce中的函数 function(有两个参数)先对集合中的第1、2个元素进行操作,得到的结果再与第三个数据用function函数运算,最后得到一个结果。

>>>def add(x, y) :            # 两数相加
...     return x + y
... 
>>> reduce(add, [1,2,3,4,5])   # 计算列表和:1+2+3+4+5
>>> reduce(lambda x, y: x+y, [1,2,3,4,5])  # 使用 lambda 匿名函数
View Code

 

装饰器

什么是装饰器及作用?

在不改变原函数的基础上,对函数执行前后进行自定义操作。

 

迭代器

内部实现__next__方法,帮助我们向后一个一个取值。

可迭代对象:一个类中内部实现__iter__方法,且返回一个迭代器

迭代器的特点:
  惰性运算
  从前到后一次去取值,过程不可逆 不可重复
  节省内存

 

生成器

生成器:一个函数调用时返回一个迭代器,或 函数中包含yield语法,那这个函数就会变成生成器

 
 

偏函数

偏函数:
import functools
def func(a1, a2, a3):
    return a1 + a2 + a3

new_func = functools.partial(func, 11, 2)  #将11,2依次传入到func函数的前两个参数
print(new_func(3))

应用场景
falsk中取值时 通过localproxy 、偏函数、localstack、local

 

3.面向对象

python中一切皆对象,函数也是对象,类也是对象。

 三大特性:

继承:

将多个类共用的方法提取到父类中,子类仅需继承父类,而不必一一实现每个方法。

 

封装:

将同一类方法分为一类:方法封装到类中,
将方法中共同的参数封装到对象中:把共用值封装到对象中。
 

多态:

多态:是指基类的同一方法在不同的派生类对象中具有不同的表现和行为。

 Python不崇尚多态,因为自带多态,崇尚鸭子类型

双下划线方法:

1、__init__:
    在类实例化成对象时,会首先调用__init__方法。
    __init__的返回值一定要是None

2、__new__:
    __new__方法是在一个对象实例化的时候调用的第一个方法,不过一般都是用python默认的一般很少重写,只有当继承的类是一个不可变类型的时候才会去重写,__new__方法,第一个参数是这个类(cls)。
这个方法需要返回一个实例对象,通常是cls实例化的对象,也可以是其他的。

3.__del__:
当对象将要被销毁的时候该方法就会被调用。

4.__dict__:
python中__dict__存储了该对象的一些属性。是一个字典,键为属性名,值为属性值。类和实例分别拥有自己的__dict__,且实例会共享类的__dict__。在__init__中,self.xxx = xxx会把变量存在实例的__dict__中,仅会在该实例中能获取到,而在方法体外声明的,会在class的__dict__中。

5.__dir__:
  __dict__与dir()的区别:
dir()是一个函数,返回的是list。dir()用来寻找一个对象的所有属性,包括__dict__中的属性,__dict__是dir()的子集;并不是所有对象都拥有__dict__属性。许多内建类型就没有__dict__属性,如list,此时就需要用dir()来列出对象的所有属性。

6、__getitem__(self,key):
返回键对应的值。
print(obj.["xxx"])

7、__setitem__(self,key,value):
设置给定键的值 
obj.["xxx"]=123

8、__delitem__(self,key):
删除给定键对应的元素。

9、__len__():
返回元素的数量

10.__setattr__
如果类自定义了__setattr__方法,当通过实例获取属性尝试赋值时,就会调用__setattr__。常规的对实例属性赋值,被赋值的属性和值会存入实例属性字典__dict__中。

12、__getattr__:实例instance(类名)通过instance.name访问属性name,__getattr__方法一直会被调用,无论属性name是否存在。找不到回去调用父类的__getattr__,如果当前类还定义了__getattr__方法,除非通过__getattr__显式的调用它,或者__getattr__方法出现AttributeError错误,否则__getattr__方法不会被调用了。如果在__getattr__方法下存在通过self.attr访问属性,会出现无限递归错误。类中中定义了__getattr__方法,实例instance获取属性时,都会调用__getattr__返回结果,即使是访问__dict__属性。

13、__call____call__方法用于实例自身的调用14、__str__:
用来返回对象的字符串表达式。
15、__mro__:
16、 - metaclass
          - 作用:用于指定使用哪个类来创建当前类
          - 场景:在类创建之前定制操作

   示例:wtforms中,对字段进行排序。

查看当前类继承了哪些类。
__双线方法__

 

⾯向对象深度优先和广度优先是什么?

Python的类可以继承多个类,Python的类如果继承了多个类,那么其寻找方法的方式有两种

当类是经典类时,多继承情况下,会按照深度优先方式查找

当类是新式类时,多继承情况下,会按照广度优先方式查找

简单点说就是:经典类是纵向查找,新式类是横向查找

经典类和新式类的区别就是,在声明类的时候,新式类需要加上object关键字。在python3中默认全是新式类

什么是函数什么是方法

from types import MethodType,FunctionType

class Foo(object):
    def fetch(self):
        pass
       Foo.fetch   此时fetch为函数
print(isinstance(Foo.fetch,MethodType))
print(isinstance(Foo.fetch,FunctionType)) # True

obj = Foo()
       obj.fetch  此时fetch为方法
print(isinstance(obj.fetch,MethodType)) # True
print(isinstance(obj.fetch,FunctionType))

 

4.模块

你常用的模块?

- re/json/logging/os/sys
- requests/beautifulsoup4

 

5.re正则

.     匹配除换行符以外的任意字符
\w    匹配字母或数字或下划线
\s    匹配任意的空白符
\d    匹配数字
\n    匹配一个换行符
\t    匹配一个制表符
\b    匹配一个单词的结尾
^    匹配字符串的开始
$    匹配字符串的结尾
\W    
匹配非字母或数字或下划线
\D    
匹配非数字
\S    
匹配非空白符
a|b    
匹配字符a或字符b
()    
匹配括号内的表达式,也表示一个组
[...]    
匹配字符组中的字符
[^...]    
匹配除了字符组中字符的所有字符
 

用法说明
*    重复零次或更多次
+    重复一次或更多次
?    重复零次或一次
{n}    重复n次
{n,}    重复n次或更多次
{n,m}    重复n到m次
正则

 

- 写一个常见正则:邮箱/手机号/IP

#匹配手机号
import re

def phone(arg):
    s=re.match("^(13|14|15|18)[0-9]{9}$",arg)
    if s:
        return "正确"
    return "错误"

print(phone("23722751552"))
#匹配邮箱 
  re.match("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$",arg)
#匹配IP
  
re.match("\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b",arg)
?: 优先匹配
\b 匹配一个单词的结尾

-match和search的区别

  re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;

  re.search匹配整个字符串,直到找到一个匹配。

import re
s="fnfffidvvgf"

m=re.match("fi",s)
print(m)  #None
s=re.search("fi",s).group()
print(s)  #fi

-贪婪匹配与非贪婪匹配

  贪婪匹配:   匹配1次或多次<.+>     匹配0次或多次<.*>

  非贪婪匹配:匹配0次或1次<.?>

 

6.给出路径找文件

方法一: 使用os.walk
file-- 是你所要便利的目录的地址, 返回的是一个三元组(root,dirs,files)。

root 所指的是当前正在遍历的这个文件夹的本身的地址
dirs 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
files 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)
def open_2(file):

    for root, dirs , files in os.walk(file):
        print("ss",files)
        for filename in files:
            print(os.path.abspath(os.path.join(root, filename)))   #返回绝对路径

open_2("F:\搜索")


方法二:
import os
def open(files):

    for dir_file in os.listdir(files):
        # print("ss",dir_file)   #递归获取所有文件夹和文件
        files_dir_file = os.path.join(files, dir_file) 

        if os.path.isdir(files_dir_file):  #是不是文件夹
            open(files_dir_file)
        else:
            print(files_dir_file)

open("F:\搜索")


并将下面的所有文件内容写入到一个文件中
def open_2(file):
    for root, dirs , files in os.walk(file):
        for filename in files:
            with open(os.path.abspath(os.path.join(root, filename)), "r") as f:
                for i in f.readlines():
                    print(i)
                    with open("./cao.txt","a",encoding="utf-8") as f2:
                        f2.write(i)
                        f2.write("\n")
open_2("F:\搜索")

示例
示例

创建删除文件

1 # 创建一个文件
2 open("chao.txt","w",encoding="utf-8")
3 import os
  #删除文件
4 os.remove("chao.txt")

 


 第三方软件安装:
- pip包管理器
- 源码安装
- 下载
- 解压
- python setup.py build
- python setup.py install

7.网络编程

 OSI 7层协议

互联网协议按照功能不同分为osi七层或tcp/ip五层或tcp/ip四层

物理层:主要是基于电器特性发送高低电压(电信号),高电压1,低电压0,设备有集线器,中继器,双绞线等!  单位:bit比特

数据链路层:定义了电信号的分组方式     设备有:网桥、以太网交换机、网卡   单位:帧

网络层:主要功能是将网络地址翻译成对应的物理地址    路由

传输层:建立端口到端口之间的通信    tcp协议udp协议

会话层:建立客户端与服务端连接

表示层:对来自应用层的命令和数据进行解释,并按照一定的格式传送给会话层。如编码、 数据格式转换和加密解密,压缩解压缩"等

应用层:规定应用程序的数据格式


 进程、线程、协程区别?

 

进程:正在执行的一个程序或者一个任务,而执行任务的是cpu
    每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,
    相比线程数据相对比较稳定安全。

线程:线程是进程的一个实体,是CPU调度和分派的基本单位
    线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

协程:是一种“微线程”,实际并不存在,是程序员人为创造出来的控制程序调度的(程序执行一段代码,切换执行另一段代码)  它可以实现单线程下的并发、
    1、程序执行遇到IO切换,性能提高,实现了并发
    2、无IO时切换,性能降低
  优点:
    1. 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级
    2. 单线程内就可以实现并发的效果,最大限度地利用cpu
1、进程多与线程比较
  1) 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
  2) 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
  3) 线程是处理器调度的基本单位,但进程不是
  4) 二者均可并发执行
  5) 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
2、协程多与线程进行比较
  1) 一个线程可以多个协程,一个进程也可以单独拥有多个协程,这样python中则能使用多核CPU。
  2) 线程进程都是同步机制,而协程则是异步
  3) 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态

 

进程池和线程池

  进程池

from concurrent.futures import ProcessPoolExecutor
import time,os
def piao(name,n):
    print('%s '%(name))
    time.sleep(2)
    return n**3
if __name__=='__main__':
    p = ProcessPoolExecutor(4)
    objs= []
    for i in range(10):
        obj = p.submit(piao,'sb %s'%i,i)
        objs.append(obj)   
    p.shutdown(wait=True)
    print("",os.getpid())
    for obj in objs:
        print(obj.result())

异步调用
异步调用
from concurrent.futures import ProcessPoolExecutor
import time,os
def piao(name,n):
    print('%s is pioing %s'%(name,os.getpid()))
    return n**2
if __name__=='__main__':
    p = ProcessPoolExecutor(4)
    for i in range(10):
        res = p.submit(piao,'alex %s'%i,i).result()
        print(res)
    p.shutdown(wait=True)
    print('',os.getpid())

同步调用
同步调用

  线程池

from concurrent.futures import ThreadPoolExecutor
from threading import current_thread
import time,random
def task(n):
    print('%s is running' %current_thread().getName())
    time.sleep(random.randint(1,3))
    return n**2

if __name__ == '__main__':
    # t=ProcessPoolExecutor() #默认是cpu的核数
    # import os
    # print(os.cpu_count())

    t=ThreadPoolExecutor(3) #默认是cpu的核数*5
    objs=[]
    for i in range(10):
        obj=t.submit(task,i)
        objs.append(obj)
        
    t.shutdown(wait=True)
    for obj in objs:
        print(obj.result())
    print('',current_thread().getName())
View Code
 
异步非阻塞?
  异步:回调,到达某个指定的状态之后,自动调用特定函数,示例:(nb_async.py 实现异步非阻塞的模块)
  非阻塞: 不等待,加上代码  sk = socket.socket()            sk.setblocking(False)  报错捕捉异常
 

 IO多路复用

  监听多个socket是否发生变化

  -select ,内部循环检测socket是否发生变化; 1024个socket
        -poll , 内部循环检测socket是否发生变化; 1024个socket
        -epoll    回调的方式
 

HTTP协议本质?

  建立在TCP协议之上,这个协议规定了请求头和请求体直接通过\r\n \r\n分割,无状态,短链接

 

TCP和UDP

  tcp是基于连接的,必须先启动服务端,然后再启动客户端去连接服务端

  udp是无连接的,先启动哪一端都可以  (应用:QQ聊天)

 

三次握手,四次挥手:

    SYC=1(建立连接)  ACK(确认请求)

    1、客户端(Client)向服务端(Server)发一次请求(SYN=1,随机产生一个值seq=J)

    2、服务端确认并回复客户端(ACK=1, SYC=1,并在seq基础上产生一个随机数发给客户端)

    3、客户端检验确认请求(ACK=1)     此时客户端与服务端就建立了连接

  四次挥手:

    FAN=1(断连接) ACK=1(确认请求)

    1、客户端向服务端发一次请求(FAN=1)

    2、服务端回复客户端 (ACK=1)  (断开客户端—>服务端)

    3、服务端再向客户端发请求(FAN=1)  (因为有数据传输,所以2、3不能合并)

    4、客户端确认请求(ACK=1)        (断开服务端--->客户端)


-GIL锁?

  GIL互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。


-进程池和线程池?

.....

8.数据库

1.引擎

innodb    支持事务(回滚)、表锁、行锁(select id,name from user where id=2 for update)

myisam    支持全文索引、表锁(- select * from user for update)

2.设计表

权限表、BBS、权限

注意:FK   M2M

3.数据操作

练习题

多表联查:
select * from tb1,tb2    没有where条件时,笛卡尔乘积效果

left join  以左表为基准,显示所有的内容,右表没有对应项时,显示null
  select * from tb1 left join tb2 on tb1.id=tb2.id; 
inner join 只显示两张表共同内容
  select * from tb1 inner join tb2 on tb1.id=tb2.id;
union  显示两张表所有内容
  select * from tb1 left join tb2 on tb1.id=tb2.id union select * from tb2 left join tb1 on tb1.id=tb2.id; 


分组函数
  select 部门ID,max(id) from 用户表 group by 部门ID having count(id)>3 
  group by 字段  having   判断条件   (固定语法)分组和聚合函数搭配

4.索引

创建表+索引
create table tb( id int not null primary key 
           name varchar(32),
           pwd varchar(32)
           unique tb_pwd (pwd))

普通索引:create index tb_name on tb(name)
联合索引:create index tb_name_age on tb(name,age)

原理:B+/哈希索引    查找速度快;更新速度慢

1、索引一定是为搜索条件的字段创建的
 2、innodb表的索引会存放于s1.ibd文件中,而myisam表的索引则会有单独的索引文件table1.MYI
 
单列:
  1、普通索引 index     加速查找
  2、唯一索引 unique    加速查找+不能重复
  3、主键索引 primary key 加速查找+不能重复+不能为空
多列:
  1、联合索引  
  2、联合唯一索引
  3、联合主键索引

联合索引遵从最左前缀原则
 如果组合索引为:(name,email)
                name and email       -- 使用索引
                name                 -- 使用索引
                email                -- 不使用索引
其它操作:
  索引合并:利用多个单例索引查找  
  覆盖索引:在索引表中就能查到想要的数据

创建了索引,但无法命中

- like '%xx'
                select * from tb1 where name like '%cn';
            - 使用函数
                select * from tb1 where reverse(name) = 'wupeiqi';
            - or
                select * from tb1 where nid = 1 or email = 'seven@live.com';
                特别的:当or条件中有未建立索引的列才失效,以下会走索引
                        select * from tb1 where nid = 1 or name = 'seven';
                        select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
            - 类型不一致
                如果列是字符串类型,传入条件是必须用引号引起来,不然...
                select * from tb1 where name = 999;
            - !=
                select * from tb1 where name != 'alex'
                特别的:如果是主键,则还是会走索引
                    select * from tb1 where nid != 123
            - >
                select * from tb1 where name > 'alex'
                特别的:如果是主键或索引是整数类型,则还是会走索引
                    select * from tb1 where nid > 123
                    select * from tb1 where num > 123
            - order by
                select email from tb1 order by name desc;
                当根据索引排序时候,选择的映射如果不是索引,则不走索引
                特别的:如果对主键排序,则还是走索引:
                    select * from tb1 order by nid desc;
View Code

 存储过程、视图、函数、触发器

存储过程、视图、函数、触发器、都是保存在数据库中

触发器:在数据库中对某张表进行“增删改”时,添加一些操作

视图:一张虚拟表,根据SQL语句动态的获取数据集,并命名,下次使用时直接调用名称(只能查)

v = select * from tb where id <1000
select * from v 
等同于:                  
select * from (select * from tb where id <1000) as v 

存储过程:将常用的sql语句命名保存到数据库中,使用时可以直接调用名称

     参数有:in(入参类型) out(出参类型) inout(出入参类型)

函数:在sql语句中使用

  - 聚合:max/sum/min/avg
  - 时间格式化 date_format
  - 字符串拼接 concat

存储过程与函数的区别:

区别:
  函数                            存储过程
  必须有返回值 return                 可以通过out、inout返回零各或多个值 
  不能单独使用,必须作为表达式的一部分         可以作为一个独立的sql语句执行
  sql语句中可以直接调用函数           sql中不能调用过程

分页

 select * form tb limit 10 offset 0

数据量过大,页数越大,查询速度越慢,因为页数越大,数据id就越大,查询时就会从头开始扫描数据,

解决办法:

方案一:
  1、记录当期页,数据ID的最大值、最小值,
  2、翻页查询时,先根据数据ID筛选数据,在limit查询
  select * from (select * from tb where id > 22222222) as B limit 10 offset 0
  如果用户自己修改url上的页码,我们可以参考rest-frameword中的分页,对url中的页码进行加密处理

方案二:
  可以根据实际业务需求,只展示部分数据(只显示200-300页的数据)

慢日志查询

slow_query_log = ON                            是否开启慢日志记录
long_query_time = 2                            时间限制,超过此时间,则记录
slow_query_log_file = /usr/slow.log          日志文件
log_queries_not_using_indexes = ON          为使用索引的搜索是否记录

数据库导入导出

导入:mysqldump -u root -p db > F:\db.txt
导出:mysqldump -u root -p db < F:\db.txt;  

执行计划

explain  select * from tb;   #查看sql语句执行速度

优化

- 不用 select * 
- 固定长度字段列,往前放
- char(固定长度)和varchar
- 固定数据放入内存:choice 
- 索引遵循最左前缀
- 读写分离,利用数据库的主从进行分离:主,用于删除、修改更新;从,查。 - 分库,当数据库中表太多,将表分到不同的数据库;例如:1w张表 - 分表   - 水平分表,将某些列拆分到另外一张表;例如:博客+博客详细   - 垂直分表,将历史信息分到另外一张表中;例如:账单 - 缓存:利用redis、memcache,将常用的数据放入缓存中 -查询一条数据   select * from tb where name='alex' limit 1 -text类型  为前面几个字符串创建索引

9.栈

class Stack():
    def __init__(self,size):
        self.size=size
        self.stack=[]

    def getstack(self):
        """
        #获取栈当前数据
        :return:
        """
        return self.stack

    def __str__(self):
        return str(self.stack)

    def top(self,x):
    # 入栈之前检查栈是否已满
        if self.isfull():
            raise Exception("stack is full")
        else:
            self.stack.append(x)

    def pop(self):
        """
        # 出栈之前检查栈是否已空
        :return:
        """
        if self.isempty():
            raise Exception("stack is empty")
        else:
            self.stack.pop()

    def isfull(self):
        """
        判断栈满
        :return:
        """
        if len(self.stack)==self.size:
            return True
        return False

    def isempty(self):
        """
        判断栈空
        :return:
        """
        if len(self.stack)==0:
            return True
        return False

if __name__ == '__main__' :
    stack=Stack(4)

    for i in range(11):
        stack.top(i)
        print(stack.getstack())

    for i in range(3):
        stack.pop()
        print(stack.getstack())
View Code

10.爬虫相关

- request/bs4
  - requests模块
    - 参数:
      - url
      - headers
      - cookies
      - data
      - json
      - params
      - proxy
    - 返回值:
      - content
      - iter_content
      - text
      - encoding="utf-8"
      - cookie.get_dict()
    - bs4
      - 解析:html.parser -> lxml
      - find
      - find_all
      - text
      - attrs
      - get
    - 其他:
      常见请求头:
        - user-agent
        - host
        - referer
        - cookie
        - content-type
      套路:
        - 先给你cookie,然后再给你授权。
        - 凭证
      轮询+长轮询
    - scrapy
      - 高性能相关,单线程并发发送Http请求
      - twisted
      - gevent
      - asyncio
      本质:基于IO多路复用+非阻塞的socket客户端实现


      问题:异步非阻塞?      

      异步:回调,到达某个指定的状态之后,自动调用特定函数,示例:(nb_async.py 实现异步非阻塞的模块)
      非阻塞: 不等待,加上代码  sk = socket.socket()            sk.setblocking(False)  报错捕捉异常

    问题:什么是协程?
        

    - 是“微线程”,不存在;是由程序员认为创造出来并控制程序:先执行某段代码、再跳到某处执行某段代码。
          -如果遇到非IO请求来回切换:性能更低。
          -如果遇到IO(耗时)请求来回切换:性能高、实现并发(本质上利用IO等待的过程,再去干一些其他的事)


    - scrapy框架
      - scrapy执行流程(包含所有组件)
      - 记录爬虫爬取数据深度(层级),request.meta['depth']
      - 传递cookie
        - 手动
        - 自动:meta={'cookiejar':True}

      - 起始URL
      - 持久化:pipelines/items
      - 去重
      - 调度器
      - 中间件
        - 下载中间件
          - agent
          - proxy
        - 爬虫中间件
          - depth
      - 扩展+信号
      - 自定义命令
    - scrapy-redis组件,本质:去重、调度器任务、pipeline、起始URL放到redis中。
      - 去重,使用的redis的集合。
      - 调度器,
        - redis列表
          - 先进先出队列
          - 后进先出栈
        - redis有序集合
          - 优先级队列

        PS:深度和广度优先
      - pipelines
        - redis列表

      - 起始URL
        - redis列表
        - redis集合

      补充:
        自定义encoder实现序列化时间等特殊类型:
        json.dumps(xx,cls=MyEncoder)

    - scrapy 

 

----------------------整理中----------------------

 

posted @ 2018-05-07 18:22  PengDa  阅读(871)  评论(0)    收藏  举报