1.函数的定义
a.数学定义的函数(function)与python中的函数(subroutine 子程序 procedures过程)
数学定义的函数:y=2*x+1
python中函数定义方法:
def test(x):
"The function definitions"
x+=1
return x
def:定义函数的关键字,全称define
test:函数名
():内可定义形参
"":文档描述(非必要,但是最好为函数添加描述信息)
x+=1:泛指代码块或程序处理逻辑
return: 定义返回值(作用:结束函数、返回某个对象)
例:
def test(x):
'''
y = 2 * x + 1
:param x:整形数字
:return:返回计算结果
'''
y = 2 * x + 1
return y
print(test)
a = test(3)
print(a)
调用运行:可以带参数也可以不带
def test():
'''
y = 2 * x + 1
:param x:整形数字
:return:返回计算结果
'''
x = 3
y = 2 * x + 1
return y
a = test()
print(a)
b.函数的作用
减少重复代码
方便修改,更易扩展
保持代码一致性
c.函数和过程
过程:就是没有返回值的函数
在python中,过程也是函数,因为即使没有定义返回值,python也会自动返回None
def test01():
msg = 'hello ypp'
print(msg)
def test02():
msg = 'hello yppcyx'
print(msg)
return msg
def test03():
msg = 'hello cyx'
print(msg)
return 1, 2, 3, 'a', None
t1 = test01()
t2 = test02()
t3 = test03()
print(t1)
print(t2)
print(t3)
返回值数=0(没有return时):默认返回None
def f():
print('OK')
s = f()
print(s)
返回值数=1:返回object
返回值数>1:返回元组(多个对象封装成一个元组)
2.函数的参数
形参变量:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元
实参:可以是常量、变量、表达式、函数等
def calc(x, y):
res = x**y
return res
res=calc(2,3)
#x, y是形参,2,3是实参
#函数一碰到return,立马结束掉
# print(x)有问题
# print(y)有问题
print(res)
位置参数和关键字参数:
位置参数:实参与形参位置一一对应,缺一不行,多一 不行
关键字参数:位置无需固定,无需一一对应,缺一不行,多一 不行
def test(x, y, z):
print(x)
print(y)
print(z)
test(1, 2, 3)
混合使用:位置参数一定要在关键字参数的左边
def test(x, y, z):
print(x)
print(y)
print(z)
test(1, 3, z=4)
def test(x, y, z):
print(x)
print(y)
print(z)
test(1, 3, z=4, y=4)报错
默认参数:要跟在非默认参数后面,但是默认参数和不定长参数连用时,需要放在不定长参数前面
def handle(x, type=None):
print(x)
print(type)
handle('hello')
handle('hello', type='mysql')
def handle(x, type=None):
print(x)
print(type)
handle('hello')
handle('hello', type='mysql')
handle('hello', 'my')
参数组/不定长参数:非固定长度的参数 **字典 *列表
用不定长参数实现加法器功能:
def add(*args):#传无命名参数
sum = 0
for i in args:
sum += i
print(sum)
add(1, 2, 3)
def test(x, *args):
print(x)
print(args)
test(1)
test(1, 2, 3, 4, 5, 6)
test(1, {'name': 'cyx'})
test(1, ['x', 'y', 'z'])
test(1, *['x', 'y', 'z'])
def test(x, **kwargs):
print(x)
print(kwargs)
test(1, y=1, z=2)
def test(x, *args, **kwargs):
print(x)
print(args)
print(kwargs)
test(1, 2, 3, 4, 7, y=3, n=8)
def test(x, *args, **kwargs):*args(无命名参数)必须放在**kwargs(有命名参数)前面,否则会报错
print(x)
print(args, args[-1])
print(kwargs, kwargs['y'])
test(1, 2, 3, 4, 7, y=3, n=8)
用不定长参数打印人员信息:
def info(**kwargs):#传命名参数 ,即键值对参数
print(kwargs)
for i in kwargs:
print('%s: %s' %(i, kwargs[i]))
info(name='cyx', sex='male', job='IT', age=23)
参数排列的优先级顺序:位置参数、关键字参数、默认参数、*args、**kwargs
3.局部变量与全局变量
python中的作用域分为四种情况(只有模块 、类及函数才能引入新作用域):
local:局部作用域,即函数中定义的变量
enclosing:嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的
global:全局变量,就是模块级别定义的变量
built-in:系统固定模块里面的变量,如int等
搜索变量的优先级顺序是:局部作用域>嵌套局部作用域>当前模块中的全局>python内置作用域,也就是LEGB
x = int(2.9)#bulit -in
g_count = 0#global
def outer():
o_count = 1#enclosing
def inner():
i_count = 2#local
print(i_count)
inner()
outer()
count = 10
def f():
print(count)#local variable 'count' referenced before assignment
count = 5
f()
count = 10
def f():
count += 5#相当于两步,先count+5,再给count重新赋值,local variable 'count' referenced before assignment
f()
count = 10
def f():
a = count + 5 #local variable 'count' referenced before assignment
count = a
f()
count = 10
def f():
count = 5#直接修改count,此count与全局变量count没有任何关系
f()
print(count)
全局变量:无缩进,在任何位置都能调用到
局部变量:子程序中定义的变量,有缩进
一般情况下,局部作用域变量赋值不影响全局作用域 ;
global +变量名可以在局部作用域修改全局变量;nonlocal+变量名,可以在局部作用域修改嵌套局部作用域变量
name = 'cyx'
def change_name():
name = 'ypp'
print('change_name', name)
change_name()
print(name)
name = 'cyx'
def change_name():
global name
name = 'ypp'
print('change_name', name)
change_name()
print(name)
hobby = '看书'
def cyx():
global hobby#声明hobby是全局变量
print('我喜欢', hobby)
hobby = '旅游'#修改全局变量
print('我喜欢', hobby)
def ypp():
hobby = '打游戏'
print('我喜欢', hobby)
ypp()
cyx()
print(hobby)
修改嵌套局部作用域变量
count = 0
def outer():
count = 1
def inner():
nonlocal count
count = 2
print(count)
inner()
print(count)
outer()
代码规范:全局变量变量名大写,局部变量变量名小写
如果函数内部无global关键字:优先读取局部变量,能读取全局变量,无法对全局变量重新赋值,但是对于可变对象(列表、字典)可以对内部元素进行操作 (remove, clear, update, append...)
如果函数内部有global关键字:变量本质上是全局变量,可读取可赋值
以下程序会报错:
hobby = ['看书', '画画']
def ypp():
hobby = '唱歌'
global hobby
print('我喜欢', hobby)
ypp()
函数嵌套函数的执行顺序
例1
NAME = 'cyx'
def ypp():
name = 'ypp'
print(name)
def yjj():
name = 'yjj'
print(name)
def nulige():
name = 'hu'
print(name)
print(name)
nulige()
yjj()
print(name)
ypp()
例2
name = "cny"
def ypp():
name = "piaopiao"
def yjj():
global name
name = 'jiajia'
yjj()
print(name)
print(name)
ypp()
print(name)
nonlocal 指定上一级变量
name = "cny"
def ypp():
name = "piaopiao"
def yjj():
nonlocal name
name = 'jiajia'
yjj()
print(name)
print(name)
ypp()
print(name)
4.函数即变量
5.递归
函数直接内部自己调用自己会报错
import time
def cal(n):
print(n)
time.sleep(2)
cal(n)
cal(10)
递归必须有一个明确的结束条件
def calc(n):
print(n)
if int(n / 2) == 0:
return n
res=calc(int(n / 2))
return res
res=calc(10)
print(res)
import time
people_list = ['cny', 'ypp', 'yjj', 'yss', 'xiaoming']
def ask_way(people_list):
print('-'*60)
if len(people_list) == 0:
return 'no one knows'
person = people_list.pop(0)
if person == 'yss':
return '%s说:我知道,在肯德基旁边' % person
print('hi 美男[%s],敢问路在何方' % person)
print('%s回答道:我不知道,但念你慧眼识猪,你等着,我帮你问问%s...' % (person, people_list))
time.sleep(1)
res = ask_way(people_list)
print('%s问的结果是: %res' % (person, res))
return res
res = ask_way(people_list)
print(res)
递归特性总结:
1.必须有一个明确的结束条件
2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3.递归效率不高,递归层次过多会导致栈溢出
6.作用域
a.return+函数名返回的是函数的内存地址,返回值+括号可以直接运行该函数
def test1():
print('in test1')
def test():
print('in test')
return test1
res = test()
print(res())
b.函数的作用域只和函数最开始声明的作用域有关,跟调用位置无关
name = 'cyx'
def foo():
name = 'ypp'
def bar():
name = 'yjj'
print(name)
return bar
a = foo()
print(a)
a()
name = 'cyx'
def foo():
name = 'ypp'
def bar():
name = 'yjj'
def tt():
print(name)
return tt
return bar
foo()()()
7.匿名函数
形式:lambda x:x+1(x为形参,x+1为返回值)
func = lambda x: x + 1
print(lambda x: x + 1)
print(func(10))
需求 :将‘cyx’改成‘cyx_df’
方法1:
name = 'cyx'
def change_name(x):
return x + '_df'
res = change_name(name)
print(res)
方法2:
name = 'cyx'
func = lambda x: x + '_df'
print(func(name))
匿名函数通常不会单独使用 ,会和其他函数一起连用
lambda需要返回多个值时,需要自己加上元组的括号,def定义的函数无需加括号 ,函数返回值会默认加上括号
func = lambda x, y, z: (x + 1, y + 1, z + 1)
print(func(1, 2, 3))
8.函数式编程
编程的方法论:面向过程、面向对象、函数式
函数式编程特点:
a.不可变:不用变量保存状态 ,不修改变量
非函数式:
a = 1
def test():
global a
a += 1
return a
test()
print(a)
函数式:
n = 1
def test(n):
return n + 1
print(test(2))
print(n)
b.函数即变量:
函数名可以当做参数传递
def foo(n):
print(n)
def bar(name):
print('my name is %s' %name)
foo(bar)
foo(bar('cyx'))
返回值包含函数,可以是自己,也可以是其他任何函def bar():
print('from bar')
def foo():
print('from foo')
return bar
n = foo()
n()
def handle():
print('from handle')
return handle
h = handle()
高阶函数:函数接收的参数是一个函数名或返回值包含函数
c.尾递归调用优化
尾调用:在函数的最后一步调用另外一个函数(最后一行不一定是函数的最后一步)
函数 bar在 foo内为尾调用
def bar(n):
return n
def foo(x):
return bar(x)
函数bar在foo内为非尾调用
def bar(n):
return n
def foo(x):
y = bar(x)
return y
函数bar在foo内为非尾调用
def bar(n):
return n
def foo(x):
return bar(x) + 1
函数bar1和bar2在foo内均为尾调用,二者在if判断条件不同的情况下都有可能作为函数的最后一步
def foo(x):
if x > 1:
return bar1(x)
elif x == 1:
return bar2(x)
9.内置函数:map函数、filter函数、reduuce函数
a.map函数
需求 1:求一个列表内所有元素的平方
num_l = [1, 2, 10, 5, 3, 7]
ret = []
for i in num_l:
ret.append(i**2)
print(ret)
需求 2:求n个列表内所有元素的平方
num_l = [1, 2, 10, 5, 3, 7]
num1_l = [1, 2, 10, 5, 3, 7]
...
def map_test(array):
ret = []
for i in array:
ret.append(i**2)
return ret
ret = map_test(num_l)
ret1 = map_test(num1_l)
...
print(ret)
print(ret1)
...
需求3:需求不断变化
方法1:
num_l = [1, 2, 10, 5, 3, 7]
num1_l = [1, 2, 10, 5, 3, 7]
def add_one(x):
return x + 1
def reduce_one(x):
return x - 1
def pf(x):
return x**2
def map_test(func, array):
ret = []
for i in array:
res = func(i)
ret.append(res)
return ret
print(map_test(add_one, num_l))
print(map_test(reduce_one, num1_l))
print(map_test(pf, num1_l))
方法1优化:
def map_test(func, array):
ret = []
for i in array:
res = func(i)
ret.append(res)
return ret
print(map_test(lambda x: x + 1, num_l))
方法 3:map 函数
num_l = [1, 2, 10, 5, 3, 7]
print(list(map(lambda x: x - 1, num_l)))
def add_one(x):
return x + 1
num_l = [1, 2, 10, 5, 3, 7]
print(list(map(add_one, num_l)))
msg = 'piaopiao'
print(list(map(lambda x: x.upper(), msg)))
map(处理逻辑,可迭代对象)
可迭代对象进行 一个for 循环,将里面的值依次赋值给处理逻辑,map函数的结果是一个可迭代对象,可以用list转换成一个列表
处理逻辑如果非常精简,可以用lambda,如果逻辑非常复杂,必须自己去定义 ;第二个参数只要 是可迭代对象即可
b.filter函数
需求 :将列表中hr开头的元素都过滤掉
方法1:
movie_people = ['hr_cyx', 'ypp', 'hr_yjj', 'hr_yss']
ret = []
for i in movie_people:
if not i.startswith('hr'):
ret.append(i)
print(ret)
方法2:
movie_people = ['hr_cyx', 'ypp', 'hr_yjj', 'hr_yss']
def filter_test(array):
ret = []
for i in array:
if not i.startswith('hr'):
ret.append(i)
return ret
print(filter_test(movie_people))
方法3:
movie_people = ['hr_cyx', 'ypp', 'hr_yjj', 'hr_yss']
def sb_show(n):
return n.startswith('hr')
def filter_test(func, array):
ret = []
for i in array:
if not func(i):
ret.append(i)
return ret
print(filter_test(sb_show, movie_people))
方法4:
movie_people = ['hr_cyx', 'ypp', 'hr_yjj', 'hr_yss']
def filter_test(func, array):
ret = []
for i in array:
if not func(i):
ret.append(i)
return ret
print(filter_test(lambda x: x.startswith('hr'), movie_people))
方法5
movie_people = ['hr_cyx', 'ypp', 'hr_yjj', 'hr_yss']
print(list(filter(lambda x: not x.startswith('hr'), movie_people)))
c.reduce 函数
需求 :求列表中所有元素的和
方法1:
num_l = [1, 2, 3, 100]
s = 0
for num in num_l:
s += num
print(s)
方法2:
num_l = [1, 2, 3, 100]
def reduce_test(array):
s = 0
for num in array:
s += num
return s
print(reduce_test(num_l))
方法3:
num_l = [1, 2, 3, 100]
def reduce_test(func, array):
res = array.pop(0)
for i in array:
res = func(res, i)
return res
print(reduce_test(lambda x, y: x * y, num_l))
需求2:在100的基础上乘以列表所有元素
num_l = [1, 2, 3, 100]
def reduce_test(func, array, init = None):
if init == None:
res = array.pop(0)
else:
res = init
for i in array:
res = func(res, i)
return res
print(reduce_test(lambda x, y: x * y, num_l, 100))
from functools import reduce
num_l = [1, 2, 3, 100]
print(reduce(lambda x, y: x * y, num_l, 100))
map, reduce, filter总结
map:处理序列中的每个元素,得到的结果是一个迭代器形式 ,需通过list转换为列表,得到的列表元素个数和位置与原来一样
filter:遍历序列中的每个元素,判断每个元素得到布尔值,如果是True则留下来,得到的结果是一个迭代器形式 ,需通过list转换为列表
people=[
{'name':'cyx','age':1000},
{'name':'ypp','age':10000},
{'name':'yjj','age':9000},
{'name':'yss','age':18},
]
print(list(filter(lambda x: x['age']<=18, people)))
reduce:处理一个序列,然后把序列进行一个合并操作
计算1到100的和
from functools import reduce
print(reduce(lambda x,y:x+y,range(100),100))
print(reduce(lambda x,y:x+y,range(1,101)))
d.其他内置函数
abs() 取绝对值
print(abs(-1))
all()参数是序列,对序列中的每个元素进行布尔运算,所有为真才为真,只要有一个为假即为假
布尔值为假的:0 ‘’ None
print(all([1, 2, '']))
print(all('1230'))#1230要看成一个整体
print(all(''))#定义里定义如果可迭代对象为空,返回 True
any()和all相反,只要有一个为真,即为真
print(any([0, '', 1]))
bin()十进制转换为二进制
print(bin(3))
bool()判断布尔值:空 ,None,0的布尔值都为False,其余都为True
bytes()将字符串转换为二进制
name = '你好 '
print(bytes(name, encoding = 'utf-8'))#utf-8一个中文三个字节
print(bytes(name, encoding = 'utf-8').decode('utf-8'))#用什么编码就要用什么解码
print(bytes(name, encoding = 'gbk'))#gbk一个中文两个字节
# print(bytes(name, encoding = 'gbk').decode())#会报错,因为decode默认用utf-8解码
print(bytes(name, encoding = 'gbk').decode('gbk'))
#乱码的根源是编码用一种格式,解码用另一种格式
# print(bytes(name, encoding = 'ascii'))会报错,ascii码不能编码中文
chr()传入数字,返回acii码表中的字符
print(chr(93))
dir()打印某一个对象下面有哪些方法,只打印方法的名字
print(dir(all))
divmod()得出商和余数,用来分页
print(divmod(10, 3))
eval()
把字符串中的数据结构给提取出来
dic = {'name': 'cyx'}
dic_str = str(dic)
print(dic_str)
a = eval(dic_str)
把字符串中的表达式进行运算
express = '1+2*(3/3-1)-2'
print(eval(express))
hash()可hash的数据类型即不可变数据类型,不可hash的数据类型即可变数据类型
hash特性:
不管传入的参数有多长,最后得出的结果长度都是固定的
不能根据hash结果反推字符串是什么
变量被重新赋值时,hash值变化
print(hash('1234jfhio79'))
help()查看帮助
print(help(all))
hex()十进制转成十六进制
print(hex(12))
oct()十进制转换为八进制
print(oct(12))
isinstance(a,b)判断a是否是b的实例
print(isinstance(1, int))
print(isinstance('abc', str))
print(isinstance([], list))
print(isinstance({}, dict))
print(isinstance({1, 2}, set))
globals()全局变量 locals 局部变量
name = '啦啦啦啦啦啦绿绿绿绿绿绿'
def test():
age = '123456'
print(globals())
print(locals())
test()
zip()传两个序列参数(列表、元组、字符串),当两个序列的元素数不一样时,多余的元素会被忽略
print(list(zip(('a', 'b', 'c'), (1, 2, 3))))
print(list(zip(('a', 'b', 'c'), (1, 2, 3, 4))))
print(list(zip(('a', 'b', 'c', 'd'), (1, 2, 3))))
dict = {'name': 'cyx', 'age': 18, 'gender': 'male'}
print(list(zip(dict.keys(), dict.values())))
print(list(zip('hello', '1234')))
max()取最大值 min()取最小值
l = [1, 3, 6, 8, -2, -9]
print(max(l))
print(min(l))
需求:取出最大年纪
默认比较的是字典的key,按照ascii码表的顺序比较
age_dict = {'age12345': 45, 'age3': 134, 'age4': 90, 'age2': 14}
print(max(age_dict))
取出最大的年纪:比较的是value,但不知道是哪个key对应的
age_dict = {'age12345': 45, 'age3': 134, 'age4': 90, 'age2': 14}
print(max(age_dict.values()))
取出谁的年纪最大,也即取一个key:value
age_dict = {'age12345': 45, 'age3': 134, 'age4': 90, 'age2': 14}
print(max(zip(age_dict.values(), age_dict.keys())))
max比较顺序:
传入的数据类型必须是可迭代类型(相当于一个for循环取出每个元素进行比较)
第一个元素能比较出大小,就不会再比较后面的
l = [
(5, 'e'),
(1, 'b'),
(3, 'a'),
(4, 'd'),
]
print(list(max(l)))
l1 = ['a10', 'b9', 'c1']
print(list(max(l1)))
不同类型间不能进行比较
l1 = ['a10', 'b9', 'c1', 100]
print(list(max(l1)))
第一位相同,就比较第二位
l1 = ['a10', 'a3', 'a10']
print(list(max(l1)))
需求 :取出年纪最大的
people=[
{'name':'cyx','age':1000},
{'name':'ypp','age':10000},
{'name':'yjj','age':9000},
{'name':'yss','age':18},
]
print(max(people, key=lambda dic: dic['age']))
ord()传入一个字符,返回其在ascii码表中表示的数字是什么
print(ord('a'))
pow(x, y, z)两个参数时表示x**y,三个参数时表示 x**y%z
print(pow(2, 3, 2))
reversed()反转,处理完没有保存下来,对被反转对象没有影响
l = [1, 2, 3, 4]
print(list(reversed(l)))
print(l)
round()四舍五入
print(round(3.5))
set()转换为集合
print(set('hello'))
slice()切片
l = 'hello'
s1 = slice(3, 5)
s2 = slice(1, 4, 2)
print(l[s1])
print(l[s2])
print(s2.start)
print(s2.stop)
print(s2.step)
sorted()排序
l = [3, 2, 1, 5, 7]
l1 = [3, 2, 'a', 1, 5, 7]
print(sorted(l))
print(sorted(l1))#排序本质就是比较大小,不同类型之间不可以比较大小
people=[
{'name':'cyx','age':1000},
{'name':'ypp','age':10000},
{'name':'yjj','age':9000},
{'name':'yss','age':18},
]
print(sorted(people, key=lambda dic: dic['age']))#和max用法非常类似
print(max(people, key=lambda dic: dic['age']))
people = {
'cyx': 900,
'ypp': 230,
'yjj': 120
}
print(sorted(people))#默认比较key
print(sorted(people, key=lambda key: people[key]))#按照value比,但返回的结果是key
print(sorted(zip(people.values(), people.keys())))#既拿到key,又拿到value
str()转换成字符串
print(type(str({'name': 'cyx'})))
print(type(eval(str({'name': 'cyx'}))))
sum()求和
l = [1, 2, 3, 4]
print(sum(l))
print(sum(range(5)))
type()查看类型
msg = '123'
if type(msg) is str:
msg = int(msg)
print(msg+1)
vars()参数为空时,相当于locals;传对象时,以字典形式 返回对象下的方法
def test():
msg = 'hfdhklwihhv'
print(locals())
print(vars())
test()
print(vars(int))
10.深浅拷贝
浅拷贝:只拷贝第一层
husband = ['cyx', 123, [15000, 9000]]
wife = husband.copy()
wife[0] = 'ypp'
wife[1] = '345'
wife[2][1] -= 5000
print(husband)#只拷贝第一层,第二层指向原来的内存地址,所以修改wife,huband也变
深拷贝:克隆一份,需要单独模块执行
import copy
husband = ['cyx', 123, [15000, 9000]]
san = copy.deepcopy(husband)
san[0] = 'hjk'
san[1] = '890'
san[2][1] -= 90
print(husband)
print(san)#克隆之后修改互不影响