python的特性注定了代码无法保密_python 基础

谈谈你对python和其他语言的区别

python 中,变量是以内容为基准而不是像 c 中以变量名为基准;

python 中,一个变量可以以多个名称访问;

python 中,数字类型的值是不可变的;

python 中,编译器会有一个小整数池的概念

为什么要学python

编译型语言:一次性,将全部的程序编译成二进制文件,然后在运行。(c,c++ ,go)

优点:运行速度快。

缺点:开发效率低,不能跨平台。

解释型语言:当你的程序运行时,一行一行的解释,并运行。(python , PHP)

优点:调试代码很方便,开发效率高,并且可以跨平台。

缺点:运行速度慢。

我对程序的定义是人可以读懂,而机器刚好可以执行的一段代码,注重于代码的可读性。

而Python的定位是“优雅”、“明确”、“简单”,用它编写的程序简单易懂,这与我当初的想法不谋而合

QAQ

数据结构( 2 )

基本的数据类型和方法都有哪些

列表: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,

函数( 7 )

函数参数传递的是什么? 引用、内存地址

默认参数尽量避免使用可变数据类型

默认参数只会被执行一次:第一次调用函数时,默认参数被初始化为【】,以后每次调用时都会使用已经初始化的【】。

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变量。

简单的说,这种内部函数可以使用外部函数变量的行为,就叫闭包。

闭包的意义与应用: 延迟计算;

闭包的意义: 返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域

#应用领域:延迟计算(原来我们是传参,现在我们是包起来)

装饰器就是闭包函数的一种应用场景

必会内置函数 - map

介绍:

会根据提供的函数对指定序列做映射。

第一个参数 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]

必会内置函数 - filter

介绍:

函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新列表。

该接收两个参数,第一个为函数,第二个为序列,序列的每个元素作为参数传递给函数进行判,然后返回 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)

>>>必会内置函数 - zip

介绍:

函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。

如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。

语法:

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)]

必会内置函数 - isinstance

介绍:

函数来判断一个对象是否是一个已知的类型,类似 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

isinstance() 与 type()的区别

介绍

type() 不会认为子类是一种父类类型,不考虑继承关系。

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

函数的骚操作( 7 )

手写:三元运算符

val = “aaa” if 1==1 else “bbb”

val

‘aaa‘

手写:lambda表达式

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: # 根据条件过滤哪些值可以。

手写:列表推导式 + lambda表达式 :# 一行代码写出30以内所有能被3整除的数的平方:

错误示例:不能使用列表生成式

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

iter‘ of generator object at 0x000002C977AF5938>

a.iter()

at 0x000002C977AF5938>

a.iter().next

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‘}

手写:字典推导式:合并大小写对应的value值,将k统一成小写

.

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和生成器的优劣

列表推导式是将所有的值一次性加载到内存中

生成器是将列表推导式的[]改成(),不会将所有的值一次性加载到内存中,延迟计算,一次返回一个结果,

它不会一次生成所有的结果,这对大数据量处理,非常有用

生成器函数: 一个函数中包含了yield关键词,那么这个函数就不是普通的函数,是一个生成器函数

调用生成器函数,不会立马执行该函数里面的代码, 而是会返回一个 生成器对象

python三神器( 5 )

生成器、迭代器、装饰器、可迭代对象的区别

容器:

是一系列元素的集合,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中一切皆对象

封装:对数据的,对对象的封装。

继承:在类的基础上进行二次开发,通过函数super() 或者"基类名.方法名() "的方式实现这一目的的。

多态:同一个方法处于不同对象中,可以产生不同的结果

多态示例

鸭子模型

class A:

def send(self):

pass

class B:

def send(self):

pass

def func(arg):

arg.send()

obj = B()

func(obj)

你知道哪些双下划线方法

双下划线:

getattr:反射

应用场景:

CBV

Django 配置文件

wtforms中的Form()实例化中 将"_fields中的数据封装到Form类中"

mro:定义解析类继承的顺序

应用场景:wtforms中 FormMeta中继承的优先级

dict:用来存储对象属性的一个字典,其键为属性名,值为属性的值

dict 与 dir()的区别:

dir()是一个函数,返回值是list

dir用来寻找一个对象的所有属性值,包括__dict__中的属性,__dict__是dir()的子集

new :

当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。

实现自定义 metaclass

应用场景:

wtforms 字段实例化时返回:不是StringField,而是UNboundField

rest_framework:many=Ture 中的序列化

单例模式

call:作用是使实例能够像函数一样被调用,同时不影响实例本身的生命周期, (call()不影响一个实例的构造和析构)

但是__call__()可以用来改变实例的内部成员。

call 与 __init__的区别

应用场景:

FLask 请求的入口app.run()

字段生成标签时:字段.str ==> 字段.call ==> 插件.call

iter:

迭代器为什么要一定实现__iter__方法(为什么要返回自身)

应用场景:wtforms中BaseForm中循环所有字段时自定义了__iter__方法

metaclass的作用

作用:用于指定当前类事业那个类来创建

场景:在类创建之前定制的操作

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

super的作用:

子类继承父类的方法,其继承顺序按照 __mro__来定义

新式类与经典类的区别

新式类跟经典类的差别主要是以下几点:

新式类对象可以直接通过__class__属性获取自身类型:type

继承搜索的顺序发生了改变,经典类多继承属性搜索顺序 :

先深入继承树左侧,再返回,开始找右侧;

新式类多继承属性搜索顺序: 先水平搜索,然后再向上移动。

ps:(经典类深度优先,新式类广度优先)

新式类增加了__slots__内置属性, 可以把实例属性的种类锁定到__slots__规定的范围之中。

新式类增加了__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))

print(type(Fun.foo))

print(isinstance(func.foo,FunctionType))

True

print(isinstance(Fun.foo,MethodType))

True

通过类去调用函数foo时,不需要传self参数。此时foo为函数

如果通过对象Fun去调用foo时,对象自动传参self。而foo则是一个方法

手写三个使用不同方法实现的单例模式

单例模式:一个类只能有一个实例化对象

应用场景:Django中的admin组件中admin.site()就是由单例模式创建的,其中封装了所有的表对象

文件导入 :import方法

作为python的模块是天然的单例模式

class My_Singleton(object):

def foo(self):

pass

my_singleton = My_Singleton()

to use

from mysingleton import my_singleton

my_singleton.foo()

使用 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()

使用类实现

--------------------------------(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)

基于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__方法会返回一个创建的实例,而__init__什么都不返回.

只有在__new__返回一个cls的实例时后面的__init__才能被调用.

当创建一个新实例时调用__new,初始化一个实例时用__init.

继承自object的新式类才有__new__

__new__至少要有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别

__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,

可以return父类(通过super(当前类名, cls))__new__出来的实例,或者直接是object的__new__出来的实例

__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值

如果__new__创建的是当前类的实例,会自动调用__init__函数,通过return语句里面调用的__new__函数的第一个参数是cls来保证是当前类实例,

如果是其他类的类名,;那么实际创建返回的就是其他类的实例,其实就不会调用当前类的__init__函数,也不会调用其他类的__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

知道有哪些类的双下划线方法,并说明作用,返回值?

https://www.zybuluo.com/kingwhite/note/136247

123

模块 ( 26 )

你的常用模块都有哪些

copy : 用于深浅拷贝

os :与操作系统交互的一个接口 比如用来处理文件和目录

sys:负责程序与python解释器的交互,提供了一系列的函数和变量,用于操控python的运行时环境。

json:序列化

re : 正则模块

logging : 日志模块

requests: 爬取数据

timeit :

subprocess:与OS模块相同,区别与异步提交命令不等待输出。与OS模块的区别

copy模块

浅拷贝与深拷贝的实现方式及区别,如果你来设计Deepcopy,如何实现

浅拷贝:只拷贝父对象,不会拷贝对象的内部的子对象(父对象不同,子对象进行引用,ID相同)

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模块

你知道哪些OS模块的方法

os.remove(‘path/filename’) # 删除文件

os.rename(oldname, newname) # 重命名文件

os.walk() # 生成目录树下的所有文件名

os.chdir(‘dirname‘) # 改变目录

os.getcwd() # 取得当前工作目录

os.path.getsize() # 返回文件大小

创建、删除文件

创建一个文件

open(“chao.txt”,“w”,encoding=“utf-8”)

import os

#删除文件

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:\搜索”)

11111

re模块

re模块的基本方法:

技术分享图片

. 匹配除换行符以外的任意字符

\w 匹配字母或数字或下划线

\s 匹配任意的空白符

\d 匹配数字

\n 匹配一个换行符

\t 匹配一个制表符

\b 匹配一个单词的结尾

^ 匹配字符串的开始

$ 匹配字符串的结尾

\W

匹配非字母或数字或下划线

\D

匹配非数字

\S

匹配非空白符

a|b

匹配字符a或字符b

()

匹配括号内的表达式,也表示一个组

[…]

匹配字符组中的字符

[^…]

匹配除了字符组中字符的所有字符

用法说明

重复零次或更多次

重复一次或更多次

? 重复零次或一次

{n} 重复n次

{n,} 重复n次或更多次

{n,m} 重复n到m次

View Code

手写正则

匹配邮箱:

- [\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解释器来回收垃圾

多进程与多线程的区别:CPU密集型应用适合用什么

多线程可以共享全局变量,多进程不能。多线程中,所有子线程的进程号相同;多进程中,不同的子进程进程号不同。

python的threading和multiprocessing模块

进程通信有哪几种方式

无名管道( pipe ): - 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系

高级管道(popen): - 将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。

有名管道(named pipe) : - 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

消息队列( message queue ) : - 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区

大小受限等缺点。

信号量( semophore ) :- 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,

其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

信号 ( sinal ) : - 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,

它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信

套接字( socket ):- 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。

介绍下协程,为何比线程还快

关于GIL锁的解释,协程的优缺点

range和xrange的区别

两者的区别是xrange返回的是一个可迭代的对象,range返回的则是一个列表. 同时效率更高,更快。

原因是实现的时候使用了yield(此为python2.x回答,python3已删除xrange)

写出将IP地址127.0.0.1转换为32位二进制和数的函数

单向链表和双向链表

写出将IPv4地址转换为IPv6的函数

面向对象的应用场景

需要传过多的参数:

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

QAQ

RESTful:

谈谈你对rest api的认识

用过哪些rest 框架

Django的rest_framework

原生CBV

不使用rest_framework

利用Django的CBV来实现RESTful,使开发者代码会多一些。

通过使用rest_framework框架提高开发效率。

这个框架使用最多的是什么?

Serializers

用户登录认证

分页

频率等

rest_framework视图中你都用过哪些基类

GenericAPIView

!rest_framework的GenericAPIView都继承过哪些类

rest_framework框架有哪些优点?

rest_framework都有哪些组件?

路由:自动帮助开发者快速为一个视图创建四个URL

版本

URL

GET

请求头

认证

!认证的流程是什么

权限

权限能不能在中间件做

访问频率的控制

视图

解析器:根据Content-Type请求体中的格式数据进行处理。request,data

分页

序列化

序列化

source

定义方法

请求的数据格式校验

渲染器

频率组件是怎么做的

限制的频率是多少?

1分钟:60-80次/每秒钟1-2次

1

2

算法排序部分(9)

手写快排;堆排;几种常用排序的算法复杂度是多少;快排平均复杂度多少,最坏情况如何优化;

手写:已知一个长度n的无序列表,元素均是数字,要求把所有间隔为d的组合找出来,你写的解法算法复杂度多少;

手写:一个列表A=[A1,A2,…,An],要求把列表中所有的组合情况打印出来;

手写:用一行python写出1+2+3+…+10**8 ;

手写python:用递归的方式判断字符串是否为回文;

单向链表长度未知,如何判断其中是否有环;

单向链表如何使用快速排序算法进行排序;

手写:一个长度n的无序数字元素列表,如何求中位数,如何尽快的估算中位数,你的算法复杂度是多少;

如何遍历一个内部未知的文件夹(两种树的优先遍历方式)

网络基础部分(11)

TCP/IP分别在模型的哪一层;

socket长连接是什么意思;

select和epoll你了解么,区别在哪;

TCP UDP区别;三次握手四次挥手讲一下;

TCP三次握手

1. 客户 --> 服务:SYN=1(发起新连接) seq = J(随机值)

2. 服务 --> 客户:

SYN=1,

ACK=1(确认接受这次连接强求),

ack=J+1(从广播的众多连接请求响应中中发现针对自己的响应,网络是广播的)

seq = K

3. 客户 --> 服务

ACK=1(我知道你接受我了)

ack=K+1(服务端从众多的连接连理响应中发现针对自己的)

当然,第三次握手消息,服务端也可能没有接收到,但不可能两边一直这样ACK下

去。但是还可以基于超时时间,重新发起连接请求。

TIME_WAIT过多是因为什么;

http一次连接的全过程:你来说下从用户发起request——到用户接收到response时的全过程;

http连接方式。get和post的区别,你还了解其他的方式么;

restful你知道么;

状态码你知道多少,比如200/403/404/504等等;# 更多信息跳转w3

TCP/UDP

socket连接和HTTP连接的区别

Q^Q

HTTP部分( 10 )

常用的HTTP方法有哪些?

GET: 用于请求访问已经被URI(统一资源标识符)识别的资源,可以通过URL传参给服务器

POST:用于传输信息给服务器,主要功能与GET方法类似,但一般推荐使用POST方式。

PUT: 传输文件,报文主体中包含文件内容,保存到对应URI位置。

HEAD: 获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证URI是否有效。

DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件。

OPTIONS:查询相应URI支持的HTTP方法。

GET方法与POST方法的区别

区别一:

- 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支持标准字符集,可以正确传递中文字符。

HTTP请求报文与响应报文格式

请求报文包含三部分:

- 请求行:包含请求方法、URI、HTTP版本信息

- 请求首部字段

- 请求内容实体

响应报文包含三部分:

- 状态行:包含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:服务器正忙

HTTP1.1版本新特性

默认持久连接节省通信量,只要客户端服务端任意一端没有明确提出断开TCP连接,就一直保持连接,可以发送多次HTTP请求

管线化,客户端可以同时发出多个HTTP请求,而不用一个个等待响应

断点续传原理

常见HTTP首部字段

通用首部字段(请求报文与响应报文都会使用的首部字段)

Date:创建报文时间

Connection:连接的管理

Cache-Control:缓存的控制

Transfer-Encoding:报文主体的传输编码方式

请求首部字段(请求报文会使用的首部字段)

Host:请求资源所在服务器

Accept:可处理的媒体类型

Accept-Charset:可接收的字符集

Accept-Encoding:可接受的内容编码

Accept-Language:可接受的自然语言

响应首部字段(响应报文会使用的首部字段)

Accept-Ranges:可接受的字节范围

Location:令客户端重新定向到的URI

Server:HTTP服务器的安装信息

实体首部字段(请求报文与响应报文的的实体部分使用的首部字段)

Allow:资源可支持的HTTP方法

Content-Type:实体主类的类型

Content-Encoding:实体主体适用的编码方式

Content-Language:实体主体的自然语言

Content-Length:实体主体的的字节数

Content-Range:实体主体的位置范围,一般用于发出部分请求时使用

HTTP的缺点与HTTPS

通信使用明文不加密,内容可能被窃听

不验证通信方身份,可能遭到伪装

无法验证报文完整性,可能被篡改

HTTPS就是HTTP加上加密处理(一般是SSL安全通信线路)+认证+完整性保护

HTTP优化

利用负载均衡优化和加速HTTP应用

利用HTTP Cache来优化网站

从浏览器输入域名网址到看到页面都发生了什么

1.浏览器向DNS服务器询问域名对应的IP地址

2.得到域名对应的IP地址后,组装HTTP请求报文

3.由TCP协议将请求报文分割成多个报文段,可靠的传给对方

4.由IP协议搜索对方地址,并传送报文,此过程可能经过多个路由器

5.服务器端的TCP从对方接收到报文

6.服务器端的HTTP解析请求报文,处理并生成响应报文

7.按照相反的顺序,将响应报文发回给浏览器

8.浏览器根据响应报文解析数据(一般为html文档),并渲染页面,文档中也很可能引用了其他资源,这些资源同样使用HTTP协议想服务器请求

什么是websocket

websocket是一种类似HTTP的协议:

让C/S创建链接不断开,以此可以完成:S向C主动推送消息

websocket协议额外做的一些前提操作:

握手,连接前进行校验

发送数据,进行加密

websocket的本质

应用场景:

5月17日13:19:13,141

Django: channel

Flask : gevent-websocket

tornado:内置

QAQ

q^q

数据库部分( 20 )

MySQL有几种引擎:查询表数据练习题

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进行更好的优化

MySQL有三种锁的级别:页级、表级、行级,这3种锁的特性可大致归纳如下:

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

为何,以及如何分区、分表;

从字面上简单理解,就是把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上。

MySQL的char varchar text的区别;

select的几种区别

select 1与select * 的区别:

“selelct 常量 from 表名” 对应所有行,返回的永远只有一个值,即常量 ,所以一般只用来判断是否有表记录;

而“select * from 表名” 是返回所有行的所有列。

性能上的差异,关键看from和where子句。如果where条件中可以通过索引,那显然 “selelct 常量 from 表名” 的性能比“select * from 表名” 好。

select count(1) 与select count() 的区别 :

性能上的差异,跟表结构有关系:

如果表中没有主键,那么count(1)比count()快

如果有主键,那么count(主键,联合主键)比count()快

如果表中只有一个字段,count()最快

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上随便修改了

了解join么,有几种,有何区别,A LEFT JOIN B,查询的结果中,B没有的那部分是如何显示的(NULL);

写出SQL语句:获取一条name="alex"的数据

select * from tb name=‘alex‘ limit 1

BTree索引和hash索引的区别(在磁盘结构上的区别);

手写:如何对查询命令进行优化;

不用 select *

固定长度字段列,往前放

char 和 varchar

固定数据放入内存 choice

数据库读写分离

分库:当数据库中表过多,将表分到不同的数据库()

分表:

水平分表:将某些列拆分到另一张表:博客+博客详细

垂直分表:将一些历史信息分到另一张表中:历史账单

缓存:利用redis、memcache进行存储

ps:当缓存宕机,如果没有进行持久化则将所有请求转接MySQL,

而MySQL承受不了压力时会造成无法启动

其它

慢日志

执行计划

分页

NoSQL了解么,和关系数据库的区别;

redis有几种常用存储类型;

乐观锁和悲观锁

触发器是什么?

QAQ

Linux部分( 4 )

讲一下你常用的Linux/git命令和作用;

查看当前进程是用什么命令,除了文件相关的操作外,你平时还有什么操作命令;

Apache和Nginx的区别

介绍下中间人攻击:

中间人攻击(Man-in-the-middle attack,通常缩写为MITM)是指攻击者与通讯的两端分别创建独立的联系,并交换其所收到的数据,

使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。

1

前端部分( 2 )

你用过什么框架和类库

jQuery

BootStrap

Vue.js、React、Angular.js

什么是响应式布局

通过浏览器和设备分辨率的改变做出相应的变化

本质是通过 @media属性来完成:

django项目部分( 19 )

简单的介绍下你在公司的项目,不管是不是后端相关的,主要是要体现出你干了什么;

你在项目中遇到最难的部分是什么,你是怎么解决的;

Django和Flask框架的区别

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

上下文管理

MVC / MTV;

Django请求生命周期

wsgi:创建socket服务端,用于接收用户请求并对请求进行初次封装

中间件:对所有请求到来之前,响应之前定制一些操作

路由: 匹配路由,在url和视图函数对应关系中,根据当前请求url找到相应的函数

视图函数:执行视图函数,业务处理【通过ORM去数据库中获取数据,再去拿到模板,然后将数据和模板进行渲染】

在经过中间件

通过wsgi将响应返回给用户

什么是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

跨域:

前后端分离时,本地测试开发时使用的

CSRF原理

目标:防止用户直接向服务端发起POST请求。

方案:先发送GET请求时,将token保存到:cookie、Form表单中(隐藏的input标签),以后再发送请求时只要携带过来即可。

问题:如果想后台发送POST请求?

form表单提交: {% csrf_token %}

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)

}

})

技术分享图片

优化方案 Django的Form的作用 1. 帮助我们生成HTML标签 2. 对用户输入的数据进行校验 ps:form对象是个可迭代对象 Q:从数据库获取数据时,下拉框无法实时刷新。 A:重写构造方法,在构造方法中重新去获取数据 def __str__(self): return self.title 缓存怎么用; CSRF是什么,django是如何避免的;XSS呢; 如果你来设计login,简单的说一下思路; session和cookie的联系与区别;session为什么说是安全的; WSGI和Nginx的作用; 浏览器缓存机制 你看过django的admin源码么;看过flask的源码么;你如何理解开源; QAQ

Flask部分( 13 )

FLask和Django的区别

对于Django来说:内部组件全面,自身功能强大,给人一种大而全的感觉,

( 你知 或者不知他,Django就在那里,不悲不喜。

你念 或者不念他,功能就在那里,不來不去。

你愛 或者不愛他,組件就在那里,不增不減。

你用,或者不用他,Django就在你手裡。不捨不棄。)

而Flask:内置组件就很少,但它的第三方组件很多,可扩展性强,还可以自定义组件,

两个框架本身都没有写sockte,都是基于wsgi协议做的,而flask框架中的上下文管理较为耀眼。

- 相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的

请求相关数据传递的方式不同:django:通过传递request参数取值

flask:见问题二

组件不同:django组件多

flask组件少,第三方组件丰富

谈谈你对Flask与Django框架的认识

相同:

都基于wsgi,

不同:

对请求处理不同:Flask基于上下文管理;Django通过传值来处理

Django功能多,内置组件全面:缺点不能自定义添加或删除组件

Flask内置组件少,但是可以通过第三方组件来扩展:Flask-email,Flask-SQLAlchemy,Flask-session等

Flask中的session是什么时候创建,什么时候销毁的?

当请求进来时,会将 requset 和 session 封装为一个 RequestContext 对象,通过 LocalStack 将 RequestContext 放入到Local对象中,

因为请求第一次来 session 是空值,所以执行 open_session,给 session(uuid4())赋值,再通过视图函数处理,请求响应时执行save.session,

将签名 session 写入 cookie 中,再将 Local 中的数值pop掉。

Flask为什么把请求放到RequestContext中?

因为 request 和 session 都是在视图中操作频繁的数据,也是用户请求需要用的数据,

将 request 和 session 封装在 RequestContext 中 top,pop 一次就可以完成,而单独不封装在一起就会多次操作,

flask中一共有几个LocalStack和Local对象

两个LocalStack,两个Local:

request、session 共同用一个 LocalStack 和 Local

g、app 共同用一个 Localstack 和 Local

Flask上下文管理是如何实现的:

前提:记得不太清楚了,/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中的数据清除

Local的作用?

用于保存:

请求上下文对象

App上下文对象

并且可以做到"线程"间的数据隔离。

线程:threading.local

协程:greenlet.get_current as get_get_ident

localstack 的源码与 threading.local(线程处理)的作用相似,

不同之处是 Local 是通过 greenlet(协程)获取唯一标识,粒度更细

LocalStack的作用?

将local对象中的数据维护成一个栈【ctx,ctx】(先进后出)

{

“协程或线程的唯一标识”: { stack:[ctx,ctx,ctx,] }

}

为什么要将Local对象中的数据维护成一个栈

当是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 相当于一次请求的全局变量,当请求进来时将 G 和 current_app 封装为一个 APPContext 类,在通过 LocalStack 将 Appcontext 放入 Local 中,

取值时通过偏函数,LocalStack、loca 中取值,响应时将 Local 中的 g 数据删除:

如何获取session/g

通过 、偏函数(lookup_req_object)、Localstack、Local 取值

Flask内置功能:

内置组件

配置 - 路由 - 视图

模板 - session - 蓝图

闪现 - 装饰器 - 中间件

第三方组件

Flask-session # 将原来保存在cookie中的session数据,放到Redis/memcache/文件/数据库中

公共:

DButils # 数据库连接池: 两种模式; 为每个参数设置一个连接/共享一个连接;全局参数

wtforms # form组件:做表单验证+生成HTML标签

手写:自己写一个类+列表, 实现栈的功能(LocalStack)

技术分享图片

分组函数 : 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())

View Code

反射在哪里用到过

那些坑爹的python面试题

标签:面向对象 通过 延迟 如何使用 setup c++ 字节 拼接 内存泄露

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值