函数闭包

定义

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

作用

  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 = 0
total = 0
def Avg_2(val):
nonlocal total,count
total+=val
count+=1
return total/count
return 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 decorate
return check_p @check_param(flag=True)
def my_sum(a,b):
return a+b if __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 decorate
raise 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
@classmethod
def 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 = name
self._subject = subject
def setName(self,name):
self._name = name
def getName(self):
return self._name
def setSubject(self,subject):
self._subject = subject
def getSubject(self):
return self._subject
def 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 = name
self._subject = subject @property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
@property
def subject(self):
return self._subject
@subject.setter
def subject(self,subject):
self._subject = subject def 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):
pass
def __str__(self):
return "I am str"
def __len__(self):
return 15
def __bool__(self):
return False if __name__ == '__main__':
a = A() print(a,len(a),a==True)

[学习总结] python语言学习总结 (三)的更多相关文章

  1. [学习总结] python语言学习总结 (二)

    1.python中的拆包 之前就只写了*可以是未知数量的参数,**可以传入未知数量命名参数.这次详细记下拆包. def f1(a, *l): print(a) # 不拆包 print(l) # 拆包 ...

  2. [学习总结] python语言学习总结 (一)

    还是不多说话了.. 1.eval函数 用法:eval(expression, globals=None, locals=None) 解释:将字符串str当成有效的表达式来求值并返回计算结果. 就是可以 ...

  3. python语言学习

    前段时间要做视频直播需要编写自动模块,就考虑使用python脚本语言,python的好多语法都是很独特的,比如数据类型不需要预定义,缩进的方式等,另外功能也很强大,豆瓣就是用python写的.我写的部 ...

  4. Python语言学习之Python入门到进阶

    人们常说Python语言简单,编写简单程序时好像也确实如此.但实际上Python绝不简单,它也是一种很复杂的语言,其功能特征非常丰富,能支持多种编程风格,在几乎所有方面都能深度定制.要想用好Pytho ...

  5. python语言学习1——初识python

    Python是著名的“龟叔”Guido van Rossum在1989年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言. 龟叔给Python的定位是“优雅”.“明确”.“简单”,所以Python ...

  6. Python语言学习之C++调用python

    C++调用python 在C/C++中嵌入Python,可以使用Python提供的强大功能,通过嵌入Python可以替代动态链接库形式的接口,这样可以方便地根据需要修改脚本代码,而不用重新编译链接二进 ...

  7. SM3杂凑算法Python语言实现——第三部分

    SM3杂凑算法实现--第三部分 一.SM3 密码概述        我们首先把需要用到的算法呈现出来,最后我们再考虑如何集合为一个库的方法,这一部分我们就开始编写一个新的算法:国家商用密码标准SM3密 ...

  8. python语言学习笔记整理

    什么是程序? 程序等于数据结构加算法,那么数据结构是一个静态的东西,算法是一个动态的东西,我们用一个新的语言编写这个程序,我们要考虑到语言也主要由数据结构和算法相关的东西,或静态或动态的东西来构成,所 ...

  9. 值得关注的10个Python语言学习博客

    大家好,还记得我当时学习python的时候,我一直努力地寻找关于python的博客,但我发现它们的数量很少.这也是我建立这个博客的原因,向大家分享我自己学到的新知识.今天我向大家推荐10个值得我们关注 ...

随机推荐

  1. CQL查Cassandra条目数中的小问题

    用查询语句:SELECT count(*) FROM tablename 返回类型是ResultSet,得到tablename中所有条目数 ResultSet类型可以直接用index访问:Result ...

  2. JS Guid生成

    function numToGuid(uid) { var str = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"; var l = uid.to ...

  3. Spring Boot Dubbo 构建分布式服务

    概述: 节点角色说明 节点 角色说明 Provider 暴露服务的服务提供方 Consumer 调用远程服务的服务消费方 Registry 服务注册与发现的注册中心 Monitor 统计服务的调用次数 ...

  4. String常用方法简介

    1. 创建String对象的常用方法 (1) String s1 = "mpptest" (2)  String s2 = new String(); (3) String s3 ...

  5. BZOJ 1116: [POI2008]CLO 并查集

    成立时当且仅当每个联通块都有环存在.一个连通块若有m个点,则必有多于m条有向边,可用并查集来维护. #include<cstdio> #include<iostream> #d ...

  6. 送气球.jpg(模拟)

    链接:https://ac.nowcoder.com/acm/contest/318/A 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言5242 ...

  7. PHP EXCEL相关

    这次的需求是在二次扫描的EXCEL报表中加入一列扫描时间. 扫描的时间之前已经写进日志里了,这次要做的就是把时间读取出来然后作为一列插入报表.其实日志也已经读出来了,要做的就是插入.但插入还是碰到不少 ...

  8. SpringBoot---Web开发---SSL配置

    1.[生成证书] 2.[SpringBoot配置SSL] 3.[http转向https]

  9. ms sqlserver 登录失败 错误:4064

    无法打开用户默认数据库.登录失败.用户‘sa’登录失败.(Microsoft SQL Server, 错误:4064) 解决方法:解决方法:先用windows身份验证的方式登录进去,然后在 安全性=& ...

  10. 使用Zeppelin时出现at org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService$Client.recv_getFormType(RemoteInterpreterService.java:288)错误的解决办法(图文详解)

    不多说,直接上干货! 问题详解 org.apache.thrift.TApplicationException: Internal error processing getFormType at or ...