一、装饰器(decorator)

  • 装饰器本质上也是函数,目的是为其他函数添加附加功能(装饰其他函数)
  • Python通过使用装饰器来达到代码的开放与封闭。

原则:

  1. 不能修改被装饰函数的源代码。
  2. 不能修改被装饰函数的调用方式。

我们现在有个需求:写一个计时器来统计每个函数执行的时间长度,满足上面的2个原则。

  • 实现一:
import time

def timer(func):
start_time = time.time()
func()
stop_time = time.time()
print("The function run time is %s" % (stop_time-start_time))
return func def f1():
print("This is function F1")
time.sleep(1) timer(f1)

上述方法虽然可以实现需求,但是它却改变了原函数f1的调用方式,所以不满足第2个原则。

  • 我们下面使用装饰器来实现:
import time

def timer(func):
def deco():
start_time = time.time()
func()
stop_time = time.time()
print("The func run time is %s" % (stop_time-start_time))
return deco @timer
def f1():
print("This is function F1")
time.sleep(1) f1()

装饰器使用“@+函数名”的语法,当代码运行到@timer的时候,会把下面被装饰的函数f1做为自己的参数,相当于:func = f1,当f1()执行时,实际上执行的是deco()。

  • 当被装饰的函数有参数时我们怎么实现呢?
  1. 参数固定时:
def login(func):
def deco(user):
print("[装饰器]正在验证登录:")
func(user)
return deco @login
def wel(user):
print("Welcome %s to login the page!" % user) wel("huyd")

2.参数不固定时:

def login(func):
def deco(*args,**kwargs):
print("[装饰器]正在验证登录:")
func(*args,**kwargs)
return deco @login
def wel(*args,**kwargs):
print("Welcome {} to login the page!".format(*args,**kwargs)) wel("huyd")
  • 当被装饰的函数有返回值时,又该怎么实现呢?
def login(func):
def deco(*args,**kwargs):
print("[装饰器]正在验证登录:")
res = func(*args,**kwargs)
return res # 此处应该将被装饰函数的返回值return
return deco @login
def wel(*args,**kwargs):
print("Welcome {} to login the page!".format(*args,**kwargs))
return "sucessful" # 被装饰的函数有返回值 wel = wel("huyd")
print(wel)
  • 装饰器也可以有自己的参数
def deco_fun1():
print("装饰器功能1") def deco_fun2():
print("装饰器功能2") def deco(deco_fun): # 第1层传入装饰器参数(这里只传入了1个参数,也可传入多个)
def outer(main_fun): # 第2层传入被装饰的函数名
def inner(): # 第3层传入被装饰函数的参数
deco_fun()
main_fun()
return inner
return outer @deco(deco_fun1) # 这样就使用了装饰器deco功能1
def index():
print("我是主程序") index()

需求:使用装饰器写一个简单的用户认证功能,当登录index页面时使用本地验证用户名,登录home页面时使用LDAP验证。

user,passwd = 'huyd','123'

def auth(auth_type):     # 判断装饰器的参数
def outer_wrapper(func):
def wrapper(*args,**kwargs):
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if username == user and password == passwd:
print("\033[32;1mLogin successful!\033[0m")
res = func(*args,**kwargs)
return res
else:
print("\033[31;1mInvalid username or password!\033[0m")
elif auth_type == "ldap":
print("Home page must be LDAP type Login!")
return wrapper
return outer_wrapper @auth(auth_type="local")
def index():
print("Welcome to index page!")
return "Index" @auth(auth_type="ldap")
def home():
print("Welcome to home page!")
return "Home" # index() # 进入index页面时使用本地验证登录
home() # 进入home页面时使用LDAP验证登录

二、生成器(generator)& 迭代器(iterator)

  • 迭代器是访问集合中元素的一种方式,迭代器 object从集合中的第一个元素开始访问,知道所有的元素被访问完成.
  • 所以迭代器的特点是:只能往前,不能后退
  • 迭代器的优点:不需要提前准备整个迭代器中的所有元素,仅仅迭代到某个元素时才计算该元素,而之前或者之后,元素可以不存在或者销毁.因为这个特点,迭代器特别适合遍历文件比较大或者无限的集合.
  • 总结下迭代器 iter()的特点吧:
  1. 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
  2. 不能随机访问集合中的某个值 ,只能从头到尾依次访问
  3. 访问到一半时不能往回退
  4. 便于循环比较大的数据集合,节省内存

迭代器是用__next__()来取值的,来看个例子吧:

gen = iter([1,2,3])

# 取值方法一:
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
print(gen.__next__()) #再取值就会报错 # 取值方法二:
for i in gen:
print(i)

能被for直接循环的都是可迭代对象,如列表,字典等。判断一个对象是不是可迭代对象,可以使用isinstance(*, Iterable)来判断。

生成器在被调用的时候返回一个迭代器。生成器有个标志性的语法yield。

当生成器被调用时,yield返回一个值,并记住当前位置,下一次调用时,从yield下一句语句运行返回下一个值。

def catch_mony(amount):
while amount > 0:
amount -= 100
print("又来取钱了!")
yield "给你100吧,剩余:{}".format(amount) atm = catch_mony(500)
print(type(atm))
print(atm.__next__())
print(atm.__next__())
print("去看电影!。。。")
print(atm.__next__()) ======================================
运行结果: <class 'generator'>
又来取钱了!
给你100吧,剩余:400
又来取钱了!
给你100吧,剩余:300
去看电影!。。。
又来取钱了!
给你100吧,剩余:200

此外,yield还有实现在单线程模式下实现并发运算的效果。如下例:

import time

def consumer(name):
print("{}准备吃包子啦!".format(name))
while True:
baozi = yield # yield也可以用于接收值
print("第{}次的包子来了,被{}吃掉了!".format(baozi, name)) def producer(name):
c1 = consumer('A')
c2 = consumer('B')
c1.__next__()
c2.__next__()
print("{}准备开始做包子了!".format(name))
for i in range(1, 11):
time.sleep(1)
print("{}第{}次做了两个包子。".format(name, i))
c1.send(i) # 将i的值传给yield
c2.send(i) # 将i的值传给yield producer("老板")

三、Json & pickle 数据序列化

用于序列化的两个模块:

  • json,用于字符串 和 python数据类型间进行转换
  • pickle,用于python特有的类型 和 python的数据类型间进行转换
  • Json模块提供了四个功能:dumps、dump、loads、load
  • pickle模块提供了四个功能:dumps、dump、loads、load
import json
data = {'k1':123,'k2':'Hello'} # json.dumps 将数据通过特殊的形式转换为所有程序语言都认识的字符串
j_str = json.dumps(data)
print(type(j_str),j_str) # json.loads 将字典形式的字符串转换为字典格式
j_dict = json.loads(j_str)
print(type(j_dict),j_dict) # json.dump 将数据通过特殊的形式转换为所有程序都认识的字符串,并写入文件
with open('result.json','w') as f:
json.dump(data,f) ####################################################################### import pickle
# pickle.dumps 将数据通过特殊的形式转换为只有python语言认识的字符串
p_str = pickle.dumps(data)
print(type(p_str),p_str) # pickle.dump 将数据通过特殊的形式转换为只有Python语言认识的字符串,并写入文件
with open('result.pk','w') as f:
pickle.dump(data,f)

Python-04-基础的更多相关文章

  1. Python编程语言基础

    今天给大家讲解python语言基础~~ 01.python核心数据类型   整型数 int:整数是不带有小数部分的数字 浮点型数 float:浮点数是带有小数部分的数字(小数部分可以是0) 复数 co ...

  2. Python语言基础与应用 (P16)上机练习:基本数据类型

    本文是笔者在学习MOOC课程<Python语言基础与应用> (北京大学-陈斌)中根据上机课时的要求写下在代码 课程总链接: 中国大学MOOC B站 本节课链接 数值基本运算: 33和7+, ...

  3. Python实验报告——第2章 Python语言基础

    实验报告 [实验目的] 1.熟悉在线编程平台. 2.掌握基本的 python 程序编写.编译与运行程序的方法. [实验条件] 1.PC机或者远程编程环境 [实验内容] 1.完成第二章实例01-07,实 ...

  4. Python文件基础

    ===========Python文件基础========= 写,先写在了IO buffer了,所以要及时保存 关闭.关闭会自动保存. file.close() 读取全部文件内容用read,读取一行用 ...

  5. 3.Python编程语言基础技术框架

    3.Python编程语言基础技术框架 3.1查看数据项数据类型 type(name) 3.2查看数据项数据id id(name) 3.3对象引用 备注Python将所有数据存为内存对象 Python中 ...

  6. Python爬虫基础

    前言 Python非常适合用来开发网页爬虫,理由如下: 1.抓取网页本身的接口 相比与其他静态编程语言,如java,c#,c++,python抓取网页文档的接口更简洁:相比其他动态脚本语言,如perl ...

  7. 小白必看Python视频基础教程

    Python的排名从去年开始就借助人工智能持续上升,现在它已经成为了第一名.Python的火热,也带动了工程师们的就业热.可能你也想通过学习加入这个炙手可热的行业,可以看看Python视频基础教程,小 ...

  8. Python爬虫基础之requests

    一.随时随地爬取一个网页下来 怎么爬取网页?对网站开发了解的都知道,浏览器访问Url向服务器发送请求,服务器响应浏览器请求并返回一堆HTML信息,其中包括html标签,css样式,js脚本等.我们之前 ...

  9. 零基础学Python--------第2章 Python语言基础

    第2章  Python语言基础 2.1 Python语法特点 2.11注释 在Python中,通常包括3种类型的注释,分别是单行注释.多行注释和中文编码声明注释. 1.单行注释 在Python中,使用 ...

  10. Python学习基础笔记(全)

    换博客了,还是csdn好一些. Python学习基础笔记 1.Python学习-linux下Python3的安装 2.Python学习-数据类型.运算符.条件语句 3.Python学习-循环语句 4. ...

随机推荐

  1. line-height行高与图片的隐匿文本间隙消除方法

    (标注 文章来源 http://www.zhangxinxu.com/wordpress/2015/08/css-deep-understand-vertical-align-and-line-hei ...

  2. jQuery实现侧边导航栏效果

    效果图: 效果体验:http://keleyi.com/keleyi/phtml/jqmenu/2.htm 以下是完整代码: <!DOCTYPE html> <html> &l ...

  3. HTML5移动端图片左右切换动画

    插件描述:HTML5移动端图片左右切换动画 小海今天要给大家分享一款很不错的图片左右切换焦点图动画,并且支持移动端触摸滑动.功能上,这款HTML5图片播放器支持鼠标滑动.手机端触摸滑动以及自动播放.外 ...

  4. 滚动条美化实践(原生js,iscroll,nicescroll)

    近期需要改造项目中的滚动条,使原滚动条在三大浏览器下表现相同,分享一下自己的改造经历: 项目中的滚动条分布在网页的各个小窗口中,使用的是-webkit-scrollbar制作,在-webkit内核的浏 ...

  5. webpack初体验

    本人菜鸟一枚,最近一直在研究webpack的使用,记录下自己的学习体会,由于网上关于webpack的资源(技术博客)太多,对于初学webpack的新手来说,看着五花八门的技术博客,真是头晕眼花(可能是 ...

  6. Day Tips:alertstemplates.xml

    1.修改Alert邮件模板,首先要注意的时候最好复制一份alertstemplates.xml,然后改一下名字,我改的是 custom_alertstemplates.xml,修改自己需要的代码部分. ...

  7. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q131-Q134)

    Question  131 You are designing multiple SharePoint 2010 features. You have the following requiremen ...

  8. ASP.NET 4.0尚未在 Web 服务器上注册 解决方法

    使用VS2010创建web应用程序时出现如下提示ASP.NET 4.0尚未在 Web 服务器上注册.为了使网站正确运行,可能需要手动将 Web 服务器配置为使用 ASP.NET 4.0,按 F1 可了 ...

  9. 使用AIDL调用远程服务设置系统时间

    在实际工作中,经常遇到客户需要用代码设置系统时间的需求,但是Android非系统应用是无法设置系统时间的.于是,我设计了一个使用系统签名的时间设置服务,客户通过bind调用服务里的方法就能达到设置时间 ...

  10. Github+hexo绑定域名

    Github绑定域名 近期在新网购买了一个属于自己的域名,因此想着把自己用hexo+github搭建的博客通过域名访问,但是找了n长时间来搞,都没有成功.心灰意冷之中再次通过google来搜索,终于有 ...