Python3-7月-笔记

8次阅读

共计 12756 个字符,预计需要花费 32 分钟才能阅读完成。

年初学习完七月老师的 Python 课程,使用 Markdown 做得笔记,一直没来及分享,趁着周末回顾下!大家可以参考下

第一章 Python 入门导学
1.1 Python 导学
  • python 不是一门新兴语言,上世纪 90 年代就已经存在。随着人工智能和大数据的火热,Python 随着成为主流编程语言
  • 以 Python 为技术主导的公司:豆瓣、知乎
  • Python 更像一个技术的润滑剂,大多数互联网公司或多或少都是会使用
  • 使用 Python3.6 版本,从基础语法到复杂高阶函数
1.2 Python 特征
  • 语法简洁,优雅,人生苦短,我用 Python
  • 易于学习,
  • 万金油语言
  • 即为强大的标准库和第三方库
  • Python 是面向对象的语言
1.3 我为什么喜欢 Python
  • 简洁、灵活、优雅,java 给人的感受是字正腔圆,大气端正
  • 易于上手难于精通
  • Python 既有动态脚本的特性,又有面向对象的特性(Java 是要编译的,Python 是可以动态执行的,但是没有 Java 严谨和工整,不用规范变量类型等)
1.4 Python 缺点
  • 慢,相对于 C,C++,Java
    (编译型语言 C,C++)由编译器编译成机器码
    (解释性语言 javascript,python)由解释权解释语言
    (Java 应该被分为在编译基础上进行解释的语言,由编译器编译成字节码,更贴近计算机能直接识别的机器码,需要编译器编译,需要解释器执行)
    (为什么有了编译型语言,还要开发解释型语言呢?
    运行效率,与开发效率不同)
    (语言没有好与坏,只有合适不合适)
1.5 一个经典误区
  • 编程?= web 编程 肯定不是呀,编程不等于开发网站或 APP
  • Python 的应用场景是非常多的
  • web 是基础,网站开发只是 web 的一部分
1.6 Python 都能做什么(万金油语言)
  • 爬虫(搜索引擎,新闻资讯)
  • 大数据与数据分析(spark)
  • 自动化运维与自动化测试
  • web 开发:flask,django(读音:粘钩)
  • 机器学习:tensorflow
  • 胶水语言:能够将其他语言制作的模块很轻松联系在一起
1.7 课程内容与特点
  • 基础语法
  • Pythonic,比如:变量值交互,x,y = y,x
  • Python 高性能与优化,选择性能最高,又易于理解的写法
  • 数据结构,使用 Python 实现一些常见的数据结构
  • 迷失在了技术海洋之中,回归语言本质,不精进,否则就是会瓶颈
1.8 Python 的前景
第二章 Python 环境安装
2.1 Python 学习建议
  • 入门:《Python 编程从入门到实践》(目前在看,感觉学完课程就没必要看了,如果当做知识回顾也是可以的)
  • 进阶书籍《流畅的 Python》
  • (不推荐)大量习题 python oj
  • 如何继续学习:数据分析(工具、框架、库是辅助,最主要的是数据模型的建立,所以是数学功底)
    AI 人工智能(Python 只是操作工具而已,最主要的是算法和数据模型)
    Python 工作中实现场景,比如自己写个小工具,推荐是搜索具体的库来实现
2.2 Python 版本选择
  • 稳定版,3.6,3.8(建议),日常开发,3.6 版本就足够了
  • Mac 中内置了 Python2
2.3 Python 多版本问题
  • 可以使用虚拟环境
2.4 Python Mac 版本指定
  • 问题是 Mac 自带 Python2,这样 Python2 就是默认版本
  • 切换到 Python3
    1. 默认是 python + 文件名,这样 Mac 调用 Python2
    所以要用 Python3 + 文件名
    2. 虚拟环境
    3. 系统默认的 Python 版本更换成 Python3
  • 或将 Python2 卸载
  • pylint 自动规范化工具
2.5 下载 Python 安装包
  • Mac 下载 Python3.8 pkg 包
  • 安装
  • 因为我的电脑里,有自带的 2.7, 竟然还有 3.7 版本,而且 3.7 我还删不掉,使用 python -V(2.7)python3 -V(3.7)python3.8 -V(3.8)
  • 所以我修改 python,默认指向 3.8
(1)修改.bash_profile 文件
vi ~/.bash_profile
PATH="/Library/Frameworks/Python.framework/Versions/3.8/bin:${PATH}"
export PATH  
(2)修改 bashrc 文件
sudo vi ~/.bashrc           //mac 下需要管理员才能修改此文件  
alias python2='/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7'
alias python3='/Library/Frameworks/Python.framework/Versions/3.8/bin/python3.8'
alias python=python3
// 添加以上三行,如果不知道自己的 python3 安装路径,可以用 which python3 命令进行查看路径
(3)修改的 bash_profile 文件 和 bashrc 文件 生效
source ~/.bash_profile
source ~/.bashrc
(4)查看 Python 当前版本
python -V  //3.8.2
2.6 安装 Python
2.7 IDLE 和第一行 Python 代码
  • IDLE 是 window 安装包自带的工具
  • Python 没有 分号 花括号,主要是利用缩进控制代码格式
第三章 Python 基本数据类型
Python3 六种数据类型
分为两类:不可变数据(number,string,tuple)可变数据(list,dictionary,set)

可变数据类型:当该数据类型对应变量的值发生变化时,对应内存地址并没有开辟新的内存,而是在原来的内存值上进行修改。

不可变数据类型:当该数据类型对应变量的值发生变化时,原来内存中的值不变,而是会开辟一块新的内存,变量指向新的内存地址。

number(数字)
string(字符串)
List(列表)
Tuple(元组)
set (集合)
Dictionary(字典)
数字 number
  • 整数 int 浮点数 float 布尔 bool 复数 complex
  • python 中没有单精度(float)和双精度(double)
  • 其他语言,整数 int 又分为 short,int,long,Python 中没有
  • type(2/2)得到的是 float, 单斜杠自动转型成浮点
  • type(2//2)得到的是 int, 双斜杠是整除
  • 二进制 0b10 => 2
    0b11 => 3
  • 八进制 0o10 => 8
    0o11 =>9
  • 十六进制 0x10 =>16
    0x1F => 31
  • Python 中,转成二进制,使用 bin()
  • Python 中,转成十进制,使用 int()
  • Python 中,转成十六进制,使用 hex()
  • Python 中,转成八进制,使用 oct()
字符串 string
  • 字符串拼接 +
  • 字符串截取‘hello world'[1]
  • 字符串截取 ‘hello world'[0:5](开始位置到结束位置 -1)[0:-1]表示第一个元素到倒数第二个元素的切片
列表 list
  • [1,’hello’,3]
元组
  • (1,2,3)
集合
  • 集合是无序的、不重复的元素序列
  • 可以使用 {} 或 set() 函数来创建集合
  • 注意:创建空集合只能是 set(),因为 {} 默认是创建空字典
  • 集合虽然定义是不重复的,但是你赋值了重复值,输出的依然是不重复值
   '''集合基本操作'''
    #1. 添加元素,如果元素已存在,则不进行任何操作
    s.add(x)
    #2. 添加元素,一次添加多个, 用逗号隔开
    s.update(x)
    #3. 移除元素(3 种方法)
    s.remove(x)
    s.discard(x)
    s.pop(x) #这个就是随机删除元素
    #4. 计算集合元素个数
    len(s)
    #5. 清空集合
    s.clear()
    #6. 判断元素是否在集合中存在
    x in s 
  • 小例子,利用集合特性来检测数据唯一性
   str = [1,2,3,4,5,6,7] 
   str_new = [1,2,2,3,4,5,4]
   def unique(seq):
       if len(str) == len(set(str)):
          print('该列表中元素是唯一的')
       else:
          print('该列表中元素不唯一')
字典
  • {}
  • key:value
  • 不允许同一个键出现两次
  • 键必须不可变,所以可以用数字,字符串或元组充当,而用列表、集合就不行
第四章 变量与运算符
变量
  • 命名有意义,可读性要强
  • 变量命名规则:字母、数字、下划线组成,首字母不能为数字
  • 系统保留关键字不能用作变量名
值类型与引用类型
  • 值类型:不可变类型(int,string,tuple)
  • 引用类型:可变类型(list,set,dictionary)
  • 如果在元组中的列表,是可以改变的(1,2,[3,4])
a = 'hello'  # id(a)
a = a + 'world' # id(a) 内存地址已经改变,所以是新的内存区域

b = 'python'
b[0] = 'b' # 会报错,因为不可改变,是原有值不可改变
b = 'php'  # 不会报错,因为是重新赋值,开辟新的内存块

# 上述情况,在 PHP 中就不会存在
$a = 'php';
$a[0] = 't';# 单一字符是没问题,但是如果是’python' 就不会替换,应该是内存区块大小限制了
print($a);# 可以正常打印 
列表的可变与元组的不可变
  • 稳定性,元组
运算符
  1. 算术运算符
    + 加
    – 减
    * 乘
    / 除
    // 整除
    % 取余
    ** 幂
    2. 赋值运算符
    =
    +=
    *=
    /=
    %=
    //=
    Python 中没有自增自减运算符 ++ —
    3. 关系运算符
    ==
    !=
    >
    <
    >=
    <=
    4. 逻辑运算符
    and 且
    or 或
    not 非
    5. 成员运算符
    in
    not in
    字典类型判断是 key
    6. 身份运算符
    is(比较的是内存地址)
    is not
    7. 位运算符 (把数字当做二进制数来进行运算)
    & 按位与
    | 按位或
    ^ 按位异或
    ~ 按位取反
    << 左移动
    >> 右移动
a = {1,2,3}
b = {2,1,3}
a == b  #true, 集合无序
a is b  #false , 比较的是内存地址

a = (1,2,3)
b = (2,1,3)
a == b #false,元组是有序的
a is b #false,比较内存地址
#比较变量,三方面:值(==),类型(type),身份(is)
#isinstance(a,string)

运算符

描述

**

指数(优先级最高)

* / % //

乘 除 取余 取整

+ –

加减运算

>> <<

右移左移运算符

&

位 and

^ |

位运算符

<= >= > <

比较运算符

<> != ==

等于运算符

= %= /= //= += -=

赋值运算符

is is not

身份运算符

in not in

成员运算符

not and or

逻辑运算符

Python 运算优先级,大家可以百度一下

第五章 分支、循环、条件、枚举
vscode 开发环境与 Python 插件安装
  • 打开控制面板 ctrl + ~
  • 搜索 command + shift + p
  • sinnpt 代码片段,快速构建代码,直接编辑不用删除,tab 跳转到下一个代码块,shift+tab 调到上一个
注释等语法
  • 单行注释 #
  • 多行注释 ”’
  • Python 是不可以压缩的,因为是通过空格来辨别语法
  • 变量命名,不要使用驼峰,而是用下划线 user_passwd
流程控制 - 条件控制
常量与 pylint 规范
while
  • 使用场景 递归,更多的还是使用 for
for in 与 for else
  • 主要用在遍历、循环 序列或者集合、字典
  • for in 类似 php foreach
  • 注意 break,continue
    continue 是此次循环,下面还会运行
    break 是结束本次循环,如果外面还有一层循环,是可以正常运行
    a = [['apple','banana','orange'],(1,2,3)]
    for x in a:
        for y in x:
        print(y)
for 与 range
  • for in range 相当于 php 的 for
    for x in range(0,10,2): #起始,终止,不符
        print(x,end='|')  #已 | 进行分割
第六章 包、模块、函数、变量作用域
6.1 包、模块、类
  • 包(类似文件夹)>> 模块(类似文件)>> 类(函数、变量)
  • 在 Java,PHP 中,一个文件最好只写一个类,并且类名和文件名是一致的。但是 Python 中,类是写在模块中,所以可以写多个类
  • 让一个普通文件夹成为一个包,那么包下必须含有__init__.py 文件
6.2 import 导入模块 和 from import 导入模块
  • Python 中的命名空间,要在理解下
  • 包和模块是不会被重复导入的,第一次导入就会将模块名加载到内存中,后续的导入仅仅是对加载到内存中的模块增加了一次引用,不会在重新执行 import 语句
  • 避免循环调用
import pylearn.helloworld.py as learn
print(learn.username)
#导入 pylearn 包下 helloworld.py 文件,重命名为 learn,打印其中的 username 变量

from pylearn.helloworld.py import username
print(username)
#也可以 from import * 表示引入模块下所有的类或变量,如果被引入的文件不希望所有都被引入,可以使用__all__=['username','password'] 限制可导出的类、变量、函数等
#如果一次想引入多个类或变量,可以 import(username,password)逗号隔开
6.3 init.py 的用法
  • 控制包里哪些模块可以导出
  • 批量引入公共类库
6.4 模块内置变量
  • 通过 dir() 查看所有变量
  • 入口文件和普通模块内置变量是有区别的
    #内置变量
    __name__ #命名空间,包名 + 模块名
    __package__ #包名
    __FILE__  #模块的路径
    __doc__   #表示模块中的注释
6.5 再深入理解顶级包的概念
  • 入口文件不可用使用相对路径导入模块
  • 7- 7 到 7 -15 可多看
第七章 Python 函数
7.1 函数定义及特点
    def get_userinfo(username,password):
        
        return username,password
        return (username,password)
        #返回多个结果,可以直接使用, 隔开,返回的结果类型也是元组, 或者可以将多个结果组合成列表或元组
    #结果接收采用序列解包,让各参数有意义。不推荐使用元素索引的方式
    username,password = getuserinfo('laravelvue','123')
7.2 序列解包与链式赋值
  • 序列解包,可以是 list,set,tuple
  • 序列封包:程序把多个值赋给一个变量时,Python 会自动将多个值封装成元组
  • 序列解包:程序允许将序列(字符串、元组、列表等)直接赋值给多个变量,此时序列的各元素会被依次赋值给每个变量(要求序列的元素个数和变量个数相等)
res = 1, 2, 3 # 序列封包,封包成一个元组赋值给 res 变量
print(res)    # 输出是序列:(1, 2, 3)
print(type(res))# 查看类型是元组类型
x, y, z = res  # 序列解包,序列中的元素依次赋值给 xyz 三个变量
x,y,z = 1,2,3  # 链式赋值
7.3 函数参数
  • 形参
  • 实参
  • 关键字参数,是为了提高代码可读性
  • 默认参数
  • 可变参数
  • 关键字可变参数
    #形参
    def get_userinfo(username,password):
        pass
    #实参    
    get('laravelvue','123') 
    #关键字参数
    get(username='laravelvue',password='123')
    #默认参数
    def get_ipinfo(ip,address='0.0.0.0')
    #可变参数
    def get_equipmentinfo(*param)
    #可以传递多个参数
    get_equipmentinfo('app','mobile')
    #如果传递元组、列表等,需要加上星号
    info = ('wxapp','mobile')
    get_equipmentinfo(*info)# 加上星号相当于解包成单个参数,所以函数获取到的就是一个一维元组,如果不加星号,那么得到的是二维元组
    #可变关键字参数
    #想要传可变关键字,必须有两个星号,如果不加,就不能传递可变关键字参数
    def city_temp(**param):
        #打印字典,要调用 items()方法
        for key,value in param.items():
        print(key,':',value)
        
    city_temp(bj='31c',sh='36') #传递的是元组,函数接收解析之后是字典
    #如果想直接传递一个字典,必须需要加上两个星号。如果不加星号就会是一个被元组包裹的字典,还是元组
    info = {'bj':'31c','sh':'36c'}
    city_temp(**info)
7.4 变量作用域,全局变量,局部变量
  • 函数体里可以使用全局变量,函数体外不可使用局部变量,但也不绝对,看具体函数
    c = 10
    def demo():
        print(c)# 函数体里可以使用全局变量,c 变量的作用域是整个代码块
        for i in range(0,9):
            a = '未预定义变量'
            c += i
        print(a)# 竟然是可以打印的,不需要预定义,因为在 Python 中,一个代码块,或者一个 for 循环,是不能成为一个作用域的,一个函数是有作用域的。真心不习惯,PHP,Java 是直接报错的
        print(c)
    #作用域链,作用域有个逐级寻找的。在 PHP,Java 中下面的代码一定是错的,因为变量未定义是不可使用的,而且未定义变量就调用,即使 Python 可以节省一行代码,但是可读性差    
    c  = 1
    def func1():
        c = 2
        def func2():
            c = 3
            print(c)
        func2()
    func1() 
    #一次把 c =3,c= 2 注释,打印结果为 3-2-1
7.5 global 全局变量
  • 可以在外部调用内部的局部变量(当然加上 global 就是全部变量了)
  • global 定义全局变量
    global db
    db = 'mysql'
第八章 面向对象
8.1 类的定义
  • python 实例化类,不用 new , 直接调用即可
    student = Student()
    而且通过. 来调用方法,而不是 ->
  • 字符串拼接用 + 很像 js
  • 类中方法,括号中要加 self
  • 类的最基本作用,封装代码
   class Student():
       name = 'laravelvue' #数据成员
       homework = 'python'
       def student_homework(self):
           print(self.name,'|',self.homework)
   student = Student()
   student.student_homework()        
8.2 函数与方法的区别
  • 没有绝对区别。在类中更多的应该叫方法, 如果在一些公共文件中编写的, 应该叫函数。
  • 类下的变量的 我习惯叫成员属性,python 叫数据成员
8.3 类、对象和实例化
8.4 构造函数
  • 构造函数自动调用
    class Student():
    name = 'laravelvue'
    homework = 'python'
        def __init__(self,name,homework):
            self.name = name
            self.homework = homework
        def student_homework(self):
            print(self.name,'|',self.homework)


    student = Student('laravelchen','python')
    print(student.homework)
8.5 区别 类变量 与实例变量
  • 类变量 – 相当于成员属性
  • 实例变量 – 就是对象的变量
  • 类变量与实例变量查找顺序 – 刚开始是会在实例中查找,如果没有会在父类中查找, 如果没有会去查找类变量
8.6 self 与实例方法
  • self 实质是一个指向实例本身的引用
  • 形参 self 比不可少,必须位于其他形参之前。
  • 解释 self:例如 python 在调用__init__构造函数创建实例时,将自动传入实参 self。每个与类相关联的方法调用都自动传递实参 self,self 实质是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
  • self 就像 PHP、Java 中的 this
  • 只是 Python 中的 self 必须在形参中强制要求写出来,叫显示调用,像 PHP 的 this 就不用写,可以直接用,叫隐式调用
8.7 类方法,静态方法,实例方法
  • Python 面向对象过程中,类属性可细分为类属性和实例属性,那么类中的方法可分为 类方法、实例方法、静态方法
  • 实例方法:一般情况下类中定义的方法 / 函数默认是实例方法
    实例方法最大的特点就是最少含有一个 self 参数,该 self 参数是为了绑定调用此方法的实例对象
  • 类方法:
    ①类方法至少包含一个参数,默认 cls
    ②Python 会自动将类本身绑定到 cls 参数,所以在调用类方法时,无需显式为 cls 参数传递参数
    ③类方法需要使用装饰器 @classmethod
  • 静态方法:
    ①静态方法没有 slf,cls 这些特殊形参,故 Python 解释器不会对其包含的参数做任何类或对象的绑定
    ②通过类直接调用,不需要创建对象
    ③静态方法主要用于存放逻辑性的代码,主要是一些逻辑属于类,但是和类本身没有交互。所以在静态方法中,不会涉及到类的属性和方法的操作
    #@classmethod 叫 装饰器
    #cls 是 class 简写
    @classmethod
    def get_info(cls):
        pass
    
    @staticmethod
    def add(x,y):
        pass
    def __get_user(self):        
        pass
8.9 访问控制 public,private,protected
  • 通过成员方法来修改成员属性
  • Python 没有 private 和 public,直接在前面设置双下划线__表示私有方法和属性
8.10 继承
  • 多继承
  • from import 文件之后,在类名括号中引入父类
    class Student(Homuman)
    PHP 中是继承分为两步,第一 use 引入; 第二 extends 继承
  • super 是子类用来调用父类方法的
  • 子类和父类方法重名,默认会执行子类方法
    其实下面的代码是 Python2 的继承方式
    super(Student,self).dohomework()
第九章 正则表达式与 JSON
9.1 Python 中使用正则表达式
  • 正则表达式的本质 就是 规则
‘’‘引入 Python 正则库’‘’import re
    str = 'Python|PHP|Java|C|C++'
    #方法一:使用 re.findall 返回结果为列表
    res = re.findall('Python',str)
    #方法二:使用 index()
    res = str.index('Python')
    #方法三:使用 in
    print('Python' in str)
    if len(res) >0:print('Yes')
    else:
        print('No')
            
9.2 正则表达式规则

模式

描述

^

匹配字符串开头

$

匹配字符串结尾

.

匹配任意字符,除了换行符

[…]

用来表示一组字符,[abc]匹配 a 或 b 或 c

[^…]

不在 [] 中的字符,[^abc]匹配除了 abc 的其他字符

re*

匹配 0 个或多个表达式

re+

匹配一个或多个表达式

re?

匹配 0 个或一个符合前面正则表达式片段,非贪婪模式

re{n}

匹配 n 个前面正则表达式

re{n,}

精确匹配 n 个前面正则表达式,a{1,}相当于 a +,a{0,}相当于 a *

re{n,m}

匹配 n 到 m 次由前面的正则表达式匹配的片段,贪婪模式

a|b

a 或 b

(re)

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

\w

匹配数字字母下划线

\W

匹配非数字字母下划线

\s

匹配任意空白字符,相当于[\t\n\r\f]

\S

匹配任意非空字符

\d

匹配任意数字, 相当于[0-9]

\D

匹配任意非数字

  • * 匹配 0 次或无限次
  • + 匹配 1 次或无限次
  • ? 匹配 0 次或 1 次
  • [] 中括号之间是或关系
  • () 小括号之间是且关系
9.3 re.sub()正则替换
  • re.sub(正则规则,替换成的字符,原始字符串,替换次数 0 是无限次)
    import re
    str = 'A12CED23412398075'
    def convert(value):
        matched = value.group()
        if int(matched) >= 6:
            return '9'
        else:
            return '0'
    #将函数当做参数传入函数中            
    res = re.sub('\d',convert,str)  
    print(res)     
9.4 re.search()和 re.match()
  • search 与 match 之匹配一次,非贪婪
  • findall 会自动匹配所有
9.5 group 分组
9.6 JSON, 序列号,反序列号
  • web 时代 - 移动端时代 -AI 时代
  • 反序列号,从 json 到 Python 或某个语言转换
  • 序列号,Python 转化成 json
    import json
    #json 对象
    json_str = '{"name":"laravelvue","age":18}'
    #json 数组
    json_arr = '[{"name":"laravelvue","age":18},{"name":"lc","age":18}]'
    #Python 将 json 对象转换成字典
    student1  = json.loads(json_str)
    #Python 将 json 数组转换成列表
    student2  = json.loads(json_arr)

json

python 格式

object

dict

array

list

string

str

number

int

number

float

true

True

false

False

null

None

9.4 json、json 对象、json 字符串
第十章 Python 高级语法与用法
10.1 枚举是一个类
  • 数字表示类型,破坏了代码的可阅读性,表示数据库里是可以的
  • 很多语言中,枚举是一个数据类型,而不是一个类
  • 枚举类和普通类的区别
    '''模拟枚举类型的三种方法'''
    # 通过定义变量
    yellow = 1
    black  = 2
    # 通过字典来定义
    {'yellow':1,'black':2}
    #通过定义类
    class TypeDiamond():
        yellow = 1
        black  = 2
    ''' 
    通过字典、类模拟枚举,有一下缺点
    1. 数据是可变的,通过代码很容易修改
    2. 不能防止重复性
    
    '''    
  • 枚举类型、枚举名称、枚举值
    '''引入 enum 类库'''
    from enum import Enum
    class Vip(Enum):
        YELLOW = 1
        BLACK  = 2
    print(Vip.YELLOW)# 这里打印出的是 Vip.YELLOW,type()的话是枚举类型
    print(Vip.YELLOW.name)  #获取枚举标签名,type()的话是 str
    print(Vip.YELLOW.value) #获取枚举值
   
  • 枚举可以进行等值比较,不能做大小比较,
  • 枚举转换 , 将数值转成名称
    a = 1
    name = Vip(a)
  • 如果想要枚举里数据不能重复,可以在类前添加装饰器
    @unique
  • 枚举类是不能实例化的,因为是单例模式
10.2 闭包
  • 基础知识能让我们写出代码,但不能让我们写出优质代码
  • 业务逻辑的开发者,不要考虑太多的封装性
  • 但是如果是包和类库的开发者,封装性要求高
  • 函数式编程
  • Python 一切皆对象
  • Python 中函数可以作为一个返回结果被返回
  • Python 中函数可以赋值给一个变量
   def add():
       def addall():
           pass
       return addall #函数可以作为一个返回结果被返回

   f = add() #函数可以赋值给一个变量
  • 闭包 = 函数 + 环境变量,把函数调用时的现场进行了保存
    def f1():
        a = 10
        def f2():
            a = 20
            print(a)
        print(a)
        f2()
        print(a)
    f1()  
    # 10-20-10
    '''理解闭包'''
    def f1():
        a = 10
        def f2():
            a*20# 如果在这里不是引用了环境变量(全局变量)里的 a,而是重新给 a 赋值,使用了局部变量;或者不使用环境变量,那么这就不是个闭包函数了
        return f2

    f = f1()    
    print(f.__closure__)     
  • 记录一个人的步数,每次记录的步数要保存,并进行累加。
    比如,初始 0 步,依次走 2,5,6 步,输出 2,7,13 步
    '''引用全局变量'''

    origin = 0
    def go(step):
        global origin
        origin += step
        return origin
    print(go(2))
    print(go(3))
    print(go(6))
    
    '''闭包函数'''
    pos = 0
    def tourist(pos):
        def go(step):
            nonlocal pos
            new_pos = pos + step
            pos  = new_pos
            return new_pos
        return go    
    go = tourist(0)    
    print(go(2))    
    print(go(3))    
    print(go(5))     
    #在这里打印 pos, 发现自始至终没有改变
    '''面向对象,调用类变量'''
    class move():
        origin = 0
        def go(self,step):
            self.step = step
            new_position = move.origin + step
            move.origin = new_position
            return new_position

    f1 = move()
    r1 = f1.go(2)
    r2 = f1.go(3)
    r3 = f1.go(4)
    print(r1, r2, r3)
    
第十一章 函数式编程、匿名函数、高阶函数、装饰器
11.1 匿名函数
    def add(x,y):
        return x+y
    
    #匿名函数
    lambda x,y:x+y
    # lambda params_list:expression
    #        参数列表    表达式
    # 表达式不能是很复杂的代码块,只能是简单的表达式
    # 调用匿名函数,可以将匿名函数赋值给变量 比如 f,然后 f()调用,但是这样没有这真体现匿名函数的优势
11.2 Python 的三元表达式
  • Python 没有像其他语言那样的专门三元表达式,而是利用 if else
  • 三元表达式经常适用于 匿名函数 中
   x > y ? x :y  
   #python 三元表达式含义如下
   # 条件为真时返回结果 if 条件判断 else 条件为假时返回结果
   x if x > y else y
11.3 map 类
  • map 类,相当于 for 循环,将传入的第二参数(列表、集合)中的每个元素,都去调用传入的第一个参数(函数)
    list_x = [1,2,3,4,5,7,9]
    def square(x):
        return x*x’‘’常规思路 可以 for 循环‘’‘for i in list_x:
        return square(i)’‘’使用 map 简化代码‘’‘list_y = list(map(square,list_x))
11.4 map 与 lambda
  • map 与 lambada 结合,可以使用匿名函数代替传入的第一个参数(函数)
  • map 和 lambda 不能提高代码的执行效率,仅是调高了代码的阅读性,让代码更简洁,当然你要能看到 map 和 lambda
   #如果匿名函数传入多个参数,那么 map 类也需要相应传入
   list_x = [1,2,3,4,5,7,9]
   list_y = [1,2,3,4,5,6,7]
   r = map(lambda x,y:x*x+y,list_x,list_y)
11.5 reduce
11.6 filter
  • 过滤
11.7 命令式编程 与 函数式编程
  • 命令式编程一些关键词,帮助理解,def if … else for .. in
  • 函数式编程一些关键词,帮助理解,map reduce filter lambda
11.8 装饰器
  • 设计原则之一:开闭原则 – 对修改是封闭的,对扩展是开放的
  • 思想:代码稳定性和复用性,想给一个函数增加一个功能,但是不想改变函数的内部实现,那么可以通过装新功能写成装饰器,每个地方调用的时候调用它,就 OK
  • 适用:
    import time

    def decorator(func):
        def wrapper():
            print(time.time())
            func()
        return wrapper
    @decorator
    def f1():
        print('This is a function')    

    # f = decorator(f1)
    # f() #这里 f 已经是一个函数,但是破坏了一般的调用方式,那如果还是想直接调用 f1 函数,那么就体现了装饰器的作用

f1()
  • 善于利用空行来进行区分代码块,让代码块结构更清晰
  • 不要在一个函数、一个类里写太多代码,函数体积越小就越灵活,就越有可能被复用,建议一个函数行数控制在 10-20 行之间
正文完
 0