原文链接:http://chenhao.space/post/29dd046f.html
笔记目标
Python基础
- 函数
- 面向对象
- 文件操作和异常处理
- 模块的使用
- 装饰器、迭代器、生成器
函数
函数概述
例如:现在有这样一段代码
print(“天王盖地虎”)
print(“小鸡炖蘑菇”)
再来一段代码:在不同的地方相同的代码,那么这样的程序改如何设计
if 条件1:
print("天王盖地虎")
print("小鸡炖蘑菇")
elif 条件2:
print("天王盖地虎")
print("小鸡炖蘑菇")
elif 条件3:
print("天王盖地虎")
print("小鸡炖蘑菇")
如果需要输出多次,是否意味着要编写这块代码多次呢?
小总结:
如果在开发程序时,需要某块代码多次,但是为了提高编写的效率以及代码的重用,所以把具有独立功能的代码块组织为一个小模块,这就是函数
函数定义
函数定义的格式:
def 函数名():
代码
#案例:
# 定义一个函数,能够完成打印信息的功能
def printInfo():
print('------------------------------------')
print(' 人生苦短,我用Python')
print('------------------------------------')
函数调用
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它
调用函数很简单的,通过 函数名() 即可完成调用
# 定义完函数后,函数是不会自动执行的,需要调用它才可以
printInfo()
------------------------------------
人生苦短,我用Python
------------------------------------
函数参数
概述:
思考一个问题,如下:
现在需要定义一个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设计?下面的代码可以吗?有什么缺陷吗?
def message():
name = input('请输入你的名字')
age = input('请输入你的年龄')
print(name,age)
message()
请输入你的名字小吴
请输入你的年龄23
小吴 23
定义带有参数函数
def add2num():
a = 11
b = 22
print(a+b)
add2num()
33
def add2num(a,b):
print(a+b)
add2num(10,20)
30
调用带有参数的函数
总结
- 定义时小括号中的参数,用来接收参数用的,称为 “形参”
- 调用时小括号中的参数,用来传递给函数用的,称为 “实参”
函数的返回值
返回值:就是程序中函数完成一件事情后,最后给调用者的结果
注意:在python中return默认值为空–》None
def add2num(a,b):
return a+b
sum = add2num(10,20)
print(sum)
30
函数的参数
函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
无参数,无返回值(此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数)
无参数,有返回值(此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数)
有参数,无返回值(此类函数,能接收参数,但不可以返回数据,一般情况下,对某些变量设置数据而不需结果时,用此类函数)
有参数,有返回值(此类函数,不仅能接收参数,还可以返回某个数据,一般情况下,像数据处理并需要结果的应用,用此类函数)
总结:
函数根据有没有参数,有没有返回值可以相互组合
定义函数时,是根据实际的功能需求来设计的,所以不同开发人员编写的函数类型各不相同
函数嵌套调用
一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用
def testB():
print('---- testB start----')
print('这里是testB函数执行的代码...(省略)...')
print('---- testB end----')
def testA():
print('---- testA start----')
testB()
print('---- testA end----')
testA()
---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----
关键字参数
定义:
允许函数调用时参数的顺序与定义时不一致
def myPrint(str,age):
print(str,age)
myPrint('laowang',35)
myPrint(age=18,str='laosong')
laowang 35
laosong 18
默认参数(缺省参数)
概述:
python为了简化函数的调用,提供了默认参数机制
调用函数时,缺省参数的值如果没有传入,则被认为是默认值
def myPrint(str,sex,age = 35):
print(str,sex,age)
myPrint('laowang','male')
laowang male 35
不定长参数
概述:
有时可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。
基本语法如下:
def functionname([formal_args,] *args, **kwargs):
"函数_文档字符串"
function_suite
return [expression]
加了星号(*)的变量args会存放所有未命名的变量参数,args为元组;
而加**的变量kwargs会存放命名参数,即形如key=value的参数,
kwargs为字典。
def fun(a,b,*args,**kwargs):
print('a =',a)
print('b =',b)
print('*args =',args)
print('**kwargs =',kwargs)
#方式1
fun(1,2,3,4,5,m=6,n=7,p=8)
#方式2:
c = (3,4,5)
d = {'m': 6, 'n': 7, 'p': 8}
fun(1,2,*c,**d)
a = 1
b = 2
*args = (3, 4, 5)
**kwargs = {'p': 8, 'n': 7, 'm': 6}
a = 1
b = 2
*args = (3, 4, 5)
**kwargs = {'p': 8, 'n': 7, 'm': 6}
匿名函数
定义:
不使用def这样的语句定义函数,使用lambda来创建匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。
lambda函数的语法只包含一个语句,如下:
lambda [arg1 [,arg2,…argn]]:expression
或者:
lambda 参数1,参数2,……,参数n:expression
sum = lambda arg1,arg2:arg1+arg2
print(sum(10,20))
30
def fun(a,b,opt):
print(a)
print(b)
print(opt(a,b))
fun(1,2,lambda x,y:x+y)
1
2
3
"""
特点:
1、lambda只是一个表达式,函数体比def简单
2、lambda的主体是一个表达式,而不是代码块,仅仅只能在lambda表达式中封装简单的逻辑
3、lambda函数有自己的命名空间,且不能访问自由参数列表之外的或全局命名空间的参数
4、虽然lambda是一个表达式且看起来只能写一行,与C和C++内联函数不同。
注意:
Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数不能直接调用print,因为lambda需要一个表达式
"""
'\n特点:\n1、lambda只是一个表达式,函数体比def简单\n2、lambda的主体是一个表达式,而不是代码块,仅仅只能在lambda表达式中封装简单的逻辑\n3、lambda函数有自己的命名空间,且不能访问自由参数列表之外的或全局命名空间的参数\n4、虽然lambda是一个表达式且看起来只能写一行,与C和C++内联函数不同。\n\n\n注意:\nLambda函数能接收任何数量的参数但只能返回一个表达式的值\n匿名函数不能直接调用print,因为lambda需要一个表达式\n'
回调函数
定义:
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,
我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行
响应
def double(x):
return x*2
def quadruple(x):
return x*4
#中间函数
def getOddNumber(k,getEvenNUmber):
return 1 + getEvenNUmber(k)
def main():
k = 1
i = getOddNumber(k,double)
print(i)
i = getOddNumber(k,quadruple)
print(i)
main()
3
5
面向对象
面向对象思想
面向过程:根据业务逻辑从上到下写代码
面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程
面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程的思路是将数据与函数按照执行的逻
辑顺序组织在一起,数据与函数分开考虑。
定义:
面向对象(object-oriented ;简称: OO) 至今还没有统一的概念 我这里把它定义为: 按人们 认识客观世界的系
统思维方式,采用基于对象(实体) 的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。
面向对象编程(Object Oriented Programming-OOP) 是一种解决软件复用的设计和编程方法。 这种方法把软件
系统中相近相似的操作逻辑和操作 应用数据、状态,以类的型式描述出来,以对象实例的形式在软件系统中复用,以达
到提高软件开发效率的作用。
类和对象
面向对象编程的2个非常重要的概念:类和对象
对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,
提出了另外一个新的概念——类
类就相当于制造飞机时的图纸,用它来进行创建的飞机就相当于对象
类
具有相似内部状态和运动规律的实体的集合(或统称为抽象)。
具有相同属性和行为事物的统称
定义:
类是抽象的,在使用的时候通常会找到这个类的一个具体的存在,使用这个具体的存在。一个类可以找到多个对象
对象
概述:
某一个具体事物的存在 ,在现实世界中可以是看得见摸得着的。
可以是直接使用的
总结:
类和对象之间的关系:
就像利用玩具的模型来创建多种不同的玩具
类就是创建对象的模板
区分类和对象
奔驰汽车 类
奔驰smart 类
张三的那辆奔驰smart 对象
狗 类
大黄狗 类
李四家那只大黄狗 对象
类的设计
类(Class) 由3个部分构成
类的名称:类名
类的属性:一组数据
类的方法:允许对进行操作的方法 (行为)
<1> 举例:
1)人类设计,只关心3样东西:
事物名称(类名):人(Person)
属性:身高(height)、年龄(age)
方法(行为/功能):跑(run)、打架(fight)
2)狗类的设计
类名:狗(Dog)
属性:品种 、毛色、性别、名字、 腿儿的数量
方法(行为/功能):叫 、跑、咬人、吃、摇尾巴
定义类
# 定义类
class Car:
# 方法
def getCarInfo(self):
print('车轮子个数:%d, 颜色%s'%(self.wheelNum, self.color))
def move(self):
print("车正在移动...")
"""
说明:
定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类
类名 的命名规则按照"大驼峰"
"""
'\n说明:\n\n 定义类时有2种:新式类和经典类,上面的Car为经典类,如果是Car(object)则为新式类\n 类名 的命名规则按照"大驼峰"\n '
对象创建
python中,可以根据已经定义的类去创建出一个个对象
创建对象的格式为:
对象名 = 类名()
BMW = Car()
BMW.move()
车正在移动...
init()
想一想:
在上一小节的demo中,我们已经给BMW这个对象添加了2个属性,wheelNum(车的轮胎数量)以及color(车的颜色),试想如果再次创建一个对象的话,肯定也需要进行添加属性,显然这样做很费事,那么有没有办法能够在创建对象的时候,就顺便把车这个对象的属性给设置呢?
答:
init()方法
使用方式:
def 类名:
#初始化函数,用来完成一些默认的设定
def __init__():
pass
class Car:
def __init__(self):
self.wheelnum = 4
self.color = '蓝色'
BMW = Car()
print(BMW.color)
蓝色
封装:
- 数据封装
封装数据的主要原因是:保护隐私-私有属性
- 方法封装
封装方法的主要原因是:隔离复杂度–函数封装
继承
继承的概念
在现实生活中,继承一般指的是子女继承父辈的财产
在程序中,继承描述的是事物之间的所属关系,例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动物;
同理,波斯猫和巴厘猫都继承自猫,而沙皮狗和斑点狗都继承足够,如下如所示:
格式:
子类在继承的时候,在定义类时,小括号()中为父类的名字
父类的属性、方法,会被继承给子类
单继承
#单继承
# 定义一个父类,如下:
class Cat(object):
def __init__(self, name, color="白色"):
self.name = name
self.color = color
def run(self):
print("%s--在跑"%self.name)
# 定义一个子类,继承Cat类如下:
class Bosi(Cat):
def setNewName(self, newName):
self.name = newName
def eat(self):
print("%s--在吃"%self.name)
bs = Bosi("印度猫")
print('bs的名字为:%s'%bs.name)
print('bs的颜色为:%s'%bs.color)
bs.eat()
bs.setNewName('波斯')
bs.run()
bs的名字为:印度猫
bs的颜色为:白色
印度猫--在吃
波斯--在跑
#注意点:设置私有属性
class Animal(object):
age = 13
def __init__(self, name='动物', color='白色'):
self.__name = name
self.color = color
def __test(self):
print(self.__name)
print(self.color)
def test(self):
print(self.__name)
print(self.color)
class Dog(Animal):
def dogTest1(self):
#print(self.__name) #不能访问到父类的私有属性
print(self.color)
def dogTest2(self):
#self.__test() #不能访问父类中的私有方法
self.test()
A = Animal()
#print(A.__name) #程序出现异常,不能访问私有属性
print(A.color)
#A.__test() #程序出现异常,不能访问私有方法
A.test()
print("------分割线-----")
D = Dog(name = "小花狗", color = "黄色")
D.dogTest1()
D.dogTest2()
"""
总结:私有的属性,,不能通过对象直接访问,但是可以通过方法访问
私有的方法 不能通过对象直接访问
私有的属性、方法,不会被子类继承,也不能被访问
一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用
"""
白色
动物
白色
------分割线-----
黄色
小花狗
黄色
'\n总结:私有的属性,,不能通过对象直接访问,但是可以通过方法访问\n 私有的方法 不能通过对象直接访问\n 私有的属性、方法,不会被子类继承,也不能被访问 \n 一般情况下,私有的属性、方法都是不对外公布的,往往用来做内部的事情,起到安全的作用\n'
多继承
"""
理解:
骡子是马和驴的杂交品种
所谓多继承,即子类有多个父类,并且具有它们的特征
"""
#Python中多继承的格式如下:
# 定义一个父类
class A:
def printA(self):
print('----A----')
# 定义一个父类
class B:
def printB(self):
print('----B----')
# 定义一个子类,继承自A、B
class C(A,B):
@classmethod
@staticmethod
def printC(self):
print('----C----')
obj_C = C()
obj_C.printA()
obj_C.printB()
----A----
----B----
多态
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态
Python伪代码实现Java或C#的多态
一个父类有多个子类
类属性和实例属性
类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,
在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,
在类外可以通过类对象和实例对象访问
class People(object):
name = 'Tom'
__age = 12
p = People()
print(p.name)
print(People.name)
# print(p.__age)
# print(People.__age)
Tom
Tom
class People(object):
address = 'beijing'
def __init__(self):
self.name = 'Tom'
self.age = 12
p = People()
print(p.address)
print(p.name)
print(p.age)
print(People.address)
print(People.name)
# print(p.age)
beijing
Tom
12
beijing
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-22-e63e70d527d3> in <module>
11
12 print(People.address)
---> 13 print(People.name)
14 # print(p.age)
AttributeError: type object 'People' has no attribute 'name'
模块
目前代码比较少,写在一个文件中还体现不出什么缺点,但是随着代码量越来越多,代码就越来越难以维护。
为了解决难以维护的问题,我们把很多相似功能的函数分组,分别放到不同的文件中去。
这样每个文件所包含的内容相对较少,而且对于每一个文件的大致功能可用用文件名来体现。
很多编程语言都是这么来组织代码结构。一个.py文件就是一个模块
在Python中有一个概念叫做模块(module),这个和C语言中的头文件以及Java中的包很类似,
比如在Python中要调用sin函数,必须用import关键字引入math这个模块,下面就来了解一下Python中的模块。
说的通俗点:模块就好比是工具包,要想使用这个工具包中的工具(就好比函数),就需要导入这个模块
优点:
- 提高代码的可维护性
- 提高了代码的复用度,当一个模块完毕,可以被多个地方引用
- 引用其他的模块(内置模块和三方模块和自定义模块)
- 避免函数名和变量名的冲突
#常见的几种格式
import numpy
from numpy import abs
from numpy import *
from random import randrange as rr
文件操作
概述:
常见的txt/avi/html/zip/word等都称之为文件
文件作用:
存储数据
文件打开
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新文件
open(文件名,访问模式)
示例如下:
f = open('test.txt', 'w')
说明:
访问模式 说明
r 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
w 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到
已有内容之后。如果该文件不存在,创建新文件进行写入。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,
新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
r+ 打开一个文件用于读写。文件指针将会放在文件的开头。
w+ 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。
如果该文件不存在,创建新文件用于读写。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。
如果该文件不存在,创建新文件用于读写。
文件关闭
使用函数:
close( )
#示例如下:
# 新建一个文件,文件名为:test.txt
f = open('test.txt', 'w')
# 关闭这个文件
f.close()
文件读写
#写
#使用write()可以完成向文件写入数据
f = open('test.txt', 'w')
f.write('hello world, i am here!')
f.close()
"""
注意:
如果文件不存在那么创建,如果存在那么就先清空,然后写入数据
"""
#读取内容
#1.read()
#2.readlines()
#3.readline()
f = open('test.txt', 'r')
content = f.read(5)
print(content)
f.close()
文件定位读写
什么是定位?
通俗的讲就是找到一个合适的位置
在软件开发中文件的读写定为该如何实现?
获取当前读写的位置
在读写文件的过程中,如果想知道当前的位置,
可以使用tell()来获取,这里是光标开始的位置
定位到某个位置
如果在读写文件的过程中,需要从另外一个位置进行操作的话,可以使用seek()
文件重命名
os模块中的rename()可以完成对文件的重命名操作
格式:
rename(需要修改的文件名, 新的文件名)
import os
os.rename('test.txt','haht.txt')
文件删除
概述:os模块中的remove()可以完成对文件的删除操作
格式:
remove(待删除的文件名)
文件夹操作
创建文件夹
使用os模块中的mkdir()函数
格式:
mkdir(str)
获取当前目录
使用os模块中的getcwd()函数
格式:
getcwd()
获取目录列表
使用os模块中的listdir()函数
格式:
listdir()
删除文件夹
使用os模块中的rmdir()函数
rmdir(str)—>str:表示需要删除的文件夹名称
异常
异常的处理
当出现异常情况时改如何处理?
捕获异常
捕获异常的基本格式:
try…except…
else
咱们应该对else并不陌生,在if中,它的作用是当条件不满足时执行的实行;
同样在try…except…中也是如此,即如果没有捕获到异常,那么就执行else中的事情
try…finally…
try…finally…语句用来表达这样的情况:
在程序中,如果一个段代码必须要执行,即无论异常是否产生都要执行,那么此时就需要使用finally。
比如文件关闭,释放锁,把数据库连接返还给连接池等
自定义异常
你可以用raise语句来引发一个异常
class ShortInputException(Exception):
def __init__(self,length,atleast):
self.length = length
self.atleast = atleast
def main():
try:
s = input('请输入--->')
if len(s) < 3:
raise ShortInputException(len(s),3)
except ShortInputException as result:
print(result.length,result.atleast)
else:
print('没有异常发生')
main()
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。
而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,
那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,
称为生成器:generator。
创建生成器
迭代器
迭代:
访问集合元素的一种方式。
迭代器:
是一个可以记住遍历的位置的对象。
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。
迭代器的特点:
迭代器只能往前不会后退。
迭代对象
以直接作用于 for 循环的数据类型有以下几种:
一类是集合数据类型,如 list 、 tuple 、 dict 、 set 、 str 等;
一类是 generator ,包括生成器和带 yield 的generator function。
这些可以直接作用于 for 循环的对象统称为可迭代对象: Iterable 。
from collections import Iterable
a = isinstance([],Iterable)
b = isinstance({},Iterable)
c = isinstance('abc',Iterable)
d = isinstance(100,Iterable)
e = isinstance((x for x in range(10)),Iterable)
print(a)
print(b)
print(c)
print(d)
print(e)
from collections import Iterator
a = isinstance(iter([]),Iterator)
b = isinstance({},Iterator)
c = isinstance('abc',Iterator)
d = isinstance(100,Iterator)
e = isinstance((x for x in range(10)),Iterator)
print(a)
print(b)
print(c)
print(d)
print(e)
迭代器使用
iter()函数
"""
1.凡是可作用于 for 循环的对象都是 Iterable 类型;
2.凡是可作用于 next() 函数的对象都是 Iterator 类型
3.集合数据类型如 list 、 dict 、 str 等是 Iterable 但不是 Iterator ,
不过可以通过 iter() 函数获得一个 Iterator 对象。
"""
装饰器
装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题,但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python, 看了下面的文章,保证你学会装饰器。
#首先要先搞明白下面的代码:
#第一波
def foo():
print('foo')
foo #表示是函数
foo() #表示执行foo函数
#第二波
def foo():
print('foo')
foo = lambda x: x + 1
foo(1) # 执行下面的lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数
def func1():
print("haha")
def outer(func):
def inner():
print("*******************")
func()
return inner
#f是函数func1的加强版本
f = outer(func1)
f()
#如何理解装饰器
#需求:
#一个企业有N个业务部门,1个基础平台部门,基础平台负责提供底层的功能,
############### 基础平台提供的功能如下 ###############
def f1():
print('f1')
def f2():
print('f2')
def f3():
print('f3')
def f4():
print('f4')
############### 业务部门A 调用基础平台提供的功能 ###############
f1()
f2()
f3()
f4()
############### 业务部门B 调用基础平台提供的功能 ###############
f1()
f2()
f3()
f4()
#第一版
############### 基础平台提供的功能如下 ###############
def f1():
# 验证1
# 验证2
# 验证3
print('f1')
def f2():
# 验证1
# 验证2
# 验证3
print('f2')
def f3():
# 验证1
# 验证2
# 验证3
print('f3')
def f4():
# 验证1
# 验证2
# 验证3
print('f4')
############### 业务部门不变 ###############
### 业务部门A 调用基础平台提供的功能###
f1()
f2()
f3()
f4()
### 业务部门B 调用基础平台提供的功能 ###
f1()
f2()
f3()
f4()
#第二版
############### 基础平台提供的功能如下 ###############
def check_login():
# 验证1
# 验证2
# 验证3
pass
def f1():
check_login()
print('f1')
def f2():
check_login()
print('f2')
def f3():
check_login()
print('f3')
def f4():
check_login()
print('f4')
#第三版
def w1(func):
def inner():
# 验证1
# 验证2
# 验证3
func()
return inner
@w1
def f1():
print('f1')
@w1
def f2():
print('f2')
@w1
def f3():
print('f3')
@w1
def f4():
print('f4')
#装饰器的基本使用
#定义函数:完成包裹数据
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
#定义函数:完成包裹数据
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
def test1():
return "hello world-1"
@makeItalic
def test2():
return "hello world-2"
@makeBold
@makeItalic
def test3():
return "hello world-3"
print(test1())
print(test2())
print(test3())