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)#克隆之后修改互不影响

 

posted on 2018-04-23 20:41  吃猫粮的狗  阅读(207)  评论(0编辑  收藏  举报