CHENGDU1-Python编程语言和PEP8规范
PEP8规范6条?
答:PEP8规范说白了就是一种规范,可以遵守,也可以不遵守,遵守PEP8可以让代码的可读性更高。
代码编排:---缩进,4个空格(编辑器都可以此功能),每行最大长度79,换行使用反斜杠......
字符串引用---python中双引号与单引号字符串是相同的,而且尽量避免在字符串中写反斜杠''
文档编排---不要在一句import多个库,
空格的使用---避免不必要的空格,各种右括号前不要加空格,逗号,冒号,分号前不要加空格,
函数左括号前不要加空格。if/for/while语句中,即使执行语句只有一句,也必须另起一行.......
注释:---块注释,在一段代码前增加的注释。行注释,在一句代码后加注释。
总体原则,错误的注释不如没有注释。所以当一段代码发生变化时,第一件事就是要修改注释!
命名规范:---尽量单独使用小写字母‘l’,大写字母‘O’等容易混淆的字母。
类的属性若与关键字名字冲突,后缀一下划线,尽量不要使用缩略等其他方式。
命名避免与python内置方法冲突,命名要有实际意义,不能随性所欲。
异常中不要使用裸露的except,except后跟具体的exceptions。异常中try的代码尽可能少。
迭代器、生成器、装饰器?
迭代:就是一个一个的取值。
可迭代对象:-------内部实现__iter__方法。
字符串,列表,元祖,集合,字典都是可迭代的。
可迭代和迭代器的相同点:都可以用for循环。
......................: 迭代器内部多实现了一个__next__方法。
判断迭代器和可迭代的方法?
答:1:判断内部是不是实现了__next__方法
2:lterable:判断是不是可迭代对象
lterable:判断是不是迭代器
range函数-----------------------------------是一个可迭代的,但不是迭代器。
map函数-------------------------------------map方法自带迭代器
哪里用过?
.............
迭代器:-----------有__next__方法的就是迭代器,迭代器是往前一个一个的取值,但是不能生成值。
生成器:-----------具有yeild方法,生成器是基于迭代器的,不仅取值还能生成值。被执行后返回的是一个生成器。生成器的本质就是一个迭代器。
装饰器:-----------装饰器的本质:就是一个闭包函数,在不修改原函数及其调用方式的情况下对原函数功能进行扩展。
装饰器的固定格式:
def timer(func):
def inner(*args,**kwargs):
'''执行函数之前要做的'''
re = func(*args,**kwargs)
'''执行函数之后要做的'''
return re
return inner
什么情况下使用装饰器?
小范围的需要给类增加方法的就可以使用装饰器
中间件是 比如验证 session,验证用户是否登录 基本上需要为绝大部分视图使用的时候就可以使用中间件来完成
带参数的装饰器?
带参数的装饰器,就是给装饰器传参。语法糖也要带个括号,在语法糖的括号里传参。
用处:当我们加了很多装饰器的时候,现在又不想加装饰器了,想把装饰器去掉,但一一去掉很麻烦,那么我们可以利用带参数的装饰器
去装饰它,这就像一个开关一样,用的时候就调用了,不用的时候去掉。
哪里用过装饰器?
用户登录
哪里用过带参数的装饰器?
flask的路由系统
闭包函数:---------在一个外函数中定义了一个函数,内函数里运用了外函数的临时变量,
并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
开放封闭原则
函数、作用域、闭包、参数?
函数
组织好的,可重复使用的,用来实现单一或相关联功能的代码段。def 开头,函数名加括号,要传入的参数放在括号中,最后冒号。
函数作用?
避免代码重复使用,提高代码的可读性。
函数名可以做参数,也可以做函数的返回值,函数名就是函数的内存地址。
函数的调用:函数内部可以调用与该函数处相同命名空间的函数。
函数的嵌套:函数内部可以定义函数,定义的函数还可以定义其他函数。
作用域
谈到作用域,就得说说命名空间,它俩是分不开的:
全局命名空间:创建存储"变量名与值的关系"的空间。
局部命名空间:在函数的运行中开辟临时的空间。
内置命名空间:内置命名空间中存放了python解释器为我们提供的名字:input,print,......我们熟悉的方法。
加载顺序:首先是内置命名空间(程序运行前执行)---->全局命名空间(从上到下顺序加载)---->局部(调用时加载)
---------全局的不能使用局部的,局部的可以使用全局的。
作用域?
就是作用的范围。
主要分两种:
全局作用域:全局命名空间与内置命名空间都属于全局范围,在整个文件的任意位置都能被引用,全局有效。
局部作用域:局部命名空间,只能在局部范围有效。
如果站在全局看:如果全局有,用全局的,如果全局没有,用内置的。
为什么要有作用域?
答:为了函数内的变量不会影响到全局。
globals:查看全局作用域的名字。
locals:查看局部作用域的名字。
nonlocal让内部函数中的变量在上一层函数中生效,外部必须有
作用链域:更大范围的作用域嵌套小范围的作用域
闭包
闭包:"闭"指的是内部的函数,"包"包含了对外部函数作用域中变量的引用。
判断闭包的方法:__closure__,返回cell是闭包函数,返回None不是闭包函数。
参数
函数的参数有:
1:形参:定义函数时定义的参数
2:实参:函数调用的时候传进来的参数。
可以传递多个参数,多个参数间用逗号隔开。
站在传参角度上,调用函数传参有两种方式:
1:按照位置传参
2:按照关键字传参。
位置传参必须在关键字传参前面,对于一个参数只能赋值一次。
还有默认参数:将变化比较小的参数设置为默认参数,参数可以不传,不传使用默认值,传会覆盖默认值。
默认参数是一个可变数据类型。
动态参数:
args:按位置传参,多余的参数都由args统一接收,保存成一个元祖。
kwargs:按关键字传参,接收多个关键字参数,由kwargs接收,保存成一个字典的形式。
列表生成式、生成器表达式?
答:
列表生成式:就是用一对中括号将生成列表的语句放入中括号内生成一个列表。
---------l = ['egg%s'%i for i in range(100)]
生成器表达式:生成器表达式通过结合列表解析和生成器来一次性生成数据。
就是将列表推导式的中括号换成小括号。生成器 = (返回结构 执行对象 if判断条件)
--------chicken=('鸡蛋%s' %i for i in range(5))
生成器表达式和列表生成式对比?
生成器表达式----较----列表生成式比较剩内存,因为是惰性计算的。
一行代码实现 9*9乘法表?
print ("\n".join("\t".join(["%s*%s=%s" %(x,y,x*y) for y in range(1, x+1)]) for x in range(1, 10)))
面向对象?
谈谈你认识面向对象?
说起面向对象又是一段沧桑史,刚开始根本没办法理解,啥是对象呀,我都没对象。后来通过做项目才对面向对象有了新的认识。
人们都喜欢说它的三大特性,那我们就从封装,继承,多态开始。
1:先说下类和对象?
类:具有相同属性和方法的一类事物
对象:也就是实例化
类内置的特殊属性有什么?
类名.__name__类的名字(字符串)
类名.__doc__类的文档字符串
类名.__base__类的第一个父类
类名.__bases__类所有父类构成的元组
类名.__dict__类的字典属性
类名.__module__类定义所在的模块
类名.__class__实例对应的类(仅仅在新式类中)
2:啥叫抽象?
抽象:不存在的,抽取类似的或比较像的。是一个过程(抽象到具体),是从小到大的过程。
3:在子类中调用父类的方法:----------super().类名()
4:接口类:------------在python中,默认是没有接口类的,接口类不能被实例化(如果实例化会报错),接口类中的方法不能被实现
5:抽象类: ------------在python中,默认是有的,父类的方法,子类必须实现,抽象类的方法也可以被实现。
6:抽象类和接口类的区别:-------------接口类不能实现方法,抽象类可以实现方法里面的内容。
7:抽象类和接口类的相同点:-----------都是用来做约束的,不能被实例化。
8:抽象类和接口类的使用:
当几个子类的父类有相同的功能需要被实现的时候用抽象类。
当几个子类有相同的功能,但实现各不相同的时候就用接口类。
9:python中的抽象类和接口类在Java里面的区别?
答:接口类支持多继承
抽象类只支持单继承
5:封装?
答:隐藏对象的属性和实现细节,仅对外提供公共访问方式。将同一类的方法和属性封装到类中,将数据封装到对象中。
好处:将变化隔离,便于使用,提高复用性,提高安全性。
封装原则:
a. 将不需要对外提供的内容都隐藏起来;
b. 把属性都隐藏,提供公共方法对其访问。
6: 继承?
答:类与类之间的关系,子类继承父类的方法和属性,解决代码重用问题。
派生:子类在父类的方法和属性的基础上产生自己的方法和属性。
如何查看继承?
类名.__bases__
多继承:在继承抽象类的过程中,我们应该尽量避免多继承。
在继承接口类的时候,可以多继承接口类。
钻石继承:
新式类:广度优先。
经典类:深度优先。
组合:将一个类的对象当做另一个类的属性,是什么有什么的关系。
7:多态?
答:多态指的是一类事物有多种形态。python里面处处都是多态。
class Wechat(object):
def send():
...
class Email(object):
def send():
...
def func(arg):
arg.send()
// obj = Wechat()
obj = Email()
func(obj)
8:经典类和新式类:
a.只有在Python2中才分新式类与经典类,Python3中统一都是新式类
b.在Python3中,无论是否继承object,都默认继承object,即Python3中所有类均为新式类。
区别:
在多继承中,新式类采用广度优先搜索,而旧式是采用深度优先搜索。
新式类更符合OOP编程思想,统一了python的类型机制。
注意:如果没有指定基类,Python的类会默认继承object类,
object是所有Python类的基类,它提供了一些常见方法(如__str__)的实现。
9:广度优先/深度优先?
答:广度优先: 广度优先的算法的实现是通过 分层次的进行遍历 先遍历第一层,然后第二层,第三层 (队列实现)
深度优先:将一个子节点的所有内容全部遍历完毕之后再去遍历其他节点实现的 (递归实现)
10:递归?
答:其实就是终止!
function Recursion(depth) {
console.log('抱着');
if (!depth) {
console.log('我的小鲤鱼')
} else {
Recursion(--depth); // 递归调用
}
console.log('的我');
}
console.log('吓得我抱起了');
Recursion(2)
#结果:吓得我抱起了抱着抱着抱着我的小鲤鱼的我的我的我
11:鸭子模型?
答:如果想编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观与行为像,但与他无任何关系的全新对象。
例如:序列类型有多种形态:字符串,列表,元祖,但他们之间没有直接的继承关系。
12:私有变量和私有方法?
私有变量:
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
私有方法:
在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
13:自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。
如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。
如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像__dict__,__name__及__doc__
答:在调用一个函数的过程中,直接或间接地调用了函数本身这个就叫递归
-----------------------------------------------------------------------------------------------------
哦,还有一些;
isinstance(obj,cls)---------------检查obj是否是类cls的对象
issubclass(sub,super)-------------检查super类的派生类
__call__----对象后面加括号,触发执行,构造方法的执行是由创建对象触发的。即:对象 = 类名()
__calll__方法的执行是由对象后加括号触发的。即:对象() 或 类()()
- 单例
- 用类做装饰器
- Flask源码
__new__-----------------------------------
- 单例
- 自定义Form验证
- wtforms源码
- django rest-framework中 序列化源码
__init__----------------------------------
__del__-----------------------------------析构方法,当对象在内存中被释放时,自动触发执行。此方法无需定义。
__iter__----------------------------------
- 对象要被for循环,stark组件组合搜索
反射(自省):以字符串的形式操作类中对象的属性。
四个可以实现自省的函数
__getattr__-------------------------------
- Flask源码,自定义的“本地线程” Local
- rest-framework request中取值
__getitem__-------------------------------
- Session源码
setattr -------------------------------
delattr -------------------------------
__next__----------------------------------
from collections import Iterator
class Item(Iterator):
def __init__(self,arg):
self.arg = arg
def __next__(self):
self.arg -= 1
if self.arg >1:
return self.arg
else:
raise StopIteration()
# 可迭代对象
class Foo(object):
def __iter__(self):
# 迭代器
return Item(10)
obj = Foo()
for item in obj:
print(item)
__dict__-------------------------
- 自定义Form
__add__ -------------------------
- data = obj1 + obj2
# obj1.__add__(obj2)
__str__和__repr__--------------改变对象的字符串显示
__for__mat---------------------自定制格式字符串
item系列:
__getitem__---------------
__setitem__---------------
__deltiem__---------------
metaclass-------可以*的,动态的修改,增加,删除,类或者实例中的方法或者属性。
当引入第三方库的时候,如果该库某些需要path的时候可以用metaclass.
批量的对某些方面使用decorator,而不需要都在上面加入@decorator_func
metaclass的实例化结果是类,而class实例化的结果instance.我们可以这样理解:
metaclass是类似创建类的模板,所有的类都是通过它来create的,(调用了__new__).
一般情况下,如果你要用类来实现metaclass的话,该类需要继承type,而且通常会重写type的__new__方法来控制创建过程。
在metaclass里面定义的方法会称为类的方法,可以直接通过类名来调用。
- 流程
metaclass的原理其实是这样的:当定义好类之后,创建类的时候其实是调用了type的__new__方法为这个类分配内存空间,创建
好了之后再调用type的__init__方法初始化(做一些赋值等)。所以metaclass的所有magic其实就在于这个__new__方法里面了。
说说这个方法:__new__(cls, name, bases, attrs)
cls: 将要创建的类,类似与self,但是self指向的是instance,而这里cls指向的是class
name: 类的名字,也就是我们通常用类名.__name__获取的。
bases: 基类
attrs: 属性的dict。dict的内容可以是变量(类属性),也可以是函数(类方法)。
所以在创建类的过程,我们可以在这个函数里面修改name,bases,attrs的值来*的达到我们的功能。这里常用的配合方法是getattr和setattr(just an advice)
- 在wtforms源码中看到过?
----wtforms源码:
GIL全局解释器锁?
答:GIL全局解释器锁,它是基于Cpython实现的。由于全局解释器锁的存在,所以在同一时间内,python解释器只能运行一个线程的代码。
线程运行在进程里,共享内存地址空间,有共享就有竞争。所以那个线程抢到了GIL锁,谁就先执行。如果遇到IO阻塞,就会把锁释放掉。
下一个线程抢到,继续执行。
GC垃圾回收机制?
答:Python的GC模块主要运用了“引用计数”来跟踪和回收垃圾。
在引用计数的基础上,还可以通过“标记-清除”解决容器对象可能产生的循环引用的问题。
通过“分代回收”以空间换取时间来进一步提高垃圾回收的效率。
详细过程:
python为每一个对象维护一个引用计数,当引用计数为0时代表这个对象为“垃圾”;
标记清除解决“循环引用”问题,标记根节点和可迭代对象,将不可达的视为垃圾;
分代回收解决标记清除的效率问题,当调用C的接口开辟内存和销毁内存的差值为700
的时候触发0代回收,当0代回收触发10次,触发一代回收,当1代触发10次,触发2次回收,
每次回收结束,没有被回收的对象放入下一代。
python2和Python3的区别?
答:
1. print不再是语句,而是函数,比如原来是 print 'abc' 现在是 print('abc')
2. 在Python 3中,没有旧式类,只有新式类,也就是说不用再像这样 class Foobar(object):
3.python2中有两种字符串类型:Unicode字符串和非Unicode字符串。Python3中只有一种类型:Unicode字符串。
4.Python2支持<>作为!=的同义词, python3只支持!=, 不再支持<>
5.在python2里,许多字典类方法的返回值是列表。最常用方法有keys, items和values。python3,所有以上方法的返回值改为动态试图。
几乎所有的python2程序都需要一些修改才能正常的运行在python3的环境下。-----------2转3--------2to3脚本
python的内置方法有那些?
__init__:构造方法,创建对象时默认执行__init__方法。
__new__:创建类实例的时候调用此方法。
__call__:对象加括号执行__call__方法。
__del__:构造方法。
__setitem__:给对象创建属性的时候执行。
__getattr__:获取对象属性的执行。
__str__:打印的是一个对象,如果有__str__,就去执行__str__里打印的东西。
__repr__:改变对象的字符串显示
__add__:两个对象相加
__dict__:查看类成员
__len__:查看长度的时候执行
__eq__:两个对象相等的时候执行。
repr和str的区别?
答:
函数str()用于将值转化为适于人阅读的形式,而repr()转化为供解释器读取的形式
(如果没有等价的语法,则会发生SyntaxError 异常),适合开发和调试阶段使用。
它俩的不同之处在于,在打印一个对象的时候,即执行了__str__,也执行了__repr__.
会首先打印__str__的返回值,如果没有__str__,就会执行__repr__.
所以在字符串格式化的时候,还是在打印的时候,__repr__都可以当__str__的替补。反之不行
当字符串格式化的时候%s和%r分别执行了__str__和__repr__.
cookie和session?
答:由于Http协议是无状态协议,无法保持状态,但我们又有保持状态的需求。就有了cookie.
有服务端产生内容,客户端收到响应保存在浏览器。当客户端再次请求的时候会自动带上cookie.
这样服务端可以通过cookie的内容来判断状态了。但由于保存在浏览器和很容易被查看和窃取,不是很安全。
由于cookie虽然解决了一部分保存状态的需求,但存在与客户端浏览器,不安全,而且字节有限。就有了session和cookie配合使用。
sesion保存在客户端有较高的安全性。当客户端访问服务端,服务端根据需求设置session。
将会话信息保存在服务器端,同时将标志session的session_id发送到客户端,客户端收到sessio_id保存在内存中,
以后发送请求都会带上这个session_id,通过sessio_id找到session,就能取得客户端的数据状态。
cookie存在服务器端,session存在于客户端上。