1. 函数基础

1.1 参数和返回值

1.1.1 参数

位置参数、关键字参数
def my_func1(x, y, z):
print(x+y+z, "计算结束") my_func1(1, 2, 3) # 位置参数写法
my_func1(x=4, y=5, z=6) # 关键字参数写法
my_func1(7, 8,z=9) # 位置参数要写在关键字参数前面
默认参数
def my_func2(a, b=2):       # 默认参数,参数b的值可以不传,默认为2,如果传了值,则b的值会覆盖默认值
print("计算结果为:", a+b) my_func2(2)
my_func2(1, 9)
非定长参数
def my_func3(*args, **kwargs):   # 参数中 *args表示列表或元组, **kwargs表示字典    args保存为元组的形式
print(args[0])
print(kwargs["name"]) my_func3(1, 2, 3, name="hgzero", age=21, addr="China")
my_func3(*[9, 8, 7], **{"name": "wuzhihao", "age": 22, "addr": "America"})

1.1.2 返回值

  • 函数若没有使用return定义返回值,则返回None。
  • 若返回值只有一个,则将返回对象直接返回。
  • 若返回值有多个,则以元组的形式将返回值返回。
  • def func1():
    print("hello world") def func2():
    return "wuzhihao" def func3():
    return 1, 2, 3, ["hgzero", "hg"] print(func1()) # 若无返回值,则返回None
    print(func2()) # 若返回值只有一个,则将返回对象返回
    print(func3()) # 若返回值有多个,则以元组的形式将返回值返回

1.2 局部变量&全局变量

  • 如果函数中变量不定义global关键字,优先读取局部变量,当读取全局变量时,无法重新给其赋值,若函数中变量加了global关键字,则变量表示的就是全局的那个变量,或者直接创建一个全局变量
  • 对于可变类型(列表、字典等),在函数内部可以对其进行内部操作(增、删、改)
  • 最好将全局变量大写 , 局部变量小写
  • name = "hgzero"                # 定义一个全局的name
    my_name = ["hgzero", "wuzhihao", "hg", "wu"] def func1():
    global name # 指明这里的name就是全局的那个name
    name = "wuzhihao"
    print(name) def func2():
    global age # 直接定义一个全局的age
    age = 22 def func3():
    my_name.append("hello") # 在函数内部对可变类型的操作会影响到全局
    print(my_name)
    my_name.pop(2) func1()
    func2()
    func3()
    print(name)
    print(age)
    print(my_name) like = "AAA"
    def my_func1():
    like = "BBB"
    def my_func2():
    nonlocal like # nonlocal 关键字代指它的上一级变量
    like = "CCC"
    my_func2()
    print(like) print(like)
    my_func1()
    print(like)

1.3 函数的递归

1.3.1 递归说明

递归一定要设置一个截止条件,且下一次递归的规模要比上一次有所减少。

python在递归的深度上做了限制(1000),且python的递归效率低且没什么用。

1.3.2 递归的尾部优化

递归的尾部优化

在最后一步进入递归可以不用保存前一步的状态(调用栈)------> 理论、

为什么要实现尾部递归优化

因为函数调用是通过栈的形式实现的,每当进入一个函数调用,那么栈就会增加一层栈帧,每当函数返回,栈就会减少一层栈帧(为了保留上一层的状态等信息)。由于栈的大小不是无限的,所以,当递归的层数过多时,会导致栈溢出。

尾部递归优化的实现方法:(理论上)

只是理论上的方法,因为python解释器没有对此进行优化。实际上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归也ok。

尾递归是指,在函数返回的时候,调用自己本身,并且,return语句不能包含表达式,这样,编译器或者解释器就可以吧尾递归做优化,使得递归本身无论调用了多少次,都只占用一个栈帧,这样就不会出现栈溢出的情况了。

1.3.3 递归使用示例

# 递归计算1+2+3···+99+100的值
def func1(num):
if num == 1:
return num
res = num + func1(num - 1)
return res
sum = func1(100)
print(sum) # 递归计算 1+(1*2)*(1*2*3)+(1*2*3*4)+(1*2*3*4*5)+···+(1*2*3*4···*8*9*10) 的值
def func2(num):
mal = 1
if num == 1:
return num
for i in range(1, num+1):
mal = i * mal
res = mal + func2(num-1)
return res
sum1 = func2(10)
print(sum1)

1.4 函数的作用域

name = "AAA"
def func1():
name = "BBB"
def func2():
name = "CCC"
def func3():
# name = "DDD"
print(name)
return func3
return func2 f2 = func1()
f3 = f2()
f3() # 以上的调用方式等价于:
func1()()() name = "hgzero"
def outer(func):
name = "alex"
func() # 相当于执行了show函数,但show函数中调用的name变量还是调用了全局的name变量
def show():
print(name) outer(show) # 这里讲show函数的地址传递给了outer , 但并不代表outer函数和show函数之间有从属关系

1.5 匿名函数

lambda表达式

# 用普通函数的方式实现两个数字相加
def sum(x, y):
return x+y
s = sum(1,2)
print(s) # 用匿名函数的方式实现两个数字相加
lam = lambda x, y: x + y # 冒号前面的为参数,冒号后面的为对参数的处理以及返回值(返回的是匿名函数的内存地址)
sum = lam(2, 3)
print(sum)

2. 高阶函数

2.1 说明

函数式编程:不用变量保存状态,不修改变量,若需要修改变量,则直接在return中返回并修改。

高阶函数

  1. 函数接受的参数是函数名
  2. 函数返回值中包含函数

2.2 三个常用的高阶函数

2.2.1 map()

num_li = [1, 2, 3, 4, 5]
add_one = map(lambda x: x+1, num_li) # map函数的第一个参数是处理逻辑(可以为普通函数或者匿名函数),第二个参数是可迭代对象
# map函数将后面的可迭代对象迭代作为参数传递给前面的函数作出对应的处理,返回值保存为一个可迭代对象
print(add_one) # map函数返回的是一个可迭代对象 # for i in add_one:
# print(i) li = list(add_one) # 可用list() 将可迭代对象转换为一个列表
print(li)

2.2.2 filter()

name_list = ["xiaoming_hg", "xiaohong_hg", "xiaohua_hg", "xiaoqiang"]

fi = filter(lambda x: x.endswith("hg"), name_list)   # filter()函数与reduce()函数类似,分别传入函数和可迭代对象
# filter 的返回值为符合过滤条件的对象
print(fi)
print(list(fi))
# for i in fi:
# print(i)

2.2.3 reduce()

# 对于后面可迭代对象中的值 ,将第一个值和第二个值进行函数操作后保存作为第一个值,再将后面的值作为第二个值,反复循环累积,得到一个终值
# reduce()函数要从fuctools包中引入
from functools import reduce
num_list = [1, 2, 3, 4, 5]
mal = reduce(lambda x, y: x+y, num_list, 100) # 第三个参数为初值
print(mal)

3. python内置函数

3.1 sum(),hash(),bytes(),dir(),bin()等

print(abs(-2))     # abs()函数返回绝对值

print(round(3.5))   # 对数字进行四舍五入

print(bool(9))    # 判断布尔值  (空、None、零的布尔值为False,其余全都为True)

print(sum([1, 2, 3, 4, 5]))    # sum()函数将参数的可迭代对象相加(必须为数字)

print(hash("wuzhihao"))   # 可hash的数据类型即是不可变数据类型

print(divmod(10, 3))   # 将第一个参数和第二个参数相除,返回一个元组,元组中第一个值为商,第二个值为余数,如这里返回(3,1)

print(bytes("你好", encoding="utf-8").decode("utf-8"))   # 编码和解码

print(dir(list))    # 打印相应的对象下面的所有的方法

print(pow(2, 3))     # pow()函数接受两个参数时表示次方,即2的3次方
print(pow(2, 3, 3)) # pow()函数接受三个参数时表示先次方,后取余,即2的3次方后,将得到的结果取余 print(all(["hello", ""])) # all()函数当它里面的可迭代对象的值全部为True时返回True,或为空时也返回True ,否则返回False
print(any(["", 1, 0])) # any()函数当它里面的值有一个为True时,则为True print(chr(97)) # 基于ASCII码表进行转换(参数为数字)
print(ord("a")) # 打印出字符在ASCII码表中对应的数字 print(globals()) # globals()函数以字典的方式返回当前位置的全部全局变量
print(locals()) # locals()函数以字典的方式返回跟当前位置统一等级的局部变量 print(bin(3)) # 将十进制转换为二进制,以 0b 开头
print(oct(10)) # 将十进制转换为八进制,以0o开头
print(hex(10)) # 将十进制转换为十六进制,以 0x 开头

3.2 enumerate(),eval(),isinstance(),zip(),max(),sorted()

num = [1, 2, 3]
for x, y in enumerate(num): # enumerate()函数接受一个可迭代对象,并遍历返回 每个元素的索引和它对应的值
print(x, y) print("python中的eval()函数:")
# eval()函数的作用:1.将字符串中的数据结构给提取出来 2.将字符串中的表达式进行计算
# str()函数将其中的参数转换为字符串形式
print(str([12, 2, 34]))
expression1 = "[1, 2, 3, 4, 5]"
expression2 = "1+2+3+(4*5)+9"
ev1 = eval(expression1)
print(type(ev1))
ev2 = eval(expression2)
print(ev2) # isinstance()函数判断第一个参数是不是第二个参数指定的数据类型
print(isinstance(5, int))
print(isinstance("hgzero", str))
print(isinstance([1,2,3], list)) # zip()函数接受两个序列类型(包括 列表、元组、字符串)的参数,并将二者一一对应成一个个元组
# 若两组参数中多了值或者少了值,以少的一方为准,多余的值舍弃
first = {"one": 1, "two": 2, "three": 3, "four": 4, "five": 5}
print(list(zip("hello", [1,2,3,4,5])))
print(list(zip(first.keys(), first.values()))) # python中的max()函数
# max()函数中传入的必须为一个可迭代类型,且迭代对象之间的数据类型必须相同
the_name = ["a1", "a2", "a3", "b4"]
the_dict = {"name1": "hgzero", "name2": "wuzhihao", "age": 21}
the_tuple = [(1, "name"), (2, "age"), (3, "gender"), (4, "addr")]
print(max(the_name))
print(max(the_dict.keys()))
print(max(the_tuple))
# 利用zip和max函数找到value最大的那个键值对:
my_dict = {"name": 1, "age": 2, "gender": 3, "addr": 4}
print(max(zip(my_dict.values(), my_dict.keys())))
name_dict = [
{"name": "hgzero", "age": 25},
{"name": "hg", "age": 14},
{"name": "zero", "age": 23},
{"name": "wzh", "age": 21},
{"name": "zhihao", "age": 26},
]
print(max(name_dict, key=lambda dict: dict["age"])) # max()函数还接受第二个参数key,为每个迭代对象中的要比较的选项 my_name = "welcome"
s = slice(1, 4, 2) # 指定切片的范围及步长 1<=slice<4 步长为2
print(my_name[s])
print(s.start) # 打印起始索引
print(s.stop) # 打印终止索引
print(s.step) # 打印步长 # sorted()函数实现排序功能
the_my_dict = [
{"name": "hgzero", "age": 25},
{"name": "hg", "age": 14},
{"name": "zero", "age": 23},
{"name": "wzh", "age": 21},
{"name": "zhihao", "age": 26},
]
print(sorted(the_my_dict, key=lambda dict: dict["age"])) # sorted()函数也有一个key的参数,为每个迭代对象要比较的内容 # import my_test # import不能以字符串类型导入模块
# import 的导入原理为: import ------> system ------> __import__
pkg = __import__("hello") # __import__ 可以以字符串类型导入模块

4. 函数的高级用法

4.1 迭代器

4.1.1 迭代器(iterator)协议

  • 对象必须提供一个__next__()方法,执行方法要么返回迭代中的下一项,要么引起一个Stopiteration异常,以终止迭代(只能往后走,不能往前退)
  • 可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义了一个__iter__()方法)
  • 协议是一种规范,可迭代对象实现了迭代器协议,python的内部格局(如for循环、sum、min、max函数),使用迭代器协议访问对象

4.1.2 for循环的工作机制

  • 先通过__iter__()方法将可迭代对象转换为迭代器,再调用迭代器中的__next__()方法遍历,最后再抓取结束时的异常
  • print("解析for循环的工作机制:")
    num = [1, 2, 3, 4, 5]
    for i in num: # 工作机制: num.__iter__() ------> num.__next__()
    print(i)

4.1.3 可迭代对象与迭代器

可迭代对象与迭代器之间的关系:

  • 可迭代对象包含迭代器
  • 如果一个对象拥有__iter__方法,其就是可迭代对象(可以被for循环迭代);如果一个对象拥有next方法,其是迭代器。
  • 定义可迭代对象,必须事先__iter__方法;定义迭代器,必须实现__iter__和next方法。

isinstance()判断对象是否为Iterable对象:

from collections import Iterable
print(isinstance([], Iterable))

4.1.4 迭代器协议的使用示例

print("使用while循环遍历一个列表:")
index = 0
while index < len(num):
print(num[index])
index += 1 print("利用迭代器协议遍历一个列表:")
iter = num.__iter__()
print(iter.__next__())
print(iter.__next__())
print(iter.__next__()) print("解析文件操作中对于文件内容的遍历:")
f = open("test.txt", "r")
f_iter = f.__iter__() # 这里先将整个文件转换为一个迭代器,之后对迭代器调用__next__()方法,只在有需要的时候才加载文件一行内容
# 当取出一行内容时,因为没有赋值给任何变量,所以占用的内存会被python的自动回收机制回收,所以这种遍历文件的方式只会动态的占用一小块内存
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
print(f_iter.__next__(), end="")
f.close() print("next()方法:") # next()方法--->调用__next__()方法
the_num = [1, 2, 3]
the_iter = the_num.__iter__() # 也可以直接使用iter(the_num)方法
print(next(the_iter)) # next(the_iter) -----> 调用 the_iter.__next__()

4.2 生成器

4.2.1 生成器概述(generator)

  • 生成器(generator)就是可迭代对象(它在内部实现了迭代器协议)
  • 生成器在python中的两种表达形式:
    • 生成器表达式
    • 生成器函数
  • 触发生成器的方式:
    • 通过调用__next__()方法,相当于send(None)
    • 通过调用send()方法

4.2.2 生成器表达式

print("生成器表达式:")
list2 = ("数字%d" % i for i in range(10)) # 将列表解析表达式外围的中括号换成小括号就变成了一个生成器
# 生成器表达式更节省内存
print(list2)
print(list2.__next__())
print(list2.__next__())
print(list2.__next__())
print(list2.__next__()) # 可以将生成器表达式传递给sum()等函数,以节省占用内存的大小
print(sum(i for i in range(100000)))
# 这里的sum函数里面的生成器表达式不需要加括号
# 如果直接在sum中传入一个非常大的列表,会造成占用太多内存而导致机器卡死,而用生成器的方式传入则会动态的占用很小的一片内存

4.2.3 生成器函数

  • 只要函数中包含yield关键字,则此函数就是一个生成器函数
  • 每调用一次 __next__(),yield后面的值就会被返回一次,且保留此次的状态,下一次调用从此位置开始。

生成器函数:

def func():
print("现在开始执行生成器函数:")
print("First----->")
yield "第一步"
print("Second----->")
yield "第二步"
print("Third")
yield "第三步"
print("End")
yield "生成器函数调用完毕" f = func()
print(f.__next__()) # __next__()函数调用接受到的返回值就是yield后面的值
print(f.__next__())
print(f.__next__())
print(f.__next__())

用yield方式的生成器实现字典中文件的内容查找:

def get_num():
f = open("population.txt", "r", encoding="utf-8") # 这个文件中的每一行都是一个字典
for i in f:
yield i # 这里返回的 i 为字符串类型 population = eval(get_num().__next__()) # 这里通过eval()函数重新恢复了文件中数据的数据类型,恢复成了字典
print("%s的人口数为%s" % (population["city"], population["population"]))
# 注意:生成器只能遍历一次 # 用生成器表达式的方式实现字典中文件数字的求和
f = open("population.txt", "r", encoding="utf-8")
p = sum(eval(i)["population"] for i in f)
print(p)

send()方法的使用:

def my_func():
print("First")
send1 = yield 1 # yield后面的值是next方法调用的返回值,而前面的值是yield接收值之后赋值的变量
print("Second")
print("此次send传送的值为:", send1)
send2 = yield 2
print("Third")
print("此次send传送的值为:", send2)
yield 3
print("End") m = my_func() # 这里并不会执行这个函数,因为只要函数内部定义了yield关键字,函数就变成了生成器,只有通过next方法调用
print(m.__next__()) print(m.send(None) ) # 这里的send(None),就相当于__next__()方法,触发一次生成器
# send()函数将值传递给当前停留位置的yield,之后这个yield会将值传递给前面的变量
print(m.send("这是第二次send"))

额外:

def func3():
for i in range(10):
yield i t = func3()
# for i in t: # 因为for循环的工作机制就是使用迭代器协议调用next方法,所以会触发生成器函数
# print(i) li1 = (i for i in t) # 这里li1会得到一个生成器的地址
li2 = (i for i in li1) # 这里li1的值已经被取完了
print(type(li1))
print(list(li1)) # 这里的list函数中会用for循环机制取值,从而触发生成器,现在这个位置li1中的值已经被取完了
print(list(li2)) # 因li1中的值已经被取完了,所以li2现在已经取不到值了

4.3 三元表达式&列表解析

4.3.1 三元表达式

name = "hgzero"
ret = "me" if name == "hgzero" else "other" # 若name等于hgzero,则返回me,否则返回other
print(ret)

4.3.2 列表解析(列表推导)

list1 = [i for i in range(10)]            # 列表解析会将生成的列表直接放于内存中,会占用较大的内存
print(list1)
list2 = ["数字%d" % i for i in range(10)] # for循环处理后将i依次往前面传递
print(list2)

4.3.3 三元表达式和列表解析的使用示例

print("三元表达式和列表解析结合")
list3 = ["数字%d" % i for i in range(10) if i > 5] # 这里不能使用else,因为已经构成了三元表达式了
print(list3) print("生成器表达式:")
list2 = ("数字%d" % i for i in range(10)) # 将列表解析表达式外围的中括号换成小括号就变成了一个生成器
# 生成器表达式更节省内存
print(list2)
print(list2.__next__())
print(list2.__next__())
print(list2.__next__())
print(list2.__next__())

4.4 生产者消费者模型

import time

# def producer():
# ret = []
# for i in range(100):
# time.sleep(0.1)
# ret.append("包子%s" % i)
# return ret
#
# def consumer(ret):
# for index, baozi in enumerate(ret):
# time.sleep(0.1)
# print("第%d个人来了,吃了第%s个包子" % (index, baozi))
#
# p = producer()
# consumer(p) def producer():
c1 = consumer("hgzero")
c2 = consumer("wuzhihao")
c1.__next__()
c2.__next__()
for i in range(10):
time.sleep(1)
print("现在包子 %s 已经做好了!" % i)
c1.send("第%s个包子" % i)
c2.send("第%s个包子" % i) def consumer(name):
print("吃包子开始!")
while True:
baozi = yield
time.sleep(1)
print("我是 %s , 现在开始吃 %s 包子" % (name, baozi)) producer()

4.5 闭包

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

一般情况下,如果一个函数结束,函数的内部所有的东西都会被释放掉,局部变量都会消失。

但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

其实闭包中外部函数的返回值定义成内部函数的地址,是为了防止内部函数被垃圾回收机制回收。

def father(name):
print("I am father")
def son():
print("I am son")
def grandson():
print("I am grandson, and my name is %s " % name)
return grandson
return son father("hgzero") # 这里调用father函数,返回的是son函数的地址,但是不会执行son函数

4.6 解压序列

# 解压序列:
a, *b, c = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 这里的 * 号表示所有的意思
print(a)
print(b)
print(c) # 交换两个变量的值:
a = 1
b = 2
print("通过中间变量的形式交换:")
c = a
a = b
b = c
print(a, b) print("另外两种不引入额外变量实现交换的方式:")
f1 = 1
f2 = 2
f1, f2 = f2, f1
print(f1, f2) n1 = 1
n2 = 2
n1 = n1 + n2
n2 = n1 - n2
n1 = n1 - n2
print(n1, n2)

5. 装饰器

5.1 装饰器基础

5.1.1 装饰器概述

  • 装饰器:

    • 本质上就是函数,功能是为其他函数添加附加功能
  • 原则:
    • 不修改被修饰函数的源代码
    • 不修改被修饰函数的调用方法
  • 装饰器 = 高阶函数 + 函数嵌套 + 闭包

5.1.2 装饰器的实现方式

用高阶函数的方式实现装饰器的功能:不合格,因为这种方式会使工作函数调用了两次

import time
def work_func():
time.sleep(1)
print("这里是work_func函数") def dec_func(func):
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time-start_time))
return func work_func = dec_func(work_func) # 这里在赋值之前就已经执行了dec_func(work_func)函数
work_func() # 这里又执行了一便work_func函数

用高阶函数 + 函数嵌套 + 闭包的方式实现装饰器:

import time
def work_func2():
time.sleep(1)
print("这里是work_func2函数") def dec_func2(func):
def wapper():
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return wapper work_func2 = dec_func2(work_func2) # 这里执行dec_func2函数时遭遇一个闭包,得到的是闭包wrapper函数的内存地址(并没有执行它)
work_func2() # 这里执行上面得到的闭包函数,即执行wapper()函数

用“语法糖”的形式实现装饰器:

import time
def dec_func3(func):
def wapper():
start_time = time.time()
func()
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return wapper @dec_func3 # 用“语法糖”的形式实现装饰器 ,相当于 work_func3 = dec_func3(work_func3)
def work_func3():
time.sleep(1)
print("这里是work_func3函数") work_func3()# 装饰器改进 , 添加返回值和多参数功能
def dec_func4(func):
def wapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs) # func()函数的返回值就是work_func函数中的返回值,用res接收之后,再返回出去
finish_time = time.time()
print("这个函数运行的时间是%d" % (finish_time - start_time))
return res
return wapper @dec_func4 # work_func4 = dec_func3(work_func3) 这时执行work_func4函数就是执行wapper函数,因为dec_func3函数返回的就是wapper的地址
def work_func4(name, age):
time.sleep(1)
print("这里是work_func4函数")
print("Name:【%s】,Age:【%d】" % (name, age))
return 12345 # 这时,work_func函数的返回值就是dec_func函数的闭包---> wapper函数的返回值 work_func4("hgzero", 21)

5.2 带认证功能的装饰器

import time

user = [
{"username": "hgzero", "passwd": ""},
{"username": "wzh", "passwd": ""},
{"username": "hg", "passwd": ""},
{"username": "zero", "passwd": ""},
{"username": "abc", "passwd": ""}
] login_dict = {"username": None, "login": False} # 这里用这个字典模拟session的功能 def login_func(func):
def wrapper(*args, **kwargs):
if login_dict["username"] and login_dict["login"]:
ret = func(*args, **kwargs)
return ret
while True:
username = input("请输入用户名:").strip()
passwd = input("请输入密码:").strip()
for dict in user:
if dict["username"] == username and dict["passwd"] == passwd:
login_dict["username"] = username
login_dict["login"] = True
ret = func(*args, **kwargs)
return ret
else:
print("用户名或密码错误!")
time.sleep(1)
print("请重新输入----->")
return wrapper @login_func
def index():
print("欢迎来到zero的网站主页!") @login_func
def home(name):
print("【%s】,欢迎来到个人中心!" % (name)) @login_func
def shopping(name):
print("【%s】,现在您的购物车中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index()
home("python工程师")
shopping("python工程师")

5.3 带参数的装饰器

import time

user = [
{"username": "hgzero", "passwd": ""},
{"username": "wzh", "passwd": ""},
{"username": "hg", "passwd": ""},
{"username": "zero", "passwd": ""},
{"username": "abc", "passwd": ""}
] login_dict = {"username": None, "login": False} # 这里用这个字典模拟session的功能 def func(db_type):
def login_func(func):
print("这个数据库的类型是:", db_type)
def wrapper(*args, **kwargs):
if login_dict["username"] and login_dict["login"]:
ret = func(*args, **kwargs)
return ret
while True:
username = input("请输入用户名:").strip()
passwd = input("请输入密码:").strip()
for dict in user:
if dict["username"] == username and dict["passwd"] == passwd:
login_dict["username"] = username
login_dict["login"] = True
ret = func(*args, **kwargs)
return ret
else:
print("用户名或密码错误!")
time.sleep(1)
print("请重新输入----->")
return wrapper
return login_func @func("MySQL") # 这里先执行func("MySQL") ---> index = login_func(index)
# 这里因为后面加了括号,所以是执行了func函数,执行了func函数所得到的返回值就是login_func函数的地址
# func()函数执行得到的地址就是login_func,所以这里就等价于是 @login_func,同时也将参数传进去了,巧妙的运用了闭包的原理
def index():
print("欢迎来到zero的网站主页!") @func("Mongodb")
def home(name):
print("【%s】,欢迎来到个人中心!" % (name)) @func("Redis")
def shopping(name):
print("【%s】,现在您的购物车中有 %s , %s , %s " % (name, "牛奶", "香蕉", "芒果")) index()
home("python工程师")
shopping("python工程师")

6. 函数使用练习

6.1 基础练习

1. 写一个函数,根据范围获取其中3和7整除的所有数的和,并返回调用者;符合条件的数字个数以及符合条件的数字的总和

print("递归的方法实现:")
def func(start, end, number = 0, n = 0): # 这里定义的关键字参数在下一次调用的时候保证不会使变量清零
if start % 3 == 0 and start % 7 == 0:
number += start # 这里的number计算所有符合条件的数字的总和
n += 1 # 这里的n计算所有符合条件的数字的各数
print("找到一个值,它是 %d" % start)
if start > end:
return n, number
ret = func(start+1, end, number, n)
return ret f = func(0, 996) # 这里的范围已经为python的最大递归深度
print("所有符合条件的数的个数为 %d ,所有符合条件的数的和为 %d" % (f[0], f[1])) print("用迭代的方法实现:")
def func2(start, end):
number = 0
n = 0
for i in range(start, end+1):
if i % 3 == 0 and i % 7 == 0:
print("找到一个值,它是 %d" % i)
number += i
n += 1
print("所有符合条件的数的个数为 %d ,所有符合条件的数的和为 %d" % (n, number)) f2 = func2(0, 996)

2. 定义一个函数统计一个字符串中大写字母、小写字母、数字的个数,并以字典的形式返回给调用者

def the_count(s, upper=0, lower=0, number=0):
for i in s:
if i.isupper(): # 判断是否是大写字母
upper += 1
if i.islower(): # 判断是否是小写字母
lower += 1
if i.isdigit(): # 判断是否是数字
number += 1
dic = {"upper": upper, "lower": lower, "number": number}
return dic name = "hgzeroWuzhihao123"
ret = the_count(name)
print(ret)

6.2 基础进阶

1. 对文件内容的增删改查

import os

def file_hander(string, type, res=None):
if type == "search":
with open("haproxy.conf", "r", encoding="utf-8") as f:
back_data = [] # 设置一个接受列表
flag = False # 设置一个标识,以确定是否查找到要找的内容
for f_line in f:
if f_line.strip() == string: # 找到了想要匹配的内容
flag = True
continue
if flag and f_line.startswith("backend"): # 判断要查找的内容是否已经读取完
# flag = False
break
if flag: # 将匹配到的内容添加到一个列表中
print(f_line, end="")
back_data.append(f_line)
return back_data elif type == "mod":
with open("haproxy.conf", "r", encoding="utf-8") as f_old, open("haproxy.conf_new", "w", encoding="utf-8") as f_new:
flag = False # 判断是否找到指定的行的标识
has_write = False # 判断文件是否已经写入的标识
for line_old in f_old:
if line_old.strip() == string: # 找到了标识的内容所在的行,开启flag标识,并进入下一行的读取
flag = True
continue
if flag and line_old.startswith("backend"): # 判断想要修改位置的内容是否已经读取完
flag = False
if not flag: # 进行其他无需修改的内容的写入
f_new.write(line_old)
else:
if not has_write: # 进行修改内容的写入
for i in res:
f_new.write(i)
has_write = True
print("修改完成") os.rename("haproxy.conf", "haproxy.conf.bak")
os.rename("haproxy.conf_new", "haproxy.conf")
os.remove("haproxy.conf.bak") def search(data): # 搜索功能
print("这是查询功能,要查找的数据是:", data)
string = "backend %s" % data # 将字符串拼接成文件中的一整行
# return back_data # 返回一个包含查到的内容的列表
return file_hander(string, type="search") def add():
pass def mod(data):
print("这是修改功能")
data = eval(data) # 因为接收到的data是字符串的形式,现在恢复其数据结构
backend = data[0]["backend"] # 就是 www.oldboy1.org
string = "backend %s" % backend # 匹配文件中的一整行内容 old_record_data = "%sserver %s weight %s maxconn %s\n" % (" "*8, data[0]["record"]["server"],
data[0]["record"]["weight"], data[0]["record"]["maxconn"])
# 因为列表中的每一项内容都自动在尾部添加了一个换行符,所以这里也要在尾部添加上一个换行符 new_record_data = "%sserver %s weight %s maxconn %s\n" % (" "*8, data[1]["record"]["server"],
data[1]["record"]["weight"], data[1]["record"]["maxconn"]) res = search(backend)
if res and old_record_data in res: # 判断查找返回的列表是否为非空且查找的记录在res列表中
index = res.index(old_record_data) # 找到要查找的记录对应的那个索引
res[index] = new_record_data # 将索引对应的那条数据替换成新的数据
res.insert(0, "%s\n" % string) # 在列表索引开头的位置添加上匹配定位的一整行内容
else:
print("要修改的内容不存在!") file_hander(string, type="mod", res=res) def delete():
pass if __name__ == "__main__":
Output = """
1.查找 ---(找到对应的backend下所有的server信息)
2.添加
3.修改
4.删除
5.退出 """ choice_dict = {
"": search,
"": add,
"": mod,
"": delete
}
while True:
print(Output)
usr_choice = input("请输入你的操作:").strip()
if usr_choice == "":
print("退出!")
break
if usr_choice in choice_dict.keys():
data = input("请输入你的内容:").strip()
ret = choice_dict[usr_choice](data)
print(ret) # 这是在调用修改功能是输入的数据内容
# [
# {'backend':'www.oldboy1.org', 'record':{'server':'2.2.2.4','weight':20,'maxconn':3000}},
# {'backend':'www.oldboy1.org', 'record':{'server':'2.2.2.5','weight':30,'maxconn':4000}}
# ] # [{'backend':'www.oldboy20.org','record':{'server':'2.2.2.3','weight':20,'maxconn':3000}},{'backend':'www.oldboy10.org','record':{'server':'10.10.0.10','weight':9999,'maxconn':33333333333}}]

7. 异常处理

7.1 错误与异常

try:
raise TypeError('类型错误') # 主动触发异常 age = input('>>>:')
int(age) except IndexError as e:
print(e) except KeyError as e:
print(e) except ValueError as e:
print(e) # except Exception as e: # 抓取所有的异常
# print('请重新输入',e) else:
print('try中的代码没有发生异常就会执行else') finally:
print('无论异常与否,都会执行该模块,通常是进行清理工作') print('')

7.2 自定义异常

class HgzeroException(BaseException): # 这里要继承BaseException
def __init__(self, msg):
self.msg = msg def __str__(self):
return self.msg # raise TypeError('类型错误')
raise HgzeroException('自己定制的异常')

7.3 断言

断言:在程序的某个位置,判断一下结果是不是想要的值,若不是想要的值,就抛出一个异常。

def test1():
res = 1
return 1
res1 = test1() assert res1 == 1 # 在程序的这个位置判断res1是否等于1,若不等于1,则抛出一个AssertionError的异常 # 下面这两行的代码和上面的断言语句等价
if res1 != 1:
raise AssertionError

Python函数&异常处理的更多相关文章

  1. python函数与异常处理

    一.python函数 1.函数自定义格式: 分为有无返回值两种类型 def 函数名(): 代码语句 -------- -------- return 参数1,(参数2等)--------------- ...

  2. Python 函数基础、有序集合、文件操作(三)

    一.set 特点: set是一个无序且不重复的元素集合访问速度快:天生解决元素重复问题 方法: 初始化 >>> s1 = set()>>> print(type(s ...

  3. python的异常处理及异常类定义

    python的异常处理语法和大多数语言相似: try: try块的语句... except exceptiontype1 as var:#使用as语句获得本次捕获到的异常的实例var except块语 ...

  4. 人生苦短之Python函数的健壮性

    如何评论一个开发代码写的好?清晰简洁明了?No,No,一个处女座就可以写出来了,整齐地代码,详细的注释不是代码好的标准,应该说不是最重要的标准.代码写的是否健壮才是检验的重要标准. 代码的健壮性: 当 ...

  5. python函数-迭代器&生成器

    python函数-迭代器&生成器 一.迭代器 1 可迭代协议 迭代:就是类似for循环,将某个数据集内的数据可以“一个挨着一个取出来” 可迭代协议: ① 协议内容:内部实现__iter__方法 ...

  6. python 函数之day3

    一 函数的语法及特性 什么是函数? 定义:函数是一个功能通过一组语句的集合,由名字(函数名)将其封装起来的代码块,要想执行这个函数,只要调用其函数名即可. 特性: 减少重复代码 使程序变的可扩展 使程 ...

  7. Python函数作用域的查找顺序

    函数作用域的LEGB顺序 1.什么是LEGB? L:local 函数内部作用域 E:enclosing 函数内部与内嵌函数之间 G:global 全局作用域 B:build-in 内置作用域 2.它们 ...

  8. Python函数讲解

    Python函数

  9. Python函数信息

    Python函数func的信息可以通过func.func_*和func.func_code来获取 一.先看看它们的应用吧: 1.获取原函数名称: 1 >>> def yes():pa ...

随机推荐

  1. Jenkins-插件开发-BUG-Messages类编译报错

    注意:下载Jenkins插件源码后报错Messages这个类怎么导包都报编译错误的问题! 今天从GitHub下载了Jenkins的一些插件源码,准备自己研究研究写个插件.但是发现每个源码中都存在一个编 ...

  2. python基本数据类型;字符串及其方法三:

    ###################判断类型################### ######################################################### ...

  3. CF861D

    题目链接:http://codeforces.com/contest/861/problem/D 解题思路: 优雅的暴力. 对于输入的每一个号码,从短到长找出它的所有子串,用 vector 保存每个号 ...

  4. Understanding REST and RESTful APIs

    Understanding REST and RESTful APIs If you've spent any amount of time with modern web development, ...

  5. Spring Boot 教程 (4) - swagger-ui

    Spring Boot 教程 - swagger-ui 1. 什么是Swagger? Swagger™的目标是为REST APIs 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到 ...

  6. 【Mac】anaconda安装xgboost(原创)

    1.下载并安装官网最新版anaconda Anaconda3-2020.02-MacOSX-x86_64.pkg 2.conda config --set channel_priority flexi ...

  7. Nginx 的过滤模块是干啥用的?

    上一篇文章我写了 Nginx 的 11 个阶段,很多人都说太长了.这是出于文章完整性的考虑的,11 个阶段嘛,一次性说完就完事了.今天这篇文章比较短,看完没问题. 过滤模块的位置 之前我们介绍了 Ng ...

  8. [PHP自动化-进阶]001.CURL模拟登录并采集数据

    引言:PHP可以通过libcurl实现模拟登录,提交数据,违法乱纪,烧杀抢虐等等事项. 简单说明一下"libcurl",补一下脑: libcurl目前支持http.https.ft ...

  9. win10系统下计算器界面变成英文的解决方法

    标题: win10系统下计算器界面变成英文的解决方法 作者: 梦幻之心星 347369787@QQ.com 标签: [win10, 计算器, 英文] 目录: 软件 日期: 2019-04-20 目录 ...

  10. try catch finally return 轶事

    最近阿里发布了java开发手册终极版,看到其中一条规约:[强制]不能在 finally 块中使用 return, finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 ...