标签:面向对象 通过 延迟 如何使用 setup c++ 字节 拼接 内存泄露
谈谈你对python和其他语言的区别
1. python 中,变量是以内容为基准而不是像 c 中以变量名为基准; 2. python 中,一个变量可以以多个名称访问; 3. python 中,数字类型的值是不可变的; 4. python 中,编译器会有一个小整数池的概念
1. 编译型语言:一次性,将全部的程序编译成二进制文件,然后在运行。(c,c++ ,go) 优点:运行速度快。 缺点:开发效率低,不能跨平台。 2. 解释型语言:当你的程序运行时,一行一行的解释,并运行。(python , PHP) 优点:调试代码很方便,开发效率高,并且可以跨平台。 缺点:运行速度慢。
3. 我对程序的定义是人可以读懂,而机器刚好可以执行的一段代码,注重于代码的可读性。
而Python的定位是“优雅”、“明确”、“简单”,用它编写的程序简单易懂,这与我当初的想法不谋而合
列表:list - list.append(obj) # 在列表末尾添加新的对象 - list.count(obj) # 统计某个元素在列表中出现的次数 - list.extend(seq) # 在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) - list.index(obj) # 从列表中找出某个值第一个匹配项的索引位置 - list.insert(index, obj)# 将对象插入列表 - list.pop(obj=list[-1]) # 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 - list.remove(obj) # 移除列表中某个值的第一个匹配项 - list.reverse() # 反向列表中元素 - list.sort([func])# 对原列表进行排序 - list.clear() # 清空列表 - list.copy() # 复制列表 字典:dict - popitem() # 随机返回并删除字典中的一对键和值(一般删除末尾对)。 - key in dict # 如果键在字典dict里返回true,否则返回false - radiansdict.copy() # 返回一个字典的浅复制 - radiansdict.keys() # 以列表返回一个字典所有的键 - radiansdict.items() # 以列表返回可遍历的(键, 值) 元组数组 - radiansdict.clear() # 删除字典内所有元素 - radiansdict.values() # 以列表返回字典中的所有值 - radiansdict.fromkeys() # 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 - radiansdict.update(dict2) # 把字典dict2的键/值对更新到dict里 - radiansdict.get(key, default=None) # 返回指定键的值,如果值不在字典中返回default值 - radiansdict.setdefault(key, default=None) # 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default - pop(key[,default]) # 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。 字符串:str - upper() # 转换字符串中的小写字母为大写。 - title() # 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见 istitle())。 - lower() # 转换字符串中所有大写字符为小写。 - rstrip() # 删除字符串字符串末尾的空格. - lstrip() # 截掉字符串左边的空格或指定字符。 - max(str) # 返回字符串 str 中最大的字母。 - min(str) # 返回字符串 str 中最小的字母。 - join(seq) # 以指定字符串作为分隔符,将 seq 中所有的元素(的字符串表示)合并为一个新的字符串 ... MySlef 整数:int - bit_length() # 查询以二进制表示一个数字的值所需的位数 - int.from_bytes(bytes,byteorder) # 返回给定字节数组所表示的整数。 - int.to_bytes(length,byteorder) # 返回表示整数的字节数组。 元组:tuple - len(tuple) # 计算元组元素个数。 - max(tuple) # 返回元组中元素最大值。 - min(tuple) # 返回元组中元素最小值。 - tuple(seq) # 将列表转换为元组。 集合:set - set1 = set({1, 2, ‘barry‘}) # 创建集合 - set2 = {1, 2, ‘barry‘} # 创建集合 - add # 将元素添加到集合中。如果元素已经存在,这不起作用。 - del set1 # 删除集合- update # 迭代增加 - clear # 删除此集合中的所有元素 - remove # 删除一个元素 - pop # 随机删除一个元素 - issubset # 子集 - issuperset # 超集 - union # 并集。(| 或者 union) - difference # 差集。(- 或者 difference) - intersection # 交集。(& 或者 intersection) - isdisjoint # 如果两个集合有一个空交点,则返回True - intersection_update # 用它自己和另一个交集更新一个集合。 - difference_update # 删除另一个集合中本集合所拥有的所有元素 - symmetric_difference # 反交集。 (^ 或者 symmetric_difference) 浮点:float - is_integer # 如果浮点数是整数,则返回True collections:Python内建的一个集合模块,提供了许多有用的集合类。 - Counter # 是一个简单的计数器,例如,统计字符出现的个数: - OrderedDict # 可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key: - deque # 是为了高效实现插入和删除操作的双向列表,适合用于队列和栈: - defaultdict # 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:
可变与不可变类型
可变:
- list, - dict
不可变:
-str, - int, - tuple, - float,
# 默认参数尽量避免使用可变数据类型 # 默认参数只会被执行一次:第一次调用函数时,默认参数被初始化为【】,以后每次调用时都会使用已经初始化的【】。 >>> def func(a,a1 = []): #默认参数 ... a1.append(a) ... print(a1) >>> func() [1] >>> func() [1, 1] >>> func() [1, 1, 1] >>> func() [1, 1, 1, 1]
def foo():
m, n=3, 5
def bar():
a=4
return m+n+a
return bar
>>>bar = foo()
>>>bar()
12
说明:
bar在foo函数的代码块中定义。我们称bar是foo的内部函数。
在bar的局部作用域中可以直接访问foo局部作用域中定义的m、n变量。
简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。
- 闭包的意义与应用: 延迟计算;
- 闭包的意义: 返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域
#应用领域:延迟计算(原来我们是传参,现在我们是包起来)
装饰器就是闭包函数的一种应用场景
介绍:
会根据提供的函数对指定序列做映射。
第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表。
语法:
map(function, iterable, ...)
- function -- 函数,有两个参数
- iterable -- 一个或多个序列
应用示例:
>>>def square(x) : # 计算平方数
... return x ** 2
...
>>> map(square, [1,2,3,4,5]) # 计算列表各个元素的平方
[1, 4, 9, 16, 25]
>>> map(lambda x: x ** 2, [1, 2, 3, 4, 5]) # 使用 lambda 匿名函数
[1, 4, 9, 16, 25]
# 提供了两个列表,对相同位置的列表数据进行相加
>>> map(lambda x, y: x + y, [1, 3, 5, 7, 9], [2, 4, 6, 8, 10])
[3, 7, 11, 15, 19]
介绍:
函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。
该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 True 或 False,最后将返回 True 的元素放到新列表中。
语法:
filter(function, iterable)
- function -- 判断函数。
- iterable -- 可迭代对象。
应用示例1:过滤出列表中的所有奇数:
def is_odd(n):
return n % 2 == 1
newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(newlist)
>>>[1, 3, 5, 7, 9]
应用示例2:过滤出1~100中平方根是整数的数
import math
def is_sqr(x):
return math.sqrt(x) % 1 == 0
newlist = filter(is_sqr, range(1, 101))
print(newlist)
>>>[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
应用示例3:filter相较于py2的区别
python2中返回的是过滤后的列表, 而python3中返回到是一个filter类
filter类实现了__iter__和__next__方法, 可以看成是一个迭代器, 有惰性运算的特性, 相对python2提升了性能, 可以节约内存。
a = filter(lambda x: x % 2 == 0, range(10))
print(a)
>>><filter object at 0x000001CC57668518>
介绍:
函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
语法:
zip([iterable, ...])
- iterabl -- 一个或多个迭代器;
返回值:
- 返回元组列表。
应用示例:
>>>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)]
介绍:
函数来判断一个对象是否是一个已知的类型,类似 type()。
语法:
isinstance(object, classinfo)
- object -- 实例对象。
- classinfo -- 可以是直接或间接类名、基本类型或者由它们组成的元组。
返回值:
如果对象的类型与参数二的类型(classinfo)相同则返回 True,否则返回 False。。
应用示例:
>>>a = 2
>>> isinstance (a,int)
True
>>> isinstance (a,str)
False
>>> isinstance (a,(str,int,list)) # 是元组中的一个返回 True
True
介绍
1. type() 不会认为子类是一种父类类型,不考虑继承关系。
2. isinstance() 会认为子类是一种父类类型,考虑继承关系。
# 如果要判断两个类型是否相同推荐使用 isinstance()。
示例:
class A:
pass
class B(A):
pass
isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
type(B()) == A # returns False
>>> val = "aaa" if 1==1 else "bbb" >>> val ‘aaa‘ >>>
my_lambda = lambda arg : arg + 1
def func(x): return x+1 variable = [ func for num in range(10) if num == 2] func: # 列表生成元素表达式,可以是有返回值的函数或者 lambda 函数。 for num in range(10): # 迭代 range(10) 将 num 传入 func 表达式中。 if num == 2: # 根据条件过滤哪些值可以。
# 错误示例:不能使用列表生成式
a = [lambda :i*i for i in range(31) if i%3 is 0]
# 错误调用方式: # 每次只会返回最后一个被循环的range(30)!
>>>a
[. at 0x000002C97... ,>> a[0]
. at 0x000002C977B96BF8>
>>> a[0]()
900
# 正确示例:使用生成器迭代执行 # 注意括号!
a = (lambda :i*i for i in range(31) if i%3 is 0)
# 调用方式:
>>> a.__iter__
<method-wrapper ‘__iter__‘ of generator object at 0x000002C977AF5938>
>>> a.__iter__()
at 0x000002C977AF5938>
>>> a.__iter__().__next__
<method-wrapper ‘__next__‘ of generator object at 0x000002C977AF5938>
>>> a.__iter__().__next__()
. at 0x000002C977B8CF28>
>>> a.__iter__().__next__()()
9
# 推导式示例: >>> mcase = {‘a‘: 10, ‘b‘: 34} >>> mcase_frequency = {mcase[k]: k for k in mcase} >>> print(mcase_frequency) {10: ‘a‘, 34: ‘b‘}
# _._ >>> mcase = {‘a‘: 10, ‘b‘: 34, ‘A‘: 7, ‘Z‘: 3} >>> mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()} >>> print(mcase_frequency) {‘a‘: 17, ‘b‘: 34, ‘z‘: 3}
# 集合推导式示例 >>> squared = {x**2 for x in [ i for i in range(-5,10) ]} >>> print(squared) {1, 4}
列表推导式list comprehension和生成器的优劣
1. 列表推导式是将所有的值一次性加载到内存中 2. 生成器是将列表推导式的[]改成(),不会将所有的值一次性加载到内存中,延迟计算,一次返回一个结果, 它不会一次生成所有的结果,这对大数据量处理,非常有用 # 生成器函数: 一个函数中包含了yield关键词,那么这个函数就不是普通的函数,是一个生成器函数 # 调用生成器函数,不会立马执行该函数里面的代码, 而是会返回一个 生成器对象
容器:
- 是一系列元素的集合,str、list、set、dict、file、sockets对象都可以看作是容器,容器都可以被迭代(用在for,while等语句中),因此他们被称为可迭代对象。
可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。
迭代器:
- 持有一个内部状态的字段,用于记录下次迭代返回值,它实现了__next__和__iter__方法,迭代器不会一次性把所有元素加载到内存,而是需要的时候才生成返回结果。
生成器:
- 是一种特殊的迭代器,它的返回值不是通过return而是用yield。
装饰器
- 在不改变原函数代码的基础上,在执行前后进行定制操作
- 生成器,一个函数内部存在yield关键字;v = 函数()。
应用场景:
- range/xrange
- py2: range(100000000),立即创建;xrange(100000000)生成器;
- py3: range(100000000)生成器;
- redis获取值
conn = Redis(...)
def hscan_iter(self, name, match=None, count=None):
"""
Make an iterator using the HSCAN command so that the client doesn‘t
need to remember the cursor position.
``match`` allows for filtering the keys by pattern
``count`` allows for hint the minimum number of returns
"""
cursor = ‘0‘
while cursor != 0:
# 去redis中获取数据:12
# cursor,下一次取的位置
# data:本地获取的12条数数据
cursor, data = self.hscan(name, cursor=cursor, match=match, count=count)
for item in data.items():
yield item
- 迭代器,内部实现__next__方法,帮助我们向后一个一个取值。
可迭代对象介绍
- 一个类内部实现 __iter__ 方法且返回一个迭代器
- 实例:
class Foo(object):
def __iter__(self):
return iter([11,22,33,44])
obj = Foo()
- 应用场景:
- wtform中对form对象进行循环时,显示form中包含的所有字段。
- 列表、字典、元组
装饰器介绍
- 在不改变原函数代码的基础上,在执行前后进行定制操作
- 手写
- 应用场景:
- Flask : 路由、before_request、after_request
- Django: csrf、缓存、内置用户登录认证
- functools:缓存、warper
def waper(func):
def inner(*args, **kwargs):
res = func(*args, **kwargs)
return res
return inner
def waper(func, x,y):
print( int(x) + int(y) )
@functools.wapper # 保留原函数信息
def inner(*args, **kwargs):
"""blabla的一些注释"""
res = func(*args, **kwargs)
return res
return inner
@wapper(1,2)
def func(a):
return a
func(123)
- 简单描述 :继承、封装、多态 - 系统描述 :先对代码进行分类:按属性进行划分(file,DB),按功能划分,将同一类方法分为一类。将方法中共同的参数封装到对象中,把共用值封装到对象中。 面向对象的私有字段: - python中一切皆对象 1. 封装:对数据的,对对象的封装。 2. 继承:在类的基础上进行二次开发,通过函数super() 或者"基类名.方法名() "的方式实现这一目的的。 3. 多态:同一个方法处于不同对象中,可以产生不同的结果 - 多态示例
# 鸭子模型
class A:
def send(self):
pass
class B:
def send(self):
pass
def func(arg):
arg.send()
obj = B()
func(obj)
- 双下划线: 1. __getattr__:反射 应用场景: - CBV - Django 配置文件 - wtforms中的Form()实例化中 将"_fields中的数据封装到Form类中" 2. __mro__:定义解析类继承的顺序 应用场景:wtforms中 FormMeta中继承的优先级 3. __dict__:用来存储对象属性的一个字典,其键为属性名,值为属性的值 - __dict__ 与 dir()的区别: 1. dir()是一个函数,返回值是list 2. dir用来寻找一个对象的所有属性值,包括__dict__中的属性,__dict__是dir()的子集 4. __new__ : - 当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。 - 实现自定义 metaclass 应用场景: - wtforms 字段实例化时返回:不是StringField,而是UNboundField - rest_framework:many=Ture 中的序列化 - 单例模式 5. __call__:作用是使实例能够像函数一样被调用,同时不影响实例本身的生命周期, (__call__()不影响一个实例的构造和析构) 但是__call__()可以用来改变实例的内部成员。 __call__ 与 __init__的区别 应用场景: - FLask 请求的入口app.run() - 字段生成标签时:字段.__str__ ==> 字段.__call__ ==> 插件.__call__ 6. __iter__: 迭代器为什么要一定实现__iter__方法(为什么要返回自身) 应用场景:wtforms中BaseForm中循环所有字段时自定义了__iter__方法
- 作用:用于指定当前类事业那个类来创建 - 场景:在类创建之前定制的操作 示例:wtforms中对字段进行排序
super的作用:
子类继承父类的方法,其继承顺序按照 __mro__来定义
新式类跟经典类的差别主要是以下几点: 1. 新式类对象可以直接通过__class__属性获取自身类型:type 2. 继承搜索的顺序发生了改变,经典类多继承属性搜索顺序 : - 先深入继承树左侧,再返回,开始找右侧; - 新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动。 ps:(经典类深度优先,新式类广度优先) 3. 新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。 4. 新式类增加了__getattribute__方法 Python 2.x中默认都是经典类,只有显式继承了object才是新式类 Python 3.x中默认都是新式类,不必显式的继承object
python的类可以继承多个类,python的类如果继承了多个类,那么其寻找的方法有两种: - 当类是经典类时:多继承情况下,会按照深度优先的方式查找 - 当类是新式类时:多继承情况下,会按照广度优先的方式查找
简单点说就是:经典类是纵向查找,新式类是横向查找
from types import MethodType,FunctionType
class func(object):
def foo(self):
print(1)
Fun = func()
print(type(func.foo))
>>> <class ‘function‘>
print(type(Fun.foo))
>>> <class ‘method‘>
print(isinstance(func.foo,FunctionType))
>>> True
print(isinstance(Fun.foo,MethodType))
>>> True
通过类去调用函数foo时,不需要传self参数。此时foo为函数
如果通过对象Fun去调用foo时,对象自动传参self。而foo则是一个方法
单例模式:一个类只能有一个实例化对象
应用场景:Django中的admin组件中admin.site()就是由单例模式创建的,其中封装了所有的表对象
1. 文件导入 :import方法
# 作为python的模块是天然的单例模式
class My_Singleton(object):
def foo(self):
pass
my_singleton = My_Singleton()
# to use
from mysingleton import my_singleton
my_singleton.foo()
2. 使用 __new__ 方法:
--------------------------------(1. # 无法支持多线程 :)------------------------------
class Singleton(object):
def __init__(self,name):
self.name = name
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "instance"):
Singleton.instance = object.__new__(cls)
return Singleton.instance
# to use :
obj = Singleton("alex")
obj1 = Singleton("alex")
obj2 = Singleton("alex")
----------------------------------(2. # 支持多线程:)---------------------------------
import threading
class Singleton(object):
instance_lock = threading.Lock() # 为线程加互斥锁
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "instance"):
with Singleton.instance_lock:
if not hasattr(Singleton, "instance"):
Singleton.instance = object.__new__(cls)
return Singleton.instance
return Singleton.instance
def task():
obj = Singleton()
print(obj)
for i in range(5):
t = threading.Thread(target=task)
t.start()
3. 使用类实现
--------------------------------(1. # 无法支持多线程 :)------------------------------
import threading
class Singleton(object):
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
# to use
obj = Singleton.instance()
obj2 = Singleton.instance()
print(id(obj), id(obj2))
----------------------------------(2. # 支持多线程:)---------------------------------
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
# 第一次调用
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
# 第二次调用
time.sleep(20)
obj = Singleton.instance()
obj2 = Singleton.instance()
print(id(obj, id(obj2)
4. 基于metaclass
--------------------------------------( 方法一 )--------------------------------------
# 创建对象
class SingletonType(type):
def __call__(cls, *args, **kwargs):
obj = super(SingletonType,cls).__call__(*args, **kwargs) #type类帮创建__new__和__init__并返回
return obj
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
# to use
obj = Foo("alex")
print(id(obj1))
--------------------------------------( 方法二 )--------------------------------------
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
# to use
obj1 = Foo(‘name‘)
obj2 = Foo(‘name‘)
print(id(obj1),id(obj2))
__new__
是一个静态方法,而__init__
是一个实例方法.__new__
方法会返回一个创建的实例,而__init__
什么都不返回.__new__
返回一个cls的实例时后面的__init__
才能被调用.__new__
,初始化一个实例时用__init__
.new与init的关系:
1. new优于init加载执行
2. 只能通过重写new方法来自定义不可变的类对象:(int,str,tuple),--->init方法不行
3. 通过new方法可以实现单例模式
lass Singleton(object):
def __new__(cls):
# 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
if not hasattr(cls, ‘instance‘):
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instance
obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = ‘value1‘
print obj1.attr1, obj2.attr1
print obj1 is obj2
copy : 用于深浅拷贝
os :与操作系统交互的一个接口 比如用来处理文件和目录
sys:负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。
json:序列化
re : 正则模块
logging : 日志模块
requests: 爬取数据
timeit :
subprocess:与OS模块相同,区别与异步提交命令不等待输出。与OS模块的区别
>>> a = [1,[1,3],3]
>>> import copy
>>> b = copy.copy(a)
>>> b
[1, [1, 3], 3]
>>> a[1].append(3)
>>> b
[1, [1, 3, 3], 3]
<>>> a
[1, [1, 3, 3], 3]
>>> a = [1,[1,2],3] >>> import copy >>> b = copy.deepcopy(a) >>> a[1].append(3) >>> b [1, [1, 2], 3] >>> a [1, [1, 2, 3], 3]
如何进行实现:
deepcopy优化版:
class FiveCardStudInfo(roomai.abstract.AbstractInfo):
public_state = None
person_state = None
def __deepcopy__(self, memodict={}):
info = FiveCardStudInfo()
info.public_state = self.public_state.__deepcopy__()
info.public_state = self.person_state.__deepcopy__()
return info
由于深拷贝需要维护一个 memo 用于记录已经拷贝的对象,所以这也是它比较慢的原因
os.remove(‘path/filename’) # 删除文件
os.rename(oldname, newname) # 重命名文件
os.walk() # 生成目录树下的所有文件名
os.chdir(‘dirname‘) # 改变目录
os.getcwd() # 取得当前工作目录
os.path.getsize() # 返回文件大小
创建、删除文件
1. # 创建一个文件
2. open("chao.txt","w",encoding="utf-8")
3. import os
#删除文件
4. os.remove("chao.txt")
给出路径找文件
--------------------------------( 方法一 )------------------------------
使用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:\搜索")
. 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线 \s 匹配任意的空白符 \d 匹配数字 \n 匹配一个换行符 \t 匹配一个制表符 \b 匹配一个单词的结尾 ^ 匹配字符串的开始 $ 匹配字符串的结尾 \W 匹配非字母或数字或下划线 \D 匹配非数字 \S 匹配非空白符 a|b 匹配字符a或字符b () 匹配括号内的表达式,也表示一个组 [...] 匹配字符组中的字符 [^...] 匹配除了字符组中字符的所有字符 用法说明 * 重复零次或更多次 + 重复一次或更多次 ? 重复零次或一次 {n} 重复n次 {n,} 重复n次或更多次 {n,m} 重复n到m次
手写正则
匹配邮箱:
- [\w!#$%&‘*+/=?^_`{|}~-]+(?:\.[\w!#$%&‘*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?
- \w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
匹配URL地址:
- [a-zA-z]+://[^\s]*
匹配国内手机号:
- \d{3}\d{8}|\d{4}\{7,8}
匹配身份证号码:
- ^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$
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
贪婪匹配与非贪婪匹配
- 匹配0次或多次 <.*>
- 非贪婪匹配:匹配0次或1次 <.?>
设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。
编码和解码了解过么
什么是装饰器,如果想在函数之后进行装饰应该怎么做
一个函数,想在运行时动态的增加功能,又不会改动函数本身的代码
使用装饰器的单例模式和使用其他方法的单例,在后续使用中有什么区别
引?计数机制的优点: 1、简单 2、实时性:?旦没有引?,内存就直接释放了。不?像其他机制等到特定时机。实时性还带来?个好处:处理回收内存的时间分摊到了平时。 引?计数机制的缺点: 1、维护引?计数 2、消耗资源循环引? list1 = []; list2 = [] list1.append(list2); list2.append(list1) 3、list1与list2相互引?,如果不存在其他对象对他们的引用,list1与list2的引用计数也仍然1,所占?的内存永远无法被回收,这将是致命的。 对于如今的强?硬件,缺点1尚可接受,但是循环引?导致内存泄露,注定python会将引?新的回收机制。(分代收集) 有三种情况会触发垃圾回收: 1、当 gc 模块的计数器达到阀值的时候,自动回收垃圾 2、调? gc.collect(),手动回收垃圾 3、程序退出的时候,python解释器来回收垃圾
多线程可以共享全局变量,多进程不能。多线程中,所有子线程的进程号相同;多进程中,不同的子进程进程号不同。
python的threading和multiprocessing模块
进程通信有哪几种方式
无名管道( pipe ): - 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系
。 高级管道(popen): - 将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
有名管道(named pipe) : - 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
消息队列( message queue ) : - 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区
大小受限等缺点。
信号量( semophore ) :- 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,
其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
信号 ( sinal ) : - 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,
它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信
。 套接字( socket ):- 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
两者的区别是xrange返回的是一个可迭代的对象,range返回的则是一个列表. 同时效率更高,更快。
- 原因是实现的时候使用了yield(此为python2.x回答,python3已删除xrange)
# 需要传过多的参数: class Foo(object): def __init__(self, a1, a2, a3, ... , an): self.a1 = a1 self.a2 = a2 ... def index(self): pass # 给了一些值,对数据进行加工:Django的自定义分页 class Foo(object): def __init__(self, a1, a2, a3, ... , an): self.a1 = a1 self.a2 = a2 ... def index(self): return self.a1 + self.a2
- Django的rest_framework
- 原生CBV
利用Django的CBV来实现RESTful,使开发者代码会多一些。
通过使用rest_framework框架提高开发效率。
Serializers
用户登录认证
分页
频率等
GenericAPIView
- 路由:自动帮助开发者快速为一个视图创建四个URL - 版本 - URL - GET - 请求头 - 认证 - !认证的流程是什么 - 权限 - 权限能不能在中间件做 - 访问频率的控制 - 视图 - 解析器:根据Content-Type请求体中的格式数据进行处理。request,data - 分页 - 序列化 - 序列化 - source - 定义方法 - 请求的数据格式校验 - 渲染器
1分钟:60-80次/每秒钟1-2次
# TCP三次握手
# 1. 客户 --> 服务:SYN=1(发起新连接) seq = J(随机值)
# 2. 服务 --> 客户:
# SYN=1,
# ACK=1(确认接受这次连接强求),
# ack=J+1(从广播的众多连接请求响应中中发现针对自己的响应,网络是广播的)
# seq = K
# 3. 客户 --> 服务
# ACK=1(我知道你接受我了)
# ack=K+1(服务端从众多的连接连理响应中发现针对自己的)
# 当然,第三次握手消息,服务端也可能没有接收到,但不可能两边一直这样ACK下
# 去。但是还可以基于超时时间,重新发起连接请求。
GET: 用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器
POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。
PUT: 传输文件,报文主体中包含文件内容,保存到对应URI位置。
HEAD: 获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效。
DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。
OPTIONS:查询相应URI支持的HTTP方法。
区别一: - get重点在从服务器上获取资源,post重点在向服务器发送数据; 区别二: - get传输数据是通过URL请求,以field(字段)= value的形式,置于URL后,并用"?"连接,多个请求数据间用"&"连接,
如http://127.0.0.1/Test/login.action?name=admin&password=admin,这个过程用户是可见的; - post传输数据通过Http的post机制,将字段与对应值封存在请求实体中发送给服务器,这个过程对用户是不可见的; 区别三: - Get传输的数据量小,因为受URL长度限制,但效率较高; - Post可以传输大量数据,所以上传文件时只能用Post方式; 区别四: - get是不安全的,因为URL是可见的,可能会泄露私密信息,如密码等; - post较get安全性较高; 区别五: - get方式只能支持ASCII字符,向服务器传的中文字符可能会乱码。 - post支持标准字符集,可以正确传递中文字符。
请求报文包含三部分: - 请求行:包含请求方法、URI、HTTP版本信息 - 请求首部字段 - 请求内容实体 响应报文包含三部分: - 状态行:包含HTTP版本、状态码、状态码的原因短语 - 响应首部字段 - 响应内容实体
200:请求被正常处理 204:请求被受理但没有资源可以返回 206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中通过Content-Range指定范围的资源。 301:永久性重定向 302:临时重定向 303:与302状态码有相似功能,只是它希望客户端在请求一个URI的时候,能通过GET方法重定向到另一个URI上 304:发送附带条件的请求时,条件不满足时返回,与重定向无关 307:临时重定向,与302类似,只是强制要求使用POST方法 400:请求报文语法有误,服务器无法识别 401:请求需要认证 403:请求的对应资源禁止被访问 404:服务器无法找到对应资源 500:服务器内部错误 503:服务器正忙
1. 默认持久连接节省通信量,只要客户端服务端任意一端没有明确提出断开TCP连接,就一直保持连接,可以发送多次HTTP请求 2. 管线化,客户端可以同时发出多个HTTP请求,而不用一个个等待响应
3. 断点续传原理
1. 通用首部字段(请求报文与响应报文都会使用的首部字段) - Date:创建报文时间 - Connection:连接的管理 - Cache-Control:缓存的控制 - Transfer-Encoding:报文主体的传输编码方式 2. 请求首部字段(请求报文会使用的首部字段) - Host:请求资源所在服务器 - Accept:可处理的媒体类型 - Accept-Charset:可接收的字符集 - Accept-Encoding:可接受的内容编码 - Accept-Language:可接受的自然语言 3. 响应首部字段(响应报文会使用的首部字段) - Accept-Ranges:可接受的字节范围 - Location:令客户端重新定向到的URI - Server:HTTP服务器的安装信息 4. 实体首部字段(请求报文与响应报文的的实体部分使用的首部字段) - Allow:资源可支持的HTTP方法 - Content-Type:实体主类的类型 - Content-Encoding:实体主体适用的编码方式 - Content-Language:实体主体的自然语言 - Content-Length:实体主体的的字节数 - Content-Range:实体主体的位置范围,一般用于发出部分请求时使用
1. 通信使用明文不加密,内容可能被窃听
2. 不验证通信方身份,可能遭到伪装
3. 无法验证报文完整性,可能被篡改
# HTTPS就是HTTP加上加密处理(一般是SSL安全通信线路)+认证+完整性保护
从浏览器输入域名网址到看到页面都发生了什么
1.浏览器向DNS服务器询问域名对应的IP地址
2.得到域名对应的IP地址后,组装HTTP请求报文
3.由TCP协议将请求报文分割成多个报文段,可靠的传给对方
4.由IP协议搜索对方地址,并传送报文,此过程可能经过多个路由器
5.服务器端的TCP从对方接收到报文
6.服务器端的HTTP解析请求报文,处理并生成响应报文
7.按照相反的顺序,将响应报文发回给浏览器
8.浏览器根据响应报文解析数据(一般为html文档),并渲染页面,文档中也很可能引用了其他资源,这些资源同样使用HTTP协议想服务器请求
websocket是一种类似HTTP的协议: - 让C/S创建链接不断开,以此可以完成:S向C主动推送消息 - websocket协议额外做的一些前提操作: - 握手,连接前进行校验 - 发送数据,进行加密 websocket的本质 ... 应用场景: 5月17日13:19:13,141 - Django: channel - Flask : gevent-websocket - tornado:内置
QAQ
InnoDB:
- 支持事务
- 行锁/表锁
- 表锁:
- select * from tb for update
- 行锁:
- select * from tb where id=2 for update;
MyISAM:
- 全文索引<
- 表锁
- 查询速度快
- 表锁语句:
- select * from tb for update;
- Innodb是索引和数据是紧密捆绑的,没有使用压缩;
- 而MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少,能加载更多索引,因此,用MyISAM可节省不少硬盘空间。
聚合函数:max/sum/min/avg
时间格式化:date_format
字符串拼接:concat
单列:B+树/哈希索引 --> 查询速度快更新速度慢
- 普通索引 :加速查找
- 唯一索引 :加速查询 + 约束(不能重复)
- 主键索引 :加速查询 + 约束(不能重复) + 不能为空
- 全文索引 :
多列:遵循最左前缀规则
- 联合索引 :
- 联合唯一索引 :
其他:
- 索引合并 :利用多个单例索引查询
- 覆盖索引 :在索引表中就能将想要的数据查询到
- 组合索引遵循最左前缀规则
如果组合索引为:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引
slow_query_log = OFF # 是否开启慢日志记录
long_query_time = 2 # 时间限制,超过此时间,则记录
slow_query_log_file = /usr/slow.log # 日志文件
log_queries_not_using_indexes = OFF # 为使用索引的搜索是否记录
mysql锁能在并发情况下的mysql进行更好的优化
MySQL有三种锁的级别:页级、表级、行级,这3种锁的特性可大致归纳如下:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
1. select 1与select * 的区别:
“selelct 常量 from 表名” 对应所有行,返回的永远只有一个值,即常量 ,所以一般只用来判断是否有表记录;
而“select * from 表名” 是返回所有行的所有列。
性能上的差异,关键看from和where子句。如果where条件中可以通过索引,那显然 “selelct 常量 from 表名” 的性能比“select * from 表名” 好。
2. select count(1) 与select count(*) 的区别 :
性能上的差异,跟表结构有关系:
如果表中没有主键,那么count(1)比count(*)快
如果有主键,那么count(主键,联合主键)比count(*)快
如果表中只有一个字段,count(*)最快
3. select sum(1)的使用:
select count(*)返回所有满足条件的记录数,此时等同于select sum(1)
但是sum()可以传任意数字,负数、浮点数都可以,返回的值是传入值n*满足条件记录数m
函数: - 参数 - 返回值:return 存储过程: - 参数 - 返回值:out/inout - 返回结果集:select * from tb;
虚拟表 --> 通过SQL帮助我们实时查询数据
在对表进行 增删改查 前后定义一些SQL操作
- 数据库分页
存在问题:
查询的页面数越大,速度就会越慢,这是因为每次数据库都会从第一条开始扫描
selsct * from tb limit 3 offset 5
models.User.object.all()[0:10]
解决方法:
根据业务场景来说:
1.如果业务对历史数据不要求的话,就显示一定的页数,就可以避免这样的问题
2.记录当前页数据id的最大最小值,根据记录的id和需要查询的范围来定。
但是在url上面会有page的值,如果用户随意改url上的页码的值的时候,可以参考restfromwork的分页来做,
对当前的url进行加密,加密之后它里面就带了当前页的最大和最小id,解密出来之后就可以直接拿来用,而且用户也没有办法在url上随便修改了
select * from tb name=‘alex‘ limit 1
1. 不用 select * 2. 固定长度字段列,往前放 3. char 和 varchar 4. 固定数据放入内存 choice 5. 数据库读写分离 6. 分库:当数据库中表过多,将表分到不同的数据库() 7. 分表: - 水平分表:将某些列拆分到另一张表:博客+博客详细 - 垂直分表:将一些历史信息分到另一张表中:历史账单 8. 缓存:利用redis、memcache进行存储 ps:当缓存宕机,如果没有进行持久化则将所有请求转接MySQL,
而MySQL承受不了压力时会造成无法启动 9. 其它 - 慢日志 - 执行计划 10. 分页
# 中间人攻击(Man-in-the-middle attack,通常缩写为MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据, 使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。
- jQuery - BootStrap - Vue.js、React、Angular.js
通过浏览器和设备分辨率的改变做出相应的变化
本质是通过 @media属性来完成:
<style>
body{
margin:0;}
.pg-header{
background-color:red;
height: 48px;}
@media( min-width: 768px ){
.pg-header{background-color: green;}}
@media( min-width: 992px ){
.pg-header{background-color: pink;}}
</style>
Django: - 内置很多组件: - ORM、admin、Form、ModelForm、中间件、信号、缓存、csrf等 Flask: - 一个轻量级框架内置组件少,可扩展很多第三方组件: - flask-session、flask-script、flask-redis、flask-flask-migrate - flask-SQLAlchemy、wtforms、blinker 两个框架都是基于wsgi协议实现的,默认使用的wsgi模块不一样, 还有一个显著的特点:处理请求的方式不一样 - Django:通过将请求封装成request对象,再通过参数进行传递 - flask: 通过上下文管理实现 延伸: - Django组件 - flask组件、用途 - wsgi - 上下文管理
1. wsgi:创建socket服务端,用于接收用户请求并对请求进行初次封装
2. 中间件:对所有请求到来之前,响应之前定制一些操作
3. 路由: 匹配路由,在url和视图函数对应关系中,根据当前请求url找到相应的函数
4. 视图函数:执行视图函数,业务处理【通过ORM去数据库中获取数据,再去拿到模板,然后将数据和模板进行渲染】
5. 在经过中间件
6. 通过wsgi将响应返回给用户
是web服务网关接口,是一套协议。以下模块实现了wsgi协议: - wsgiref :性能低,易配置 - werkzurg - uwsgi 以上模块本质:实现socket监听请求,获取请求后将数据封装,然后交给web框架处理
详解:
本质是编写了socket服务端,用来监听用户的请求,如果有请求到来,则将请求进行一次封装然后将【请求】交给web框架来进行下一步处理
所有请求都要穿过中间件: - 对所有的请求进行批量处理 - 在视图函数执行之前后进行一些自定义操作。
- 解决cors跨域请求
- csrf
- csrf的本质:
- 用户先发送get获取csrf token:Form表单中一个隐藏的标签 + cookie
- 发起post请求时,需要携带之前发送给用户的csrf token;
- 在中间件的process_view 方法中进行校验
- process_request(self,request)
- process_view(self, request, callback, callback_args, callback_kwargs)
- process_template_response(self,request,response) # 当视图函数的返回值对象中有render方法时,该方法才会被调用
- process_exception(self, request, exception)
- process_response(self, request, response)
中间件的执行流程:
1 请求先执行所有中间件的process_request,然后做路由匹配,找到函数不执行。
2 再执行所有的process_view,在执行视图函数。
3 再执行process_response
4 如果程序报错执行process_exception
5 如果程序有render方法则执行process_template_response
# 为什么要在中间件用这些:
- 一些内置组件上的应用:
- csrf
- session
缓存
- 用户登录校验 # 如果不使用就需要为每个函数添加装饰器,太过繁琐。
- 权限处理 # 用户登录后将权限放到session中,然后再每次请求时都需要判断当前用户是否有权访问当前url,这些检查的东西可以放到中间件中统一处理。
- session
- 跨域:
- 前后端分离时,本地测试开发时使用的
目标:防止用户直接向服务端发起POST请求。
方案:先发送GET请求时,将token保存到:cookie、Form表单中(隐藏的input标签),以后再发送请求时只要携带过来即可。
问题:如果想后台发送POST请求?
form表单提交:
<form method="POST">
{% csrf_token %}
<input type=‘text‘ name=‘user‘ />
<input type=‘submit‘ />
</form>
ajax提交:
$.ajax({
url:‘/index‘,
type:‘POST‘,
data:{csrfmiddlewaretoken:‘{{ csrf_token }}‘,name:‘alex‘}
})
前提:引入jquery + 引入jquery.cookie
$.ajax({
url: ‘xx‘,
type:‘POST‘,
data:{name:‘oldboyedu‘},
headers:{
X-CSRFToken: $.cookie(‘csrftoken‘)
},
dataType:‘json‘, // arg = JSON.parse(‘{"k1":123}‘)
success:function(arg){
console.log(arg)
}
})
<body> <input type="button" onclick="Do1();" value="Do it"/> <input type="button" onclick="Do2();" value="Do it"/> <input type="button" onclick="Do3();" value="Do it"/> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery.cookie.js"></script> <script> $.ajaxSetup({ // 为所有Ajax请求添加函数 beforeSend: function(xhr, settings) { xhr.setRequestHeader("X-CSRFToken", $.cookie(‘csrftoken‘)); } }); function Do1(){ $.ajax({ url:"/index/", data:{id:1}, type:‘POST‘, success:function(data){ console.log(data); } }); } function Do2(){ $.ajax({ url:"/index/", data:{id:1}, type:‘POST‘, success:function(data){ console.log(data); } }); } function Do3(){ $.ajax({ url:"/index/", data:{id:1}, type:‘POST‘, success:function(data){ console.log(data); } }); } </script> </body>
1. 帮助我们生成HTML标签 2. 对用户输入的数据进行校验 ps:form对象是个可迭代对象 Q:从数据库获取数据时,下拉框无法实时刷新。 A:重写构造方法,在构造方法中重新去获取数据 def __str__(self): return self.title
- 对于Django来说:内部组件全面,自身功能强大,给人一种大而全的感觉,
( 你知 或者不知他,Django就在那里,不悲不喜。
你念 或者不念他,功能就在那里,不來不去。
你愛 或者不愛他,組件就在那里,不增不減。
你用,或者不用他,Django就在你手裡。不捨不棄。)
而Flask:内置组件就很少,但它的第三方组件很多,可扩展性强,还可以自定义组件,
- 两个框架本身都没有写sockte,都是基于wsgi协议做的,而flask框架中的上下文管理较为耀眼。
- 相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的
请求相关数据传递的方式不同:django:通过传递request参数取值
flask:见问题二
组件不同:django组件多
flask组件少,第三方组件丰富
相同:
都基于wsgi,
不同:
对请求处理不同:Flask基于上下文管理;Django通过传值来处理
Django功能多,内置组件全面:缺点不能自定义添加或删除组件
Flask内置组件少,但是可以通过第三方组件来扩展:Flask-email,Flask-SQLAlchemy,Flask-session等
当请求进来时,会将 requset 和 session 封装为一个 RequestContext 对象,通过 LocalStack 将 RequestContext 放入到Local对象中,
因为请求第一次来 session 是空值,所以执行 open_session,给 session(uuid4())赋值,再通过视图函数处理,请求响应时执行save.session,
将签名 session 写入 cookie 中,再将 Local 中的数值pop掉。
因为 request 和 session 都是在视图中操作频繁的数据,也是用户请求需要用的数据,
将 request 和 session 封装在 RequestContext 中 top,pop 一次就可以完成,而单独不封装在一起就会多次操作,
两个LocalStack,两个Local:
- request、session 共同用一个 LocalStack 和 Local
- g、app 共同用一个 Localstack 和 Local
- 前提:记得不太清楚了,/or 最近刚看过
简单来说,falsk上下文管理可以分为三个阶段:
1、请求进来时,将请求相关的数据放入上下文管理中
2、在视图函数中,要去上下文管理中取值
3、请求响应,要将上下文管理中的数据清除
详细点来说:
1、请求刚进来,将request,session封装在RequestContext类中,app,g封装在AppContext类中,并通过LocalStack将requestcontext和appcontext放入Local类中
2、视图函数中,通过localproxy--->偏函数--->localstack--->local取值
3、请求相应时,先执行save.session()再各自执行pop(),将local中的数据清除
- 用于保存:
- 请求上下文对象
- App上下文对象
- 并且可以做到"线程"间的数据隔离。
线程:threading.local
协程:greenlet.get_current as get_get_ident
- localstack 的源码与 threading.local(线程处理)的作用相似,
不同之处是 Local 是通过 greenlet(协程)获取唯一标识,粒度更细
将local对象中的数据维护成一个栈【ctx,ctx】(先进后出) { “协程或线程的唯一标识”: { stack:[ctx,ctx,ctx,] } }
当是web应用时:不管是单线程还是多线程,栈中只有一个数据 - 服务端单线程: { 111:{stack: [ctx, ]} } - 服务端多线程: { 111:{stack: [ctx, ]} 112:{stack: [ctx, ]} } 离线脚本:可以在栈中放入多个数据,在任何情况下都可以获取到当前app的请求和响应 with app01.app_context(): print(current_app) with app02.app_context(): print(current_app) print(current_app)
G 相当于一次请求的全局变量,当请求进来时将 G 和 current_app 封装为一个 APPContext 类,在通过 LocalStack 将 Appcontext 放入 Local 中,
取值时通过偏函数,LocalStack、loca 中取值,响应时将 Local 中的 g 数据删除:
通过 、偏函数(lookup_req_object)、Localstack、Local 取值
- 内置组件
- 配置 - 路由 - 视图
- 模板 - session - 蓝图
- 闪现 - 装饰器 - 中间件
- 第三方组件
- Flask-session # 将原来保存在cookie中的session数据,放到Redis/memcache/文件/数据库中
- 公共:
- DButils # 数据库连接池: 两种模式; 为每个参数设置一个连接/共享一个连接;全局参数
- wtforms # form组件:做表单验证+生成HTML标签
分组函数 : group by 字段 having 判断条件 (固定语法)分组和聚合函数搭配
分组函数 : group by 字段 having 判断条件 (固定语法)分组和聚合函数搭配
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())
标签:面向对象 通过 延迟 如何使用 setup c++ 字节 拼接 内存泄露
原文地址:https://www.cnblogs.com/clement-jiao/p/8719323.html