python既支持函数编程,也支持面向对象编程,很多情况下,二者都能完成某个任务,java只支持面向对象。
功能居多,面向用户,如每个请求对应一个功能,功能驱动,业务功能多:函数
封装多,开源组件,精炼,提取公共部分,等:写面向对象。如Django框架,drf,全是类, 封装成一个组件时,重用性高,使用起来更简洁。
python函数特点:
-
函数作用域:
python中以一个函数为一个作用域,不是以冒号为作用域的,和JavaScript没有let关键字前一样。java以{}为作用域,如果在{}声明了一个变量,只能在{}这个作用域使用该变量
全局也是个作用域,可以看成一个大函数, -
pass
流程占位 -
函数的参数
*args 容纳传过来的参数,动态插入,传多少都行
**kwargs
如果函数中某个参数为可变类型,没有执行前,编译过程中,不仅生成了一个函数内存,还生成了了一个另外一个空间,存放默认的可变数据类型
例:
def f(n, n2=[]): # 如果函数中某个参数为可变类型,没有执行前,编译过程中,不仅生成了一个函数内存,还生成了了一个n2=[]的空间,
n2.append(n)
return n2
l2 = f(666) # 如果没有传n2,默认使用空列表,内存中的内容为[666,]
print(l2)
print(id(l2))
l1 = f(1, [2, 3]) # 由于传了新值,开辟了新的空间
print(l1)
l3 = f(2) # 没有传第二个参数,还是用默认的空间中的值
print(l3)
print(id(l3))
运行结果
[666]
2282968690504
[2, 3, 1]
[666, 2]
2282968690504
- 列表生成式
data = [lambda :i for i in range(10)]
ret = data[5]()
print(ret)
运行结果
9
由于i这个变量在内存空间中一直被重新赋值,最终为9,所以执行时都是9
- 装饰器
场景
flask框架路由
django的csrf
django的缓存
django的auth认证组件
基本装饰器:
import functools
def wapper(func):
@functools.wraps(func) # 加了这个装饰器,函数的原信息保留下来了
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
def f1():
pass
print(f1, f1.__name__)
@wapper
def f1(): # 执行时:wapper(f1)()
pass
print(f1, f1.__name__)
运行结果:
<function f1 at 0x000001CF622BEC80> f1
<function f1 at 0x000001CF61BD41E0> f1 实际是inner地址
例1:写装饰器,重复执行n次
import functools
def couter(times): # 带参数的装饰器必须返回一个装饰器, 区别是保留了一个参数times
def wapper(func):
@functools.wraps(func)
def inner(*args, **kwargs):
for i in range(times):
result = func(*args, **kwargs)
return result
return inner
return wapper
@couter(5) # 带参数的装饰器 # 执行couter函数,返回值和@结合起来,当做装饰器,
def f1():
print('f1')
f1()
运行结果:
f1
f1
f1
f1
f1
- 生成器
生成器作用:节省空间
列表:可迭代对象
应用场景:
redis中有1000万条数据,全部打印到屏幕。
redis中的数据存在内存上的,数据太大,不能一次取,通过redis中的hscan_iter的中的生成器,一段一段取出来。
例:
# 假如redis中数据如下
'''
{
v1: {
'n1': 1,
'n2': 2,
'n3': 3,
'n4': 4,
'n5': 5,
'n6': 6,
'n7': 7,
'n8': 8,
'n9': 9,
'n10': 10,
'n11': 11,
'n12': 12,
'n13': 13,
'n14': 14,
'n15': 15,
...
'n1000w': 1000w
}
}
'''
import redis
conn = redis.Redis()
g = conn.hscan_iter(a) # h:hash name:v1 count:一次取多少 yield:成了生成器对象
for i in g: # 写完生成器时没有取值,只有进行迭代时才执行内部的代码
print(i)
源码解析:
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:
# [{}, ...] --> cursor = 100 取完后cursor=0
cursor, data = self.hscan(name, cursor=cursor,
match=match, count=count)
for item in data.items(): # 循环每条数据
yield item # 往外yield每条数据,一旦yield完再走上面的while循环
- 迭代器
for循环内部就是用迭代器,从前到后一个一个获取
生成器是一种特殊的迭代器,是迭代器的一种
可迭代对象:类中含有__iter__方法和返回一个迭代器
普通类:
class F():
pass
o = F()
for i in o:
print(i) # TypeError: 'Foo' object is not iterable 由于不是可迭代对象,所以不可迭代
可迭代对象:
class F():
def __iter__(self):
# return iter([1, 2, 3]) # iter()返回一个迭代器,(可以用next获取)
yield 1
yield 2
yield 3 # 由于生成器是迭代器的一种,返回生成器,
o = F()
for i in o:
print(i)
运行结果:
1
2
3
- 反射
getattr
setattr
delattr
hasattr
应用场景:
1.django的CBV中:根据method不同找到不同的方法,内部通过getattr找到的
2.配置文件setting
python大部分配置文件都用到反射。
如:django的中间件的加载
那么他是怎样通过这个字符串找到对应的类呢?
其他配置文件的内容也通过字符串反射找到对应的类。如Scrapy框架中的配置文件,DjangoRfw中的配置文件
反射的作用: