一、函数
1、函数是什么?
函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
语法定义
def sayhi():#函数名
print("Hello, I'm nobody!")
sayhi() #调用函数
可以带参数
#下面这段代码
a,b = 5,8
c = a**b
print(c)
#改成用函数写
def calc(x,y):
res = x**y
return res #返回函数执行结果
c = calc(a,b) #结果赋值给c变量
print(c)
2、函数参数
形参:变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数
获得确定值。
3、默认参数
看下面代码:
def stu_register(name,age,country,course):
print("----注册学生信息------")
print("姓名:",name)
print("age:",age)
print("国籍:",country)
print("课程:",course)
stu_register("王山炮",22,"CN","python_devops")
stu_register("张叫春",21,"CN","linux")
stu_register("刘老根",25,"CN","linux")
发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是 中国, 这就是通过默认参数实现的,把country变成默认参数非常简单
def stu_register(name,age,course,country="CN"):
这样,这个参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值。
另外,你可能注意到了,在把country变成默认参数后,我同时把它的位置移到了最后面,为什么呢?
4、关键参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是,关键参数必须放在位置参数之后。
stu_register(age=22,name='alex',course="python",)
5、非固定参数
若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定参数
def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式
print(name,age,args)
stu_register("Alex",22)
#输出
#Alex 22 () #后面这个()就是args,只是因为没传值,所以为空
stu_register("Jack",32,"CN","Python")
#输出
# Jack 32 ('CN', 'Python')
还可以有一个**kwargs
def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
print(name,age,args,kwargs)
stu_register("Alex",22)
#输出
#Alex 22 () {}#后面这个{}就是kwargs,只是因为没传值,所以为空
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
# Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
函数调用
# 动态参数
def show(*args,**kwargs):
print(args,type(args))
print(kwargs,type(kwargs))
# 普通的调用
show(11,22,33,key1='aa',key2='bb')
# 在调用时传入列表和字典
li = [11,22,33]
di = {'key1':'aa','key2':'bb'}
show(*li,**di)
str.format的案例使用
str1 = '{0} is {1}'
rest = str1.format('alex','sb')
print(rest)
str2 = '{name} is {action}'
rest = str2.format(name='alex',action='sb')
print(rest)
6、局部变量
name = "Alex Li"
def change_name(name):
print("before change:",name)
name = "金角大王,一个有Tesla的男人"
print("after change", name)
change_name(name)
print("在外面看看name改了么?",name)
输出
before change: Alex Li
after change 金角大王,一个有Tesla的男人
在外面看看name改了么? Alex Li
7、函数的返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
- 函数在返回多个值是,python会自动将多个值封装成元祖返回
import math
# 函数的多个参数以及多个返回值
def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y + step * math.sin(angle)
return nx, ny # 返回多个值时,python自动将多个值封装成元组返回
print(move(30,40,6,45)) # (33.15193193290638, 45.10542114720471)
nx,ny = move(30,40,6,45)
print(nx,ny) # 33.15193193290638 45.10542114720471
8、函数的递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
def calc(n):
print(n)
if int(n/2) == 0: # 此次的条件为n为1时,退出循环.
return n
else:
return calc(int(n / 2))
递归函数实际应用案例,二分查找(二分查找只适合已排序的列表):
def binary_search(dataset,find_num):
print(dataset)
if len(dataset) > 1:
mid = int(len(dataset)/2)
if dataset[mid] == find_num: #find it
print("找到数字",dataset[mid])
elif dataset[mid] > find_num:
print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
return binary_search(dataset[:mid],find_num)
else:
print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
return binary_search(dataset[mid+1:], find_num)
else:
if dataset[0] == find_num: #find it
print("找到数字啦",dataset[0])
else:
print("要找的数字[%s]不在列表里" % find_num)
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
binary_search(data,12)
非递归方式的实现:
def binary_search2(dataset,find_num):
start = 0
end = len(dataset) - 1
while start <= end :
print(dataset[start:end+1])
mid = int((start + end)/2)
if dataset[mid] == find_num: # find it
print("找到数字", dataset[mid])
return dataset[mid]
elif dataset[mid] > find_num:
print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
end = mid - 1
else:
print("\033[32;1m找的数在mid[%s]右面\033[0m" % dataset[mid])
start = mid + 1
print("要找的数字[%s]不在列表里" % find_num)
data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
binary_search2(data,12)
9、函数的嵌套
10、匿名函数(lambda表达式)
在讲lambda之前先看一下三元运算符
# 普通条件语句
if 1 == 1:
name = 'luotianshuai'
else:
name = 'shuaige'
以上简单的逻辑判断可以使用三元运算符表示:
# 三元运算
name = 'luotianshuai' if 1 == 1 else 'shuaige'
lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值。lambda语句构建的其实是一个函数对象。
foo = lambda x,y,z : x+y+z
以上lambda表达式和以下函数的效果是一样的:
def foo(x,y,z):
return x + y + z
12、内置参数
map和filter
#!/usr/bin/env python3
num_list = [11,22,33,44]
# map:将所以列表集体操作,返回新的列表
new_num_list = map(lambda x:x+100,num_list)
print(list(new_num_list))
# filter: 将满足条件的放入新的列表中
new_num_list = filter(lambda x:True if x>22 else False,num_list)
print(list(new_num_list))
验证码:
#!/usr/bin/env python3
import random
verify_code = []
for i in range(4):
random_num = random.randint(1, 9)
if random_num < 5:
random_code = random.randint(66,90)
verify_code.append(chr(random_code))
else:
verify_code.append(str(random_num))
print(''.join(verify_code))
二、迭代器
如何判断一个对象是可迭代对象呢?方法是通过collections模块的Iterable类型判断.
print(isinstance('abc', Iterable)) # 字符串是否可迭代:True
print(isinstance(['a','b','c'], Iterable)) # 列表是否可迭代:True
print(isinstance(123, Iterable)) # 数字是否可迭代:False
对字典进行迭代操作
user_dict = {'username':'Alex','age':18,'job':'Engineer'}
# 迭代字典得到key,通过key获取value
for key in user_dict:
value = user_dict[key]
print(key,':', value)
# 迭代字典中所有的key和value
for key, value in user_dict.items():
print(key, '=', value)
# 迭代字典中所有的key
for key in user_dict.keys():
print(key)
# 迭代字典中所有的value
for value in user_dict.values():
print(value)
对字符串进行迭代操作
str = 'ABCDEFG'
for ch in str:
print(ch)
#result
A
B
C
D
E
F
G
最后一个小问题,如果要对list实现类似Java那样的下标循环怎么办?Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身.
username_list = ['Alex', 'Eric', 'Kingle', 'Magic']
for index, username in enumerate(username_list):
print(index, username)
for index, username in enumerate(username_list, 100):
print(index, username)
三、生成器
生成器:一个函数在调用时返回一个迭代器,那么这个函数就叫做生成器,那这个函数就会变成生成器
def cash_money(amount):
while amount > 0:
amount -= 100
yield 100
print('又来取钱了....')
atm = cash_money(500)
print(atm.__next__())
print(atm.__next__())
print(atm.__next__())
使用yield实现单线程中的异步并发效果(生产者和消费者的案例)
import time
def consumer(name):
print('准备处理用户%s请求'% name)
while True:
req = yield
print('正在处理[%s]的第[%s]请求'%(name,req))
def producer():
alex = consumer('Alex')
eric = consumer('Elex')
alex.__next__()
eric.__next__()
for i in range(10):
time.sleep(1)
print('同时并发2个请求')
alex.send(i)
eric.send(i)
producer()
四、装饰器
#!/usr/bin/env python3
# 装饰器原理解析1
def login(func):
print('login sucessful ...')
return func
def index(username):
print('%s,welcome to python ...' %username)
index = login(index)
index('zhangming')
# 装饰器原理解析2:以上在不执行index('zhangming')函数时,也会执行login验证,需要进行以下改造.
def login(func):
def inner(arg):
print('login sucessful ...')
func(arg)
return inner
def index(username):
print('%s,welcome to python ...' %username)
index = login(index)
index('zhangming') # 此时执行的是inner函数
# 装饰器的使用
def login(func):
def inner(arg):
print('login sucessful ...')
func(arg)
return inner
@login # 等同于 index = login(index)
def index(username):
print('%s,welcome to python ...' %username)
#index = login(index)
index('zhangming')
# 装饰器的使用:装饰器的返回值和参数
def login(func):
def inner(*args,**kwargs):
print('login sucessful ...')
return func(*args,**kwargs)
return inner
@login
def index(username,password):
print('%s,welcome to python ...' %username)
return True
#index = login(index)
stats = index('zhangming','123456')
print(stats)
五、列表生成表达式
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
列表生成式
'''
# 生成一个[1, 2, 3, ..., 10]列表
print([x for x in range(1,11)])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 生成一个[1x1, 2x2, 3x3, ..., 10x10]列表
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
print([x*x for x in range(1, 11)])
# 生成一个[1+1, 2+2, 3+3, ..., 10+10]列表
print([x+x for x in range(1, 11)])
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# 生成一个[1x1, 2x2, 3x3, ..., 10x10]列表中所有的偶数
print([x*x for x in range(1, 11) if x%2 == 0])
[4, 16, 36, 64, 100]
# 使用两层循环,可以生成全排列.
print([x+y for x in 'ABC' for y in 'XYZ'])
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
# 列出当前目录下的所有文件和目录名,可以通过一行代码实现.
import os
print([dir for dir in os.listdir('.')])
# 列表生成式也可以使用两个变量来生成list
test_dict = {'x': 'A', 'y': 'B', 'z': 'C' }
print([k + '=' + v for k,v in test_dict.items()])
['y=B', 'x=A', 'z=C']
# 将list中所有的字符串变成小写:
test_list = ['Hello', 'World', 'IBM', 'Apple']
print([l.lower() for l in test_list])
['hello', 'world', 'ibm', 'apple']
# 输出L1列表中的所有字符串
l1 = ['Hello', 'World', 18, 'Apple', None]
print([s for s in l1 if isinstance(s,str)])
['Hello', 'World', 'Apple']
# 生成一个4*4二维数组
l2 = [ [ i for i in range(4)] for j in range(4) ]
for l in l2:
print(l)
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
[0, 1, 2, 3]
案例:生成一个4*4的二维数组,将其旋转90度
# 99乘法表
for i in range(10):
for j in range(i+1):
print('%d*%d=%d' %(i, j, i * j),end='\t'),
print('')
# 列表90度旋转
data = [[i for i in range(4)] for j in range(4) ]
for d in data:
print(d)
print('----')
for i in range(len(data)):
for j in range(i,len(data[i])):
tmp = data[i][j]
data[i][j] = data[j][i]
data[j][i] = tmp
print('[%d][%d]<=>[%d][%d]' % (i,j,j,i))
print('----')
for d in data:
print(d)
案例:冒泡排序
data = [1,25,2,45,65,10,56,85,45,23]
for i in range(1,len(data)):
for j in range(len(data)-i):
if data[j] > data[j+1]:
tmp = data[j]
data[j] = data[j+1]
data[j+1] = tmp
print(data)
练习:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os,re,sys
def show_backend_server(file,backend_name):
server_flag = False
with open(file, 'r') as read_file:
for line in read_file.readlines():
if re.match('backend', line):
if re.split('\s+', line)[1] == backend_name:
server_flag = True
else:
server_flag = False
if server_flag and re.match('\s+server', line):
print(line.replace('\n',''))
def add_backend_server(file,handle_dict):
newfile = '%s.new' % file
backend_flag = False
server_flag = False
server_li = []
with open(file, 'r') as read_file, open(newfile, 'w') as write_file:
for line in read_file:
line_li = line.strip().split(' ')
if line_li[0] == 'backend' and line_li[1] == handle_dict['backend']:
write_file.write(line)
backend_flag = True
continue
if backend_flag and re.match('\s+server', line):
server_li.append(line)
server_flag = True
continue
if server_flag:
server_dict = handle_dict['record']
server_line = '\tserver {name} {server} weight {weight} maxconn {maxconn}\n'.format(**server_dict)
if server_line not in server_li:
server_li.append(server_line)
for l in server_li:
write_file.write(l)
server_flag = False
write_file.write(line)
backend_flag = False
os.remove(file)
os.rename('%s.new' % file,file)
def del_backend_server(file,handle_dict):
newfile = '%s.new' % file
backend_flag = False
server_flag = False
server_li = []
with open(file, 'r') as read_file, open(newfile, 'w') as write_file:
for line in read_file:
line_li = line.strip().split(' ')
if line_li[0] == 'backend' and line_li[1] == handle_dict['backend']:
write_file.write(line)
backend_flag = True
continue
if backend_flag and re.match('\s+server', line):
server_li.append(line)
server_flag = True
continue
if server_flag:
server_dict = handle_dict['record']
server_line = '\tserver {name} {server} weight {weight} maxconn {maxconn}\n'.format(**server_dict)
if server_line in server_li:
server_li.remove(server_line)
for l in server_li:
write_file.write(l)
server_flag = False
write_file.write(line)
backend_flag = False
os.remove(file)
os.rename('%s.new' % file, file)
def user_input():
backend_name = input('请输入backend:')
name = input('请输入服务器的名字:')
server = input('请输入服务器的IP:')
weight = input('请输入服务器的权重:')
maxconn = input('请输入服务器的最大连接数:')
record = {'name': name, 'server': server, 'weight': weight, 'maxconn': maxconn}
handle_dict = {'backend': backend_name, 'record': record}
return handle_dict
if __name__ == '__main__':
while True:
print(
'''
选择:
1、获取ha记录
2、增加ha记录
3、删除ha记录
4、退出
''')
choice = input('请输入操作序号:')
if choice == '1':
backend_name = input('请输入backend:')
show_backend_server('conf/ha.txt', backend_name)
elif choice == '2' :
handle_dict = user_input()
add_backend_server('conf/ha.txt', handle_dict)
elif choice == '3':
handle_dict = user_input()
# {'backend': 'www.oldboy.org', 'record': {'name': '100.1.7.9', 'server': '100.1.7.9', 'weight': '20', 'maxconn': '20'}}
print(handle_dict)
del_backend_server('conf/ha.txt', handle_dict)
elif choice == '4':
sys.exit()
else:
pass