三范式
1.一个数据一个字段
2. 只要有主键的
3. 减少重复
GIL
叫什么:全局解释器锁cpython
有什么用:单核的情况下实现多任务NB
怎么解决:
换解释器锁jpython
进程加协程(个人建议)
线程用其他语言实现,python调用
深拷贝与浅拷贝
深拷贝
递归拷贝每一层的数据
浅拷贝
拷贝第一层的数据
跟引用的区别
引用:多个变量指向同一个内存地址
拷贝:产生一个新地址(不可变类型不会产生,int,字符串,元组)
python基本上如果提供了copy方法都是浅copy
私有化
_x:单前置下划线,私有化属性或方法,from somemodule import * 禁止导入,类对象和子类可以访问
__xx:双前置下划线,避免与子类中的属性命名冲突,无法在外部直接访问(名字重整所以访问不到)
__xx__:双前后下划线,用户名字空间的魔法对象或属性。例如:__init__ , __ 不要自己发明这样的名字
xx_:单后置下划线,用于避免与Python关键词的冲突
模块搜索路径
sys.path
模块更新
from imp import reload
导入两种模块方式的区别
import **** 这个可以当做是引用
from **** import *** 这个可以当做深拷贝
闭包
闭包:两个函数的嵌套,外部函数返回内部函数的引用,外部函数一定有参数
有什么用:在执行函数的时候可以在外部函数中保留参数在内存中
写法:两个函数的嵌套,外部函数返回内部函数的引用,外部函数必须有参数
def 外部函数(参数):
def 内部函数():
pass
return 内部函数
闭包跟函数之间的区别:
1.格式两个函数嵌套
2.闭包外部函数的参数可以在内存中保持
nonlocal这个就是修改外部参数的值
装饰器
装饰器是什么:闭包上加@xxx
1. 先写一个万能装饰器
def set_fun(func):
def call_fun(*args,**kwargs):
return func(*args,**kwargs)
return call_fun
2. 在要装饰的函数上写一个@xxx
@set_fun
def test():
print("test")
装饰器有结论
1.装饰前的test函数是由func指向的
2.装饰后的test其实就是call_fun
3.道德上装饰不会去更改原先函数的返回值及调用方式
4.func,装饰前的test,call_fun三个参数必须一致
两个装饰器装饰一个函数
能够说出执行的结果,(秋裤大法跟电梯)
一个装饰器一个函数(了解)
二个装饰器装饰器一个函数内存图(了解)
装饰器传参
概述:三个函数的嵌套,第三层函数返回闭包的外层的引用,第三层必须有参数。
在闭包外层再套一层,返回闭包的引用
def set_args(args):
def set_fun(func):
def call_fun(*args,**kwargs):
return func(*args,**kwargs)
return call_fun
return set_fun
@set_args("xx")
def test():
print("test")
@set_args("xx")这个要分两步执行,第一步执行 set_args("xx")函数得到一个闭包的最外层的引用,第二步去@闭包的最外层引用去执行原先的装饰器过程
多态
python有多态,但是不是一个严谨的多态,因为Python是一个动态语言,没有强制类型
封装
一个函数一个功能,一个类是多个相关函数的集合
继承
子类中相同的方法会放到父类中,减少代码重复性
mro 及多继承
mro类初始化顺序表,保持我们的类只初始化一次
super()从mro顺序表中找到自已的位置,从mro顺序表中调用下一个类
实例与类之间的调用关系
实例可以调用三种类型的方法(静态,类,实例),可以调用类的属性及自我的属性
类可以调用三种类型的方法(静态,类,实例),但是不能调用实例上的属性
property(常量)
1. 完成常量,常量是能得到到数据,但是不能修改数据,一般常量都是大写
2. 代码实现
1.这个常量一般在init中创建一个私有的属性
2.提供一个得到这个私有属性的方法,但是我们为了让常量更直观,在方法上加入装饰器@property
3.调用就可以使用(类名.方法名)
魔法属性与方法
__dict__:查看属性
__class__:查看谁创建了我
__init__:初始化
__new__:创建时,一般单例
__call__:实例()调用
上下文管理器
只要实现了__init__ ,__enter__,__exit__这三个方法就可以说实现了上下文管理器
1.简化了代码
2.程序退出时自动关闭
3.操作时出现异常也会自动关闭
with myopen() as f:
pass
myopen()这个调用__init__方法
as 后面的f由__enter__这个方法返回
程序执行完后退出我们会执行exit,一般用来关闭资源
logging日志模块
开发过程中出现bug是必不可免的,你会怎样debug?从第1行代码开始看么?还是有个文件里面记录着哪里错了更方便呢!!!log日志
1. 日志级别
日志一共分成5个等级,从低到高分别是:
1.DEBUG
2.INFO
3.WARNING
4.ERROR
5.CRITICAL
说明:
DEBUG:详细的信息,通常只出现在诊断问题上
INFO:确认一切按预期运行
WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例 如。磁盘空间低”)。这个软件还能按预期工作。
ERROR:更严重的问题,软件没能执行一些功能
CRITICAL:一个严重的错误,这表明程序本身可能无法继续运行
这5个等级,也分别对应5种打日志的方法: debug 、info 、warning 、error 、critical。默认的是WARNING,当在WARNING或之上时才被跟踪。
2. 日志输出
有两种方式记录跟踪,一种输出控制台,另一种是记录到文件中,如日志文件。
说明
1.通过logging.basicConfig函数对日志的输出格式及方式做相关配置,上面代码设置日志的输出等级是WARNING级别,意思是WARNING级别以上的日志才会输出。另外还制定了日志输出的格式。
2. 注意,只要用过一次log功能再次设置格式时将失效,实际开发中格式肯定不会经常变化,所以刚开始时需要设定好格式。
3、日志格式说明
logging.basicConfig函数中,可以指定日志的输出格式format,这个参数可以输出很多有用的信息,如下:
%(levelno)s: 打印日志级别的数值
%(levelname)s: 打印日志级别名称
%(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
%(filename)s: 打印当前执行程序名
%(funcName)s: 打印日志的当前函数
%(lineno)d: 打印日志的当前行号
%(asctime)s: 打印日志的时间
%(thread)d: 打印线程ID
%(threadName)s: 打印线程名称
%(process)d: 打印进程ID
%(message)s: 打印日志信息
在工作中给的常用格式如下:
format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s'
这个格式可以输出日志的打印时间,是哪个模块输出的,输出的日志级别是什么,以及输入的日志内容。
元类(Django)了解
元类的格式
类名 = type(类名,(父类...),{属性名:属性值})
可以修改类的属性
在类中使用metaclass=处理的对象