函数

定义:

对功能进行定义和封装,在需要时候,随时拿过来直接调用,定义和封装的就是函数.

函数:对代码块的封装和定义

 

调用函数:

定义函数的语法:

def   函数名():

      函数体(代码块)

函数名的命名规则和变量的命名规则一样.

函数的调用:

函数名()  使用函数名去调用,函数就会被调用.

例:

def fan():
print("先找到电饭煲,")
print("将适量的米洗好,")
print("将洗好的米放入电饭煲中,")
print("插上电源,")
print("将到合适的时间.")
fan()
结果:
先找到电饭煲,
将适量的米洗好,
将洗好的米放入电饭煲中,
插上电源,
将到合适的时间.

函数的返回值  return

当函数结束的时候,该调用方一个结果.

return作用:遇到return,函数就会停止不会再继续执行.

return的几种情况:

1.return后面什么内容都不写后者不写return.那么返回的就是None.

例:

def fan():
print("先找到电饭煲,")
print("将适量的米洗好,")
print("将洗好的米放入电饭煲中,")
print("插上电源,")
print("将到合适的时间.")
return
ret=fan()
print(ret)
结果:
先找到电饭煲,
将适量的米洗好,
将洗好的米放入电饭煲中,
插上电源,
将到合适的时间.
None

2.如果return后面写一个返回值,则调用者可以接收一个结果.

例:

def fan():
print("先找到电饭煲,")
print("将适量的米洗好,")
print("将洗好的米放入电饭煲中,")
print("插上电源,")
print("将到合适的时间.")
return "做米饭步骤"
ret=fan()
print(ret)
结果:
先找到电饭煲,
将适量的米洗好,
将洗好的米放入电饭煲中,
插上电源,
将到合适的时间.
做米饭步骤

3.如果return后面写了多个结果,则调用者可以接收一个元组(tuple),调用者可以直接解构成多个变量.

例:

def yue():
print("约会")
return "送花","吃饭","看电影"
a,b,c=yue()
print(a,b,c)
结果:
约会
送花 吃饭 看电影

 

函数的参数:

在函数执行的时候,给函数传递信息

参数分为:形参和实参.

例:

def yue(song,fangshi):
print("%s,吃饭,%s" % (song,fangshi))
yue("送花","看电影")
yue("不送","逛街")
结果:
送花,吃饭,看电影
不送,吃饭,逛街

函数的参数个数是没有要求的,但是,在运行的时候形参和实参要匹配,按照位置把实参赋值给形参.

实参:在函数调用的位置,实际是给函数传递的值

实参的分类:

(1)位置参数

(2)关键值参数.  在实参调用的时候可以指定参数的值是多少.

(3)混合参数.  先写位置参数在写关键字参数,否则会报错.

例:

def xinxi(name,age,sex,hobby,salary):
print("%s\t%s\t%s\t%s\t%s\t" % (name,age,sex,hobby,salary))
xinxi("abc",21,"女","听歌",'10000')
xinxi(age=20,name="abc",hobby="听歌",salary=10000,sex="女")
xinxi("abc",21,"女",salary=10000,hobby="听歌")
结果:
abc 21 女 听歌 10000 
abc 20 女 听歌 10000 
abc 21 女 听歌 10000

形参:在函数声明的位置,声明出来的变量

形参的分类:

(1)位置参数

(2)默认值参数

(3)默认值和位置参数混合使用

例:

def xinxi(id,name,sex="男"):
print("id:%s,名字:%s,性别:%s" % (id,name,sex))
xinxi(2,"b","女")
xinxi(1,"a",)
结果:
id:2,名字:b,性别:女
id:1,名字:a,性别:男

函数语法:

def 函数名(形参)

      函数体(代码块)

     (return  "   ")

函数名(实参) 

例:1+2+3+4+...+n=?

def num(n):
sum = 0
count=1
while count<=n:
sum+=count
count+=1
return sum
ret=num(100)
print(ret) ==<5050>

例:判断n是奇数还是偶数?

def fn(n):
if n%2==0:
return "偶数"
return "奇数"
ret=fn(425)
print(ret) ==<奇数> 

动态参数(形参):

动态接收位置参数 *args  [def 函数名(*参数名(可以传入任意位置的参数))]

动态参数接收的是元组(tuple)类型的数据

例:

def fn(*food):
print("我要吃:",food)
fn("米饭","馒头","面条","菜")
==<我要吃: ('米饭', '馒头', '面条', '菜')>

动态接收参数的时候要注意:动态参数必须在位置参数后面

动态接收关键字参数  **kwargs 接收到是一个字典(dict)

例:

def fn(**drink):
print(drink)
fn(drink1="北冰洋",drink2="芬达",drink3="雪碧")
==<{'drink1': '北冰洋', 'drink2': '芬达', 'drink3': '雪碧'}>

传参的顺序:位置参数->*args->默认值参数->**kwargs

例:

def fn(a,b,*c,d=4):
print(a,b,c,d)
fn(1,2,3,4,5,6,7,8,9)
==<1 2 (3, 4, 5, 6, 7, 8, 9) 4>

*args 和**kwargs可以接收所有参数

例:

def fn(*args,**kwargs):
print(args,kwargs)
fn(1,5,6,7,name="a",age=12,sex="女")
==<(1, 5, 6, 7) {'name': 'a', 'age': 12, 'sex': '女'}>

动态传参的另一种传参方式:

在实参位置上给一个序列,列表,在可迭代对象前面加一个*表示把这个序列按照顺序打散.

在形参位置上加*表示把接收的参数组合成一个元组

字典也可以打散,需要两个*

例:

def fn(*args):
print(args)
li=["麻花","月季","紫金花","玫瑰花"]
fn(*li)
==<('麻花', '月季', '紫金花', '玫瑰花')>

例:

def fn(**kwargs):
print(kwargs)
dic={"a":1,"b":2}
fn(**dic)
==<{'a': 1, 'b': 2}>

 

注释:

例:

def fn(a,b):
"""
函数fn是计算a+b的和
:param a: 第一个数
:param b: 第二个数
:return: 返回a+b的和
"""
print(a,b)
return a+b

 

命名空间:

1.内置命名空间:python解释器内部运行时的变量函数list,tuple,str,int这些都是内置命名空间

2.全局命名空间:直接在py文件中,函数外声明的变量都属于全局命名空间.

3.局部命名空间:在函数中声明的变量会放到局部命名空间.

加载顺序:内置命名空间>全局命名空间>局部命名空间(函数被执行的时候)

取值顺序:局部命名空间>全局命名空间>内置命名空间

 

作用域:

1.全局作用域:全局命名空间+内置命名空间  通过globals()函数查看全局作用域中的内容

2.局部作用域:局部命名函数 通过locals()函数查看局部作用域中的变量和函数信息

例:

a=10
def fn():
a=40
b=20
def abc():
print("haha")
print(a,b)
print(globals())
print(locals())
fn()

 

函数嵌套:

1.只要遇见()就是函数的调用.如果没有()就不是函数的调用

2.函数的执行顺序

例:

def fn1():               #1
print("haha") #3
def fn2(): #4
print("keke") #6
fn2() #5
print("hoho") #7
fn1() #2
==<haha
keke
hoho>

 

关键字global和nonlocal:

global表示.不在使用局部变量作用域中的内容.而改用全局作用域中的变量

例:

a=10
def fun():
global a #表示不再局部创建这个变量,而是直接使用全局的a
a=20
print(a)
fun()
print(a) ==<20 20>

nonlocal 表示在局域作用域中1,调用父级命名空间中的变量

例:

a=10
def fn1():
a=20
def fn2():
nonlocal a
a=30
print(a)
fn2()
print(a)
fn1() ==<30 30>

 

函数名的运用:

函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量.

1.函数名可以赋值给其他变量

例:

def fn():
print("abc")
print(fn) #函数的内存地址
a = fn #将函数赋值给a
a() #调用函数
==> <function fn at 0x00000229C37C2AE8>
abc

2.函数可以作为函数的参数

例:

def func(fn):
fn()
def gn():
print("abc")
func(gn) ==>abc

3.函数名可以当做容器类的元素

例:

def fn1():
print("呵呵")
def fn2():
print("嘿嘿")
def fn3():
print("吼吼")
lis = [fn1,fn2,fn3]
for i in lis:
i()
==>呵呵
嘿嘿
吼吼

4.函数名可以作为函数的返回值

例:

def gn():
def inner():
print("aaa")
return inner #返回inner函数
ret = gn()
ret() ==>aaa

 

闭包:

1.闭包定义:内层函数对外层(非全局)的变量的引用.

变量写在全局是不安全.

例:

def fn():
name = "alex"
def inner():
print(name)
return inner
ret = fn()
ret() ==>alex #访问inner函数

2.闭包的特点:

(1)安全(防止其它程序改变这个变量)

(2)常驻内存,提高效率.

3.查看闭包

__closure__()函数可以查看闭包.

如果不是闭包返回None 是闭包会返回cell

例:

def fn():
name = "alex"
def inner():
print(name)
inner()
print(inner.__closure__)
fn()
==> alex
(<cell at 0x00000204D86B9468: str object at 0x00000204D867D0D8>,)

 

迭代器:

1.可迭代对象和迭代器

str.list.tuple.set.range.文件句柄都是可迭代的数据类型

可迭代的数据类型中都有__iter__()函数.用dir()函数来查看一个数据类型中是否包含了那些函数.

例:

s = 'abc'
print("__iter__"in dir(s)) ==>True

所有包含了__iter__函数的数据类型都是可迭代的数据类型

Iterable表示可迭代的

__iter__作用返回一个迭代器  

__next__和__iter__两个函数都是迭代器的内部函数

例:

lst = ["abc","def","ghi"]
it = lst.__iter__()
print(it.__next__()) ==>abc
print(it.__next__()) ==>def
print(it.__next__()) ==>ghi
print(it.__next__()) ==>Error 迭代到最后一个之后,再迭代会报错

例:

lis = ["abc","def","ghi"]
it = lis.__iter__()
while 1:
try:
name = it.__next__()
print(name)
except StopIteration:
break
==>abc \n def \n ghi

try...except固定搭配

例:

lst = [1,2,3]
print("__iter__"in dir(lst)) ==>True
print("__next__"in dir(lst)) ==>False

例:

lst = [1,2,3]
from collections import Iterable
from collections import Iterator
print(isinstance(lst,Iterable)) ==>True
print(isinstance(lst,Iterator)) ==>False

isinstance(对象,类型)判断对象是不是...类型

迭代器一定是可迭代的

文件句柄是迭代器

2.迭代器的特点

(1)节省内存

(2)惰性机制

(3)不能反复,只能向下执行

 

生成器:

在python中有三种方式来获取生成器.

1.通过生成器函数

2.通过生成器表达式创建生成器

3.通过数据的转换也可以获取生成器

例:yield就是生成器函数

def fn():
print("ABC")
yield 123
print(fn()) ==><generator object fn at 0x000001924E88A938>
获取生成器内存地址

例:生成器实质就是迭代器.

def fn():
print("ABC")
yield 123
ret = fn()
print(ret.__next__())
==>ABC
123

yield是分段执行一个函数.  return直接停止函数

在程序运行完最后一个yield.那么后面继续进行__next__()程序会报错

生成器的优点:节省内存 

例:

def fn():
i = 1
while i<100001:
yield "衣服%s" % i
i = i + 1
g = fn()
g1 = fn() g和g1是两个生成器
print(g.__next__())
print(g.__next__())
print(g.__next__())
print(g.__next__())
结果:
衣服1
衣服2
衣服3
衣服4

生成器是一个一个的指向下一个,不会回去,__next__()到哪,指针就指到那下一次继续获取指针指向的值

生成器函数被执行,获取的是生成器,而不是函数的执行

生成器的for循环

例:

def fn():
yield "aa"
yield "bb"
yield "cc"
g = fn()
for i in g: 本质执行的是__next__()
print(i)
结果:
aa
bb
cc

例:生成器加到列表里面

def fn():
yield 11
yield 22
yield 33
g = fn()
lst = list(g)
print(lst)
结果:[11, 22, 33]

send()方法和__next__()函数一样都可以让生成器执行到下一个yield

例:

def eat():
print("你吃什么啊")
a = yield "馒头"
print("a = ",a)
b = yield "大饼"
print("b =",b)
c = yield "韭菜盒子"
print("c =",c)
yield "GAME OVER"
gen = eat()
ret1 = gen.__next__()
print(ret1)
ret2 = gen.send("胡辣汤")
print(ret2)
ret3 = gen.send("狗粮")
print(ret3)
ret4 = gen.send("猫粮")
print(ret4)
结果:
你吃什么啊
馒头
a =  胡辣汤
大饼
b = 狗粮
韭菜盒子
c = 猫粮
GAME OVER

send和next的区别:

(1)send和next都是让生成器走向下一次

(2)send可以给上一个yield的位置传递值,不能给最后yield传值.在第一次执行生成器代码不能用send()

 

推导式来实现生成器:

列表推导式:

语法:[最终结果(变量) for 变量 in 可迭代对象 条件]

例:for循环

lst = []
for i in range(1,15):
lst.append("python%d" % i)
print(lst)
结果:['python1', 'python2', 'python3', 'python4', 'python5', 'python6', 'python7', 'python8', 'python9', 'python10', 'python11', 'python12', 'python13', 'python14']

例:推导式

lst = ["prthon%d" % i for i in range(1,15)]
print(lst)
结果:['prthon1', 'prthon2', 'prthon3', 'prthon4', 'prthon5', 'prthon6', 'prthon7', 'prthon8', 'prthon9', 'prthon10', 'prthon11', 'prthon12', 'prthon13', 'prthon14']

例:求100以内的偶数

lst = [i for i in  range(1,101) if i % 2 == 0]
print(lst)
结果:[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]

 

生成器推导式:

语法:(结果 for 变量 in 可迭代对象 if条件)

例:

g = (i for i in range(10))
print(g) ==><generator object <genexpr> at 0x000002875BB1A938>
print(list(g)) ==>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

生成器推导式特点:几乎不占内存;惰性机制,不到最后不会拿值

例:

def fn():
print(111)
yield 222
g = fn()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g))
print(list(g1))
print(list(g2))
结果:
111
[222]
[]
[]

 

字典推导式:

语法:{结果 for 变量 in 可迭代对象 条件}结果==>key:value

例:

dic = {"a":1,"b":2,"c":3}
new_dic = {dic[key]:key for key in dic}
print(new_dic) ==>1: 'a', 2: 'b', 3: 'c'}

例:

lst1 = ["A","B","C"]
lst2 = ["a","b","c"]
dic = {lst1[i]:lst2[i] for i in range(len(lst1))}
print(dic) ==>{'A': 'a', 'B': 'b', 'C': 'c'}

集合推导式 :  特点: 无序 去重

语法:{结果 for 变量 in 可迭代对象 条件}

例:

lst = [1,-1,2,3,1,5,7,3]
s = {i for i in lst}
print(s) ==>{1, 2, 3, 5, 7, -1}

 

例题:

1.

user_list = [{"name":"alex","hobby":"抽烟"},
{"name":"alex","hobby":"喝酒"},
{"name":"alex","hobby":"烫头"},
{"name":"wusir","hobby":"喊麦"},
{"name":"wusir","hobby":"街舞"}]
==>[{'name': 'alex', 'hobby_list': ['抽烟', '喝酒', '烫头']},
{'name': 'wusir', 'hobby_list': ['喊麦', '街舞']}]

解题思路: 判断是否在result里面存在这个人的信息,如果不存在则新建一个字典,把hobby_list对应的value值放到一个列表中; 如果存在把hobby_list对应的列表加入一个hobby.

 解题步骤:

user_list = [{"name":"alex","hobby":"抽烟"},
{"name":"alex","hobby":"喝酒"},
{"name":"alex","hobby":"烫头"},
{"name":"wusir","hobby":"喊麦"},
{"name":"wusir","hobby":"街舞"}]
result = []
for user in user_list:
for new_user in result:
if new_user["name"] == user["name"]:
new_user.setdefault("hobby_list",[]).append(user["hobby"])
break
else:
dic = {}
dic["name"] = user["name"]
dic["hobby_list"] = [user["hobby"]]
result.append(dic)
print(result)

如果默认值参数是一个可变的数据类型,在调用的时候改变了.在其他位置看到的也跟着改变.

例:

def extendList(val, list=[]):
list.append(val)
return list
list1 = extendList(10)
list2 = extendList(123, [])
list3 = extendList('a')
print('list1=%s' % list1)
print('list2=%s' % list2)
print('list3=%s' % list3)
==>list1=[10, 'a']
list2=[123]
list3=[10, 'a']

2. 二分查找:查找的必须是有序序列

例:lst = [11,22,33,44,55,66,77,88,99]

第一种:
lst = [11,22,33,44,55,66,77,88,99]
n = 66
count = 1
left = 0
right = len(lst)-1
while left <= right:
middle = (left + right)//2
if n > lst[middle]:
left = middle + 1
elif n < lst[middle]:
right = middle - 1
else:
print(count)
print(middle)
break
count += 1
else:
print("不存在")
结果:3 5

第二种:
lst = [11,22,33,44,55,66,77,88,99]
def fn(left,right,n):

if left > right:
return -1
else:
middle = (left + right) // 2
if n > lst[middle]:
left = middle+1
elif n < lst[middle]:
right = middle - 1
else:
return middle
return fn(left,right,n)
print(fn(0,len(lst)-1,66)) ==>5


第三种:
lst = [11,22,33,44,55,66,77,88,99]
def fn(lst,n):
left = 0
right = len(lst) - 1
middle = (right + left)//2
if right < left :
print("不存在")
return
if n > lst[middle]:
lst = lst[middle+1:]
elif n < lst[middle]:
lst = lst[:middle]
else:
print("存在")
return
fn(lst,n)
fn(lst,66) ==>存在

3.

def add(a,b):
return a+b
def test():
for r in range(4):
yield r
g = test()
for n in [2,10]:
g = (add(n ,i) for i in g )
print(list(g)) ==>[20, 21, 22, 23]
解题思路:for n in [2,10] g = (add(n ,i) for i in g)=====g = (add(10,i) for i in (add(10,i) for i in text()))

 

posted @ 2018-07-12 16:26  烟灰与黑  阅读(150)  评论(0编辑  收藏  举报