1、包和模块
包:package
用来存放模块的文件夹
在python中将普通文件夹当成包
但是普通文件夹并不是包
如果在一个文件夹中存在__init__.py文件,这个文件夹就是python的一个包
在python中,如果导入了某个包,该包的初始化文件会自动执行(__init__.py)
在__init__.py文件中,一般用来书写一些初始化该包的代码
注意:__all__一般是容器
模块:xx.py 文件
import module_name
import os.* #在导包的时候,如果能够使用*,表示导入该包下的所有模块
2、is 和 = =:
在python中,==符号是用来判断两个变量的值
在python中,is关键字是判断两个变量的内存地址
3、小整形缓冲区:
python为了方便大家更快的使用一些常见的数据,提供了一个小整形缓冲区
数据范围是 [-5, 256]
id 全局函数
字符串常量也是一个常量
元组也一样
不可变类型在内存中只有一份
4、深浅拷贝
拷贝:复制数据
深浅拷贝,说的就是复制堆内存(对象)的过程
python考虑到我们有时候需要拷贝堆内存(对象),专门提供了模块copy
import copy
浅拷贝对象 = copy.copy(对象) #浅拷贝
浅拷贝:只会将堆内存的第一层完成拷贝,并不会多层拷贝(节约内存考虑)
深拷贝:在复制对象对象的时候,使用递归拷贝,将两个对象完全分开
深拷贝对象 = copy.deepcopy(对象) #深拷贝
不可变数据类型,深浅拷贝时本质不会发生变化!!!
a = 10
b = copy.copy(a)
id(a)
>>>1407830080
id(b)
>>>1407830080
5、函数的补充
偏函数:
简化操作
有时候我们需要不断调用某个函数,而此时存在固定的参数,那么就使用偏函数来完成简化操作
import functools
from functools import partial
my_int = partial(int,base=8)
my_int("10")
>>>8
闭包(closure):
函数包含函数
可以调用其他函数变量的函数
缺点:下面代码中,函数被调用后,内存没有释放
优点:变量a常驻内存,使局部变量具有全局变量的特点
def outer():
a = 10
def fn():
print(a)
return fn
result = outer()
#既然返回的是函数,就可以调用函数
result()
6、生成器:
|-- 列表生成式
python,列表生成式,快速生成需要的列表数,这是一个非常强大的功能
优点:简单的一行代码,快速生成我们需要的大量数据
缺点:
1、代码复杂度较高,可读性较低,维护成本比较高
2、正常编程中,可能我们需要的数据是列表中某个或某几个数据,但是列表生成式,直接将所有数据都生成到内存,大大浪费了内存
[ i for i in range(10)]
[ x for x in range(100) if x % 2 == 0]
[ x*y for x in range(10) for y in range(10)]
|-- 使用列表生成式的优点,但是又想节约内存
|-- 列表生成器(generator)
|-- 将列表生成式的中括号,换成圆括号,这样一个正常的列表生成式就会变成列表生成器
ls = (x for x in range(100))
>>>返回了一个生成器对象,堆内存地址
生成器最大的特点:并不会将数据直接存储在内存中,将生成数据元素的算法存储下来,得到一个对象(这段算法),该对象就是列表生成器(generator)
当我们需要元素的时候,调用next全局函数,就会返回对应的值
next(ls)
直至没有值,会抛出一个迭代终止异常,列表生成器停止工作
注意:生成器这个对象存在一个魔法方法__next__(),该方法和全局的next函数一样,都是用来返回列表生成器的下一个值
ls.__next__()
在真正的开发中,一些简单的就可以使用列表生成式,但是也存在一些很复杂的列表,这些列表一般很难使用一行或者几行代码生成,一般需要大量的代码来描述生成对应的数据
如:斐波那契数列的生成
从第三个元素开始,每个元素的值 = 前两个元素之和
此时,一般会将这些代码封装成一个函数
#斐波那契数列生成函数
ls = []
def fobina(n):
first, second = 1, 2
index = 0
while index < n:
#存储到列表中
ls.append(first)
#从第三个数据开始,每一个元素等于前两个数之和
first, second = second, (first + second)
index += 1
fobina(5)
print(ls)
|-- python也提供了将函数转换为列表生成器的方法
使用关键字yield
注意:如果一个函数中,存在yield关键字,此时该函数,不再是一个普通的函数,而是调用函数返回值的一个生成器
def fobina(n):
first, second = 1,2
index = 0
while index < n:
#因为内存原因,这儿不再使用列表存储,而是使用yield关键字
#将需要的数据返回回去
yield first
first, second = second, (first + second)
index += 1
#调用yield关键字的函数
res = fobina(10)
print(type(res))
#一个一个调用输出
#print(next(res))
#print(res.__next__())
#使用循环输出
for i in res:
print(i)
注意:
1、当函数中存在了yield关键字之后,函数不再是一个普通函数,当调用这个函数时,函数本身并不会被执行,返回值是一个生成器
2、使用next函数调用该生成器,代码开始执行,执行到yield关键字时,返回对应的值
3、下次再调用next调用生成器,代码会在上一次返回的地方继续向下执行
def fobina(n):
first, second = 1,2
index = 0
while index < n:
print("----1----")
yield first
print("----2----")
first, second = second, (first + second)
index += 1
res = fobina(10)
print(type(res))
print(next(res))
print(next(res))
7、迭代器
|-- 可迭代对象
|-- 列表
|-- 字符串
|-- 元组
|-- 集合
|-- 字典
......
判断某个对象是否可以迭代,如果可以迭代,我们可以通过for把每个元素取出来
判断某个对象是否可以迭代:
python提供了一个模块 collections模块中,存在Iterable类,
from collection.abc import Iterable
instance(对象, Iterable)
判断某个对象是否是迭代器:
能够被next函数调用,并且返回下一个值的对象,就是一个迭代器
如生成器,就是一个迭代器
iter 全局函数就可以将一个可迭代的对象转换为一个迭代器
s = "abc"
ss = iter(s)
type(ss)
>>><class 'str_iterator'>
isinstance(ss, Iterator)
>>>True
next(ss)
>>>'a'
next(ss)
>>>'b'
8、装饰器:
装饰代码,装饰功能
在原有功能的基础上,进一步的装饰代码,使得代码的功能更加强大。
结论:
1、软件开发,需要遵循一些软件开发的原则
OCP(open close protocol)原则 ---关闭开放原则
指的就是代码应该遵循对修改关闭,对增加开放
2、软件设计23种模式
装饰器,就是装饰者设计模式的体现
装饰器,来完成底层结构代码的扩展
|-- 装饰器怎么写
定义一个闭包函数
闭包函数就是我们需要装饰的代码
@闭包函数 完成装饰
|-- 装饰器运行原理
|-- 断点调试
"""
在所有功能里面加入日志
"""
#此时,我们自己定义的这个闭包函数就是一个装饰器
def out(fn):
def log():
print("开始记录日志了")
fn()
print("等执行完在记录数据")
return log
@out
def login():
#违背OCP原则
#print("记录日志了")
print("登陆了")
@out
def reg():
print("注册了")
login()
reg()
python是一门动态语言
如 Java c c++ 这些都叫做静态语言
当类被定义下来,不允许在外部被修改的
class Test(object):
def __init__(self,name,age):
pass
t1 = Test("小小",16)
print(t1.age)
t1.age = 18
#动态语言允许外界重新定义属性
t1.gender = "男"
python的垃圾回收机制:
python中的垃圾回收是以引用计数为主,分代收集和标记清除为辅
面试题:
python中list进行排序是sort方法,全局函数sorted也可以排序,他们的区别:
sort 是将列表本身发生排序,不会有返回值
sorted全局函数不会操作有序列表本身,会先拷贝出一个列表,对这个列表进行操作,然后return回来,原列表不会发生变化