函数闭包

定义

延伸了作用域的函数(能访问定义体之外定义的非全局变量

作用

  1. 共享变量的时候避免使用了不安全的全局变量
  2. 允许将函数与某些数据关联起来,类似于简化版面向对象编程
  3. 相同代码每次生成的闭包,其延伸的作用域都彼此独立(计数器,注册表)
  4. 函数的一部分行为在编写时无法预知,需要动态实现,同时又想保持接口一致性
  5. 较低的内存开销:类的生命周期远大于闭包
  6. 实现装饰器

代码

print("Class方式:")
class Averager:def __init__(self):self.series = []def __call__(self,new_val):self.series.append(new_val)return sum(self.series)/len(self.series)
avg1 = Averager()
print(avg1(3))
print(avg1(2))print("闭包方式:")
def Avg_1():count = 0total = 0def Avg_2(val):nonlocal total,counttotal+=valcount+=1return total/countreturn Avg_2
avg = Avg_1()
print(avg(9))
print(avg(10))
'''
输出
Class方式:
3.0
2.5
闭包方式:
9.0
9.5
'''

理解

功能说明

这段代码需要解决的是,定义一个average函数,我们每次传进去一个值,都可以得到这个值和之前传入值的平均值。比如第一次传入1,均值就是1,第二次传入2,均值就是1.5,以此类推。

类方式

第一种方式是通过构建一个类,这也是我们通常容易想到的方式,利用在类里面创建一个list,每次调用都将新值append进去,这是一种解决方法。

函数闭包方式

这里跟前面提到的作用域是有关的,函数闭包延伸了作用域,我们可以看到,我们的外层函数只是为了存储两个变量而已,没有其他作用了。其实这时候应该有个疑惑,在调用Avg_1()之后,由于count和total是在Loval层,函数调用结束了应该销毁了才是,但实际上并没有,我们在Avg_2中通过nolocal关键字延长了两个变量的生命周期,使得我们在每次调用的时候都能访问都两个变量,达到效果。

装饰器

为什么会出现装饰器这个东西

  • 名称管理
  • 显示调用
  • 就近原则
  • 充分复用

@语法糖

'@' 用做函数的修饰符,可以在模块或者类的定义层内对函数进行修饰,出现在函数定义的前一行,不允许和函数定义在同一行。

什么是装饰器

  • 装饰器是一个可调用的对象,以某种方式增强函数的功能
  • 装饰器是一个语法糖,在源码中标记函数(此源码指编译后的源码)
  • 解释器解析源码的时候将被装饰的函数作为第一个位置参数传给装饰器
  • 装饰器可能会直接处理被装饰函数,然后返回它(一般仅修改属性,不修改代码)
  • 装饰器也可能用一个新的函数或可调用对象替换被装饰函数(但核心功能一般不变)
  • 装饰器仅仅看着像闭包,其实功能的定位与闭包有重合也有很大区别
  • 装饰器模式的本质是元编程:在运行时改变程序行为
  • 装饰器的一个不可忽视的特性:在模块加载时立即执行
  • 装饰器是可以堆叠的,自底向上逐个装饰
  • 装饰器是可以带参数的,但此时至少要写两个装饰器
  • 装饰器的更加Pythonic的实现方式其实是在类中实现 call() 方法

代码

def check_param(**kw):flag = kw.get('flag')def check_p(func):def decorate(*args):if flag:if not all([isinstance(arg,int) for arg in args]):raise TypeError("{} only accepts integers as argument".format(func.__name__))return func(*args)return decoratereturn check_p@check_param(flag=True)
def my_sum(a,b):return a+bif __name__=='__main__':print(my_sum(1,2))print(my_sum(1,2.0))'''
输出
3
Traceback (most recent call last):File "/home/xueaoru/文档/pydemo/blog.py", line 18, in <module>print(my_sum(1,2.0))File "/home/xueaoru/文档/pydemo/blog.py", line 7, in decorateraise TypeError("{} only accepts integers as argument".format(func.__name__))
TypeError: my_sum only accepts integers as argument'''

解释

上面的代码是为了完成一个检查my_sum函数的参数是否是整数的功能的装饰器,同时增加了开关功能,我们将flag设置为true就是开启检查功能,如果不是整数,则直接报错。

理解

装饰器是对函数在不改变原有函数内部实现的情况下,对原有函数进行功能增强。而@语法糖是对原函数进行修饰的修饰符,当调用@语法糖进行修饰的时候,即使该函数并不调用,也会执行修饰语句,因为触发了运行装饰器。这时候该函数作为参数传给修饰函数的外部函数,然后该函数作为引用赋值给内部函数的函数名,也就是说我们真正的操作是在内部函数中进行的,因此可以在内部函数中对原函数进行功能增强。其中,有参数的时候呢,内部函数也需要通过*和**拆包得到参数,原函数有返回值的时候呢,我们在调用完原函数的时候也应该给出返回值。而装饰器本身带参数的时候呢,可以在装饰函数外再加一层接收参数的包装得到参数。

OOP In Python

概念

一切都是对象

从语言设计层面理解Python中的数据类型:一切都是对象,都是从Object继承过来的。Object由三部分组成:identity、type、value。

identity

理解

当Objects创建之后呢,identity也不会改变,直到被销毁。我觉得跟c++里的地址差不多吧,当然也不能完全这么理解,也有不同的方。

要点

  • 变量存储的是创建的Object的identity
  • 创建出来的不同Object有不同的identity
  • 变量的id变了不是因为Object的identity变了,而是对应的Object变了
  • 对于不可变对象而言,计算结果如果已经存在,可以直接返回相同的identity

type

要点

  • 当Object创建后,其type不会改变
  • type决定了一个Object可以支持那些运算,可能的值在哪些范围

value

要点

  • 有些Object的value可以改变:可变对象
  • 有些Object的value不可以改变:不可变对象

每一个class在定义的时候如果没有继承的话,那么他继承的就是Object这个超级class,而每一个自定义的class在python中都是一个type object。

@classmethod

理解

可以把类中的某个方法变成这个类的方法而不依赖于对象,也就是说,在对象没有创建的时候,我们也可以调用这个类的方法执行一定的操作。这就有点像C++中的静态成员函数。

代码

class Student:teacher_name = "Omg"def __init__(self,name):self._name = name@classmethoddef Teacher(cls):print(cls.teacher_name)def Me(self):print(self._name)
if __name__== '__main__':aa = Student("xue")aa.Teacher()aa.Me()Student.Teacher()
'''
Omg
xue
Omg
'''

解释

这段代码是通过调用Teacher方法得到老师的名字,可以看出,我们就算不通过对象直接调用,也可以输出老师的名字。classmethod就起这个作用。

@property

理解

本质上这是一个装饰器,可以省去写get、set函数的对外绑定。

property

函数原型为

property(fget=None, fset=None, fdel=None, doc=None)

代码

@property与下面的代码效果是一样的

class Teacher:def __init__(self,name,subject):self._name = nameself._subject = subjectdef setName(self,name):self._name = namedef getName(self):return self._namedef setSubject(self,subject):self._subject = subjectdef getSubject(self):return self._subjectdef show(self):print("name is:{} and subject is:{}".format(self._name,self._subject))name = property(getName,setName)subject = property(getSubject,setSubject)
if __name__ == '__main__':t = Teacher("A","math")t.show()t.name = "B"t.subject = "English"t.show()
'''
name is:A and subject is:math
name is:B and subject is:English
'''

使用@property之后的更加优美的版本

class Teacher:def __init__(self,name,subject):self._name = nameself._subject = subject@propertydef name(self):return self._name@name.setterdef name(self,name):self._name = name@propertydef subject(self):return self._subject@subject.setterdef subject(self,subject):self._subject = subjectdef show(self):print("name is:{} and subject is:{}".format(self._name,self._subject))
if __name__ == '__main__':t = Teacher("A","math")t.show()t.name = "B"t.subject = "English"t.show()

注意

这里@property必须在setter前面初始化,这个应该很容易理解,因为解释器读程序的时候是从上往下读的。

Special method

要点

  1. 之所有要实现special method,是为了让自定义的class与python中的内置函数无缝衔接
  2. python中有大量的内置函数,而这些函数中绝大部分是special method
  3. python中的special method :https://rszalski.github.io/magicmethods/

代码

class A:def __init__(self):passdef __str__(self):return "I am str"def __len__(self):return 15def __bool__(self):return Falseif __name__ == '__main__':a = A()print(a,len(a),a==True)

转载于:https://www.cnblogs.com/aoru45/p/9937751.html

[学习总结] python语言学习总结 (三)相关推荐

  1. python语言学习:python语言学习中的定义类、定义函数、封装api等详细攻略

    python语言学习:python语言学习中的定义类.定义函数.封装api等详细攻略 目录 python语言学习中的定义类 python语言学习中的定义函数 python语言学习中封装api pyth ...

  2. Python语言学习:Python语言学习之硬件交互应用(arduino、树莓派等)相关的简介、案例应用之详细攻略

    Python语言学习:Python语言学习之硬件交互应用(arduino.树莓派等)相关的简介.案例应用之详细攻略 目录 Python与硬件交互应用 1.适合运行python的嵌入式硬件系统 1.1. ...

  3. Python语言学习:Python语言学习之正则表达式常用函数之re.search方法【输出仅一个匹配结果(内容+位置)】、re.findall方法【输出所有匹配结果(内容)】案例集合之详细攻略

    Python语言学习:Python语言学习之正则表达式常用函数之re.search方法[输出仅一个匹配结果(内容+位置)].re.findall方法[输出所有匹配结果(内容)]案例集合之详细攻略 导读 ...

  4. Python语言学习:三种随机函数random.seed()、numpy.random.seed()、set_random_seed()及random_normal的简介、使用方法(固定种子)详细攻略

    Python语言学习:三种随机函数random.seed().numpy.random.seed().set_random_seed()及random_normal的简介.使用方法(固定种子)之详细攻 ...

  5. Python语言学习之字母R开头函数使用集锦:random/range/replace/reshape用法之详细攻略

    Python语言学习之字母R开头函数使用集锦:random/range/replace/reshape用法之详细攻略 random/range/replace/reshape用法 1.random用法 ...

  6. 【Python】Python语言学习:面向对象编程,类和对象,封装、继承和多态

    这一周Python语言学习,记录如下. 01 面向对象编OOP 1.1 为什么学习和应用OOP? 1 OOP适合更加复杂的需求分析和项目开发. 2 OOP具有更强大的封装能力. 3 OOP相比于面向过 ...

  7. Python语言学习:python语言代码调试—异常处理之详细攻略

    Python语言学习:python语言代码调试-异常处理之详细攻略 目录 python语言代码调试-异常处理 异常捕捉可以使用 try/except 语句 相关文章 Python3 错误和异常 | 菜 ...

  8. Python语言学习:利用pandas对两列字段元素求差集(对比两列字段所有元素的异同)

    Python语言学习:利用pandas对两列字段元素求差集(对比两列字段所有元素的异同) 目录 利用pandas对两列字段元素求差集(对比两列字段所有元素的异同) 输出结果 实现代码 利用pandas ...

  9. Python语言学习:在python中,如何获取变量的本身字符串名字而非其值/内容及其应用(在代码中如何查找同值的所有变量名)

    Python语言学习:在python中,如何获取变量的本身字符串名字而非其值/内容及其应用(在代码中如何查找同值的所有变量名) 目录

最新文章

  1. STM32-RCC内部总线时钟设置程序详讲
  2. Swiper学习之三---swiper的配置选项 ②:Free模式和Effects切换效果
  3. 95-10-190-启动-DynamicConfigManager
  4. 树大招风:英伟达证实遭遇攻击,核心源代码惨遭泄露,75GB机密数据被公开
  5. 指针法算中点坐标c语言,C语言:利用指针编写程序,用梯形法计算给定的定积分实例...
  6. SpringMVC学习指南【笔记4】数据绑定、表单标签库、转换器、格式化、验证器
  7. 边缘检测---Roberts算子
  8. maya城市汽车流光效果插件car motion light 1.0.1下载及教程
  9. 【线性系统】五、稳定性
  10. mysql实现跨库多表查询
  11. 人工智能数学基础---定积分2:定积分的性质
  12. 微信客服介绍和使用指引(4.19)
  13. linux查看gc日志,GC通用日志解读
  14. java delphi socket_Delphi跨平台Socket通讯库
  15. 微信公众号数据分析报告
  16. Windows Server 2012远程默认端口3389的修改
  17. nexus 向私服推送jar包 两种方式实现
  18. /etc/fstab 只读无法修改的解决办法
  19. 两个外企常用的电面网站
  20. 如何简单有效的删除win10英语美式键盘

热门文章

  1. sqoop导入hive时间格式问题解决方案
  2. java集合的遍历_Java集合之遍历
  3. java 内存泄露 书籍_java虚拟机内存溢出和泄漏实例
  4. servlet里面为什么有时候覆_为什么新来的经理强烈推荐?前后端分离知识,学到了...
  5. proe50安装方法64位_proe5.0安装方法64位
  6. 蓝桥杯单片机stc15f2k61s2矩阵按键中断扫描代码
  7. HTML+CSS+JS实现 ❤️照相机快门图片动画特效❤️
  8. matlab中如何表示线积分,MATLAB - 复杂的线/路径积分
  9. python 电脑显示桌面_使用Python快速实现显示器关闭和锁住桌面
  10. java启动应用_java 学习:在java中启动其他应用,由jenkins想到的