pythonpr函数_python函数

本章内容

1、函数

2、形参、实参

3、全局与局部变量

4、默认、位置、关键字参数

5、函数的递归

6、函数的嵌套

7、闭包函数

8、可变参数

9、函数的用法

10、匿名函数lambda

11、闭包函数

12、装饰器

13、高阶函数

14、列表生成式

15、生成器

16、迭代器

17、python内置函数

函数

使用函数的三大优点:

1、代码重用

2、保持一致性

3、可扩展性

return返回值:

1、当一个函数没有使用return显示定义的返回值时,python解释器会隐式的返回None

2、return一个值时,返回的是个object

3、ruturn多个值时,返回的是个tuple,里面的值可以是int、tuple、list、dict

函数是第一类对象的概念

1、函数可以被引用

f1 = func

f1()    #f1可以被执行

2、函数可以为参数,

3、函数的返回值可以是参数

4、函数可以作为容器类型元素,

cmd = {‘n’:func1,'b':func2}

形参、实参

def hello(a,b):       #这里的a,b属于形参

print 'hello,a,b'

a= 'python

b = 'jim'

hello(a,b)     #这里的的a,b属于实参

形参:只有在被调用的时候才会分配内存,调用结束后,立即释放内存,值仅在函数内部有效(局部变量)

实参:有确定的值的参数,所有的数据类型都可以被当做参数传递给函数。可以向函数内传递任意的数据类型。

python解释器有自己的内存回收机制,a='hello' ,在内存中开辟了一个内存空间,a 变量去引用这个内存的空间,相当于a是这快地址的门牌号,如果解释器看到这个内存空间没有门牌号的话,这个内存空间则会被释放。

全局与局部变量

在子程序中定义的变量成为局部变量,在程序的一开始定义的变量成为全局变量。全局变量的作用于整个程序,局部变量的作用于是定义该变量的子程序,当全局变量与局部变量同名时,在定义局部变量的子程序内,局部变量起作用,在其他地方全局变量起作用。

局部变量:作用域只在当前的函数内部,外部变量默认不能被函数内部修改的,只能引用,如果想在函数内部修改全区变量,必须golbal,但是强烈建议不要这么用,调试不方便。

上面说的不能修改的的变量类型是int str ,但是函数内部是可以修改列表,字典,集合,实例(class)

下列说明,变量为列表类型时不引用golbal就可以被修改。

names = ['jim','rose','jack']defchang_name():

names[0]= '吉姆'

print(names)

chang_name()print(names)

运行结果:

['吉姆', 'rose', 'jack']

['吉姆', 'rose', 'jack']

函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”:>>> a = abs # 变量a指向abs函数>>> a(-1)# 所以也可以通过a调用abs函数

默认、位置、关键字参数

默认参数

def hello(name='world',age=19):print 'my name is %s,and I am %s years old'%(name,age)

hello(name='Mr.python')------------------------------my nameis Mr.python,and I am 19years old

注:age我没有指定,则使用默认的值,19了,这个age就是设定了默认参数

位置参数

def hello(name='NB',age=20): #参数的默认值,调用时不声明,则使用默认参数

print 'my name is %s,%s years old'%(name,age)printhello()print hello('mypython',10) #这里面name和age对应的位置是不可以变动的。

关键字参数

defhello(name,age):print 'my name is %s,%s years old'%(name,age)print hello(age=1000,name='mypython') #这里可以通过关键字参数来随意的变更位置。

位置摆放:

默认参数,必须放在位置参数的后面

关键字参数,同上小练习:

输入一个数,计算阶乘

defjiecheng(number):for i in range(1,(number+1)):

sum= i *sumreturnsum

number= raw_input('please input a number')

请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。return 只返回一个值,如果有多个结果的话那会已(a,b.......)元组的形式返回

函数的递归

尾递归是指,在函数返回的时候,调用自身本身

利用递归的方式来计算阶乘。 就是函数自己调用自己。

defjiecheng(number):if number ==1:return 1

return number*jiecheng(number-1) #其原理就是自己乘以自己上一个数的阶乘。

print jiecheng(4)

小点:当明确的结束条件时,循环到999次时就会报错,不然一直跑下去会吃死内存。

递归特性:

1.必须有个明确的结束条件:

2.每次进入更深一层递归时,问题规模相比上次递归都应该减少

3.递归的效率不高

使用递归函数需要注意防止栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出

如果想定义一个什么事也不做的空函数,可以用pass语句:

def nop():

pass

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

pass还可以用在其他语句里,比如:

if age >= 18:

pass

缺少了pass,代码运行就会有语法错误。

函数的嵌套

分为两种:

1、嵌套定义:

小丽:

x = 1

def func1():

def func2():

def func3():

print (x)

return func3

return func2

func1()

嵌套的调用最多不要超过三层,不然的话可读性就会变差。

2、嵌套调用:一个调用另一个

小丽:

def my_max2(x,y): #这是比较两个数的大小,现在相比较四个数,咋办

if x > y:

return x

else:

return y

def my_max4(a,b,c,d): #划分为最细的情况其实就是两个数的比较

res1 = my_max2(a,b)

res2 = my_max2(res1,c)

res3 = my_max2(res2,d)

return res3

print(my_max4(100,2,-1,5))

闭包函数

下面由嵌套函数引出闭包函数

def func1():

x=1

def func2():

print (x)

return func2

f=func1()

f()

这就是一个闭包函数,没有看出什么可用之处吧,下面做个总结:

1.首先是func2中x变量的查找,只会在它的上一层查找,在函数外如果有x的赋值,也不会影响func2中的x这就相当于x与func2打包在一起了。

2.惰性运算,f=func1()后把func2()给了f,但是f没有运行,只有f+()后才会运行

根据这两个特性没有看到闭包函数的nb之处是吧,继续看小丽。

利用一会学到的爬虫来说明

from urllib.request import urlopen

def page(url):

def get():

return urlopen(url).read

return get

baidu = page('http://baidu.com/')

baidu()

只要一baidu()就会去爬百度的网页了,走到这还是没看出啥来是吧,那再来个python=page('http://python.org')   直接python就会去爬python的网站了,这就相当于个接口,你把python传给别人,别人直接调用就可以,不用关系再去定义python的网址,因为python的网址已经隐藏到函数中了。

话说我随用随掉不可以吗?

def get(url):

return urlopen(url).read

get('http://www.baidu.com')

其实直接get('http://www.baidu.com') 与baidu() 没啥区别,区别在于闭包函数已经把变量(url=www.baidu.com)存在函数中了,什么时候用什么时候加()调用就可以了。

可变参数

*收集的是位置参数,不能收集关键参数,收集到的是元组---此方法名为可变参数。

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple

** 收集的是关键字参数,收集到的是字典 ---又名关键字参数

关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

def hello(name = 'world',*para,**par):print 'my name is %s'%(name)printparaprintpar

hello('Mr.python',1,2,3,4,5,6,7,8,haha='haha',nihao='nihao')

结果:

my nameisMr.python

(1, 2, 3, 4, 5, 6, 7, 8)

{'nihao': 'nihao', 'haha': 'haha'}

[Finishedin 0.1s]

小用法:向函数中的*args传递列表。

def foo(x,y,*args):

print (x)

print(y)

print(args)

l = ['a','b']

foo(1,2,*l) #*l的用法,把列表分成单个的项然后传递给函数,相当于*['a','b'] = *args, 然后把*去掉,args = ['a','b'] 然后传递到函数中,函数再已('a','b')的形式输出

函数的用法

1.函数可以当作参数来使用:

defoperate(fn,name):returnfn(name)defsayhello(name):return 'hello %s!'%(name)defhehe(name):return 'hehe %s !'%(name)print operate(sayhello,'MR.python')print operate(hehe,'mr.python')-----------------------------------hello MR.python!

hehe mr.python !

[Finishedin 0.1s]

2.结合sorted来使用:

arr2 = [('192.168.1.1',2),('192.168.1.2',1),('192.168.1.3',3)]defsort_fn(arg):return arg[1] #取的是列表内元素,各个元组的下表是1的关键字

print sorted(arr2,key=sort_fn)

arr3= [{'name':'python','age':10},{'name':'C++','age':8},{'name':'java','age':9}]defsort_dict(arg):return arg['age'] #取的是列表内元素,各个字典的下表age的关键字的值

print sorted(arr3,key=sort_dict)---------------------------------------------------------------------------[('192.168.1.2', 1), ('192.168.1.1', 2), ('192.168.1.3', 3)]

[{'age': 8, 'name': 'C++'}, {'age': 9, 'name': 'java'}, {'age': 10, 'name': 'python'}]

注释的地方容易理解吗?感觉只能靠记

下面通过写个简单的sorted,来做个练习。

实现了list的排序,但是列表和字典的怎么实现呢?

这里面设计到函数的引用,请查看过程。

匿名函数lambda

下面引入lambda,lambda 只能实现简单的函数

def qu_key1(arr):

return arr['age']

翻译为lambda 就是 lambda arr:arr['age']

下面用lambda来替代。

下面在利用lambda实现list也可以比较的功能。

利用函数的默认值,key=lambda x:x 来实现对list的比较,实际上就是没有是通过lambda什么都没有操作的。

贴上代码:

def my_sort(arr,key=lambdax:x):

length=len(arr)for i in range(length-1):for j in range(length-1-i):if key(arr[j]) > key(arr[j+1]):

arr[j],arr[j+1] = arr[j+1],arr[j]returnarr#def qu_key(arr):#return arr[1]

#def qu_key1(arr):#return arr['age']

a= [6,5,4,3,3,2,1]printmy_sort(a)

arr2= [('192.168.1.1',2),('192.168.1.2',1),('192.168.1.3',3)]print my_sort(arr2,key=lambda x:x[1])

arr3= [{'name':'python','age':10},{'name':'C++','age':8},{'name':'java','age':9}]print sorted(arr3,key=lambda x:x['age'])--------------------------------------------------------------------------[1, 2, 3, 3, 4, 5, 6]

[('192.168.1.2', 1), ('192.168.1.1', 2), ('192.168.1.3', 3)]

[{'age': 8, 'name': 'C++'}, {'age': 9, 'name': 'java'}, {'age': 10, 'name': 'python'}]

看到上面的代码是不是有疑惑,那lambda是什么呢?先来个简单的例子,首先得明确一点lambda其实就是个函数:

g= lambda x:x+1

print g(1)>>2当然,你也可以这样使用:lambda x:x+1(1)>>>2

可以这样认为,lambda作为一个表达式,定义了一个匿名函数,上例的代码x为入口参数,x+1为函数体,用函数来表示为:

1 def g(x):

2 return x+1

lambda 也可以多参数:

lambda x,y:x+y

非常容易理解,在这里lambda简化了函数定义的书写形式。是代码更为简洁,但是使用函数的定义方式更为直观,易理解。

lambda if 判断运算:

for i in map(lambda x:x*2 if x>5 else x-1 [1,2,3,4,5,6,7,8,9]):

注:lambda支持到最复杂的运算是三元运算,更复杂的运算不支持。

装饰器

装饰器:本质上是个函数,(装饰其他的函数)就是为了其他函数添加附加的功能。

1.最好不要修改源代码,有课能用的地方很多,错一点,会有连带反应。

2.不要更改调用的方式。

这不能动那不能动,想添加功能咋办?用装饰器喽。

原始装饰器:

标准格式:

defzhuangsq(fn):defnew_hello(name):print 'good morning' +namereturn 'haha' +fn(name)returnnew_hello#装饰起代码必须在上面,用@zhuangsq替代了上面的 hello = zhuangsq(hello)

@zhuangsqdefhello(name):return 'nice to meet you' +nameprint hello('MR.python')

哈哈,到了这里有一个参数或者不传递参数的装饰器都已经搞定了,但是如果有多个参数呢,再如果加上加上装饰器后再调用hello() 其实就是调用的new_hello()这个函数了,位置参数呢,哪有如何接受呢?别怕在new_hello()中用*args,**kwargs接受,但是接受了是个元组和字典啊,如何才能让内部的fn函数接受呢?哈哈,还是用*args,**kwargs,这里就会他元组和字典里的这些想

全部独立的分开。

效果如下:

new_hello(*arge,**kwargs):

print 'good morning' + name

return 'haha' + fn(*args,**kwargs)

如果在hello()函数中有return呢?现在我们知道装饰后其实就是运行的new_hello,这时候咋办new_hello中也需要return,那return什么?return fn这个函数。其实也就是hello()

装饰器之return 小例:

1 user,passwd = 'alex','12345'

2

3 defauth(func):4 def wrapper(*args,**kwargs):5 username = input('username:').strip()6 password = input('password:').strip()7

8 if user == username and passwd ==password:9 print('\033[32;1m User has passed authentication \033[0m')10 res = func(*args,**kwargs)11 returnres12 else:13 print('\033[31;1m User does not exit! \033[0m')14

15 returnwrapper16

17

18 @auth19 deflogin():20 print('This is login,I will login')21 return 'I love this web!!'

22

23 @auth24 defbbs():25 print('This is bbs')26

27 defindex():28 print('this is index')29

30 print(login()) #函数return有返回值的话需要print,把结果打印出来

31 bbs()32 index()33

34

35

36 运行结果:37 username:alex38 password:12345

39 User has passed authentication40 This islogin,I will login41 I love this web!!42 username:alex43 password:12345

44 User has passed authentication45 This isbbs46 this is index

return 使用

升级一下,如果使用装饰器,一部分页面需要本地验证,另一方面需要另外一套系统来做验证,那又能怎么办呢? --->对装饰器再添加一层!

1 defauth(auth_type):2 print('auth func is',auth_type)3 defouter_wrapper(func):4 def wrapper(*args, **kwargs):5 username = input('username:').strip()6 password = input('password:').strip()7

8 if user == username and passwd ==password:9 print('\033[32;1m User has passed authentication \033[0m')10 res = func(*args, **kwargs)11 returnres12 else:13 print('\033[31;1m User does not exit! \033[0m')14

15 returnwrapper16 returnouter_wrapper17

18 @auth(auth_type='local')19 deflogin():20 print('This is login,I will login')21 return 'I love this web!!'

22

23 @auth(auth_type='ldap')24 defbbs():25 print('This is bbs')26

27 defindex():28 print('this is index')29

30 print(login())31 bbs()32 index()33

34

35

36 运行结果:37

38 auth func islocal39 auth func isldap40 username:alex41 password:12345

42 User has passed authentication43 This islogin,I will login44 I love this web!!45 username:alex46 password:12345

47 User has passed authentication48 This isbbs49 this is index

装饰器中添加参数

高阶函数

注:其是调用ads函数的内存地址。

满足一下两个条件即可称之为高阶函数:

1、把函数的内存地址当做参数传给另外一个函数

2、一个函数把另外一个函数当做返回值返回。

高阶函数  +  嵌套函数  =  装饰器

列表生成式

[ i*2  for i in range(10) ]

转换为普通的代码:

a = []

for i in range(10):

a.append(i*2)

列表生成式的作用,就是使代码更简洁

先来个小练习a= [1,2,3,4,5,6,7,8,9] 里面的每个数值都加1

1.可以利用lambda:

map(lambda x:x+1,a)

2.第二种方法:根据每个数的索引来对每个数+1运算

注意:这时候不能用列表的index来去索引,因为如果有重复的,它只会取第一个,需要用enumerate

a= [1,2,3,4,5,6,7,8,9]

for index,i in enumerate(a):

a[index] = i+1

print(a)

3.列表生成式

a= [1,2,3,4,5,6,7,8,9]

b = [i+1 for i in a]

列表生成式最大的运算也是三目运算

a= [1,2,3,4,5,6,7,8,9]

b= [i*i if i >5 else i for i in a]

生成器

通过列表生成式,我们可以直接创建一个列表,但是,受到内存的限制,列表容量肯定是有限的,而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面的几个元素,那后面绝大数元素占用的空间就拜拜浪费了。

所以,如果列表元素可以按照某种算法来推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间,

在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个

>>> L = [x * x for x in range(10)]>>> L [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range(10))>>> g at 0x104feab40>

创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?如果要一个一个打印出来,可以通过generator的next()方法:

>>>g.next() 0>>> g.next() 1

>>> g.next() 4

>>> g.next() 9

>>> g.next() 16

>>> g.next() 25

>>> g.next() 36

>>> g.next() 49

>>> g.next() 64

>>> g.next() 81

>>>g.next()

Traceback (most recent call last): File"", line 1, in StopIteration

next(a)python2中的方法

a.__next__()python3中的方法

我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。当然,上面这种不断调用next()方法实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:

>>> g = (x * x for x in range(10))>>> for n ing:

...printn ...

01 4 9 16 25 36 49 64 81

所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。这里我们看到,这个迭代器只支持到三元运算,其实他本事不止这些,复杂的形式用函数的方式来实现:

斐波那契数

deffib(max):

n,a,b=0,0,1

while n

a,b= b,a+b

n+=1

return 'done'fib(10)

这里把print (b) 改为yeild就变为生成器了,可以利用for循环去调用,每想调用一个就调用一个,如果想执行其他的,期间也可以执行,这就是他的作用,现用现执行,不浪费内存,这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

现改之为生成器样式

deffib(num):

n,a,b= 0,0,1

while n

a,b= b,a+b

n+=1

return 'done'd= fib(10)whileTrue:try:print(d.__next__())exceptStopIteration as e:print(e)print('Generator return value',e.value)break

这里为什么要用try去捕获异常呢,因为使用next方法,执行到最后会抛出一个 StopIteration 的异常

利用yield来模拟单线程并发:

1 importtime2

3 defconsumer(name):4 print("%s 准备来吃包子了"%name)5

6 whileTrue:7 baozi = yield

8

9 print('包子[%s]来了,被[%s]吃了'%(baozi,name))10

11 defproducer(name):12 c = consumer('A')13 c2 = consumer('B')14 c.__next__()15 c2.__next__()16 print('lz开吃吃包子了')17 for i in range(10):18 time.sleep(1)19 print('做一个包子,分成两半')20 c.send(i) #传递给yield一个值,

21 c2.send(i)22

23

24 producer('Alex')25

26 执行结果:27 会每次两个客户同事输出,效果像并发28

29 A 准备来吃包子了30 B 准备来吃包子了31 lz开吃吃包子了32 做一个包子,分成两半33 包子[0]来了,被[A]吃了34 包子[0]来了,被[B]吃了35 做一个包子,分成两半36 包子[1]来了,被[A]吃了37 包子[1]来了,被[B]吃了38 做一个包子,分成两半39 包子[2]来了,被[A]吃了40 包子[2]来了,被[B]吃了41 做一个包子,分成两半42 包子[3]来了,被[A]吃了43 包子[3]来了,被[B]吃了44 做一个包子,分成两半45 包子[4]来了,被[A]吃了46 包子[4]来了,被[B]吃了47 做一个包子,分成两半48 包子[5]来了,被[A]吃了49 包子[5]来了,被[B]吃了50 做一个包子,分成两半51 包子[6]来了,被[A]吃了52 包子[6]来了,被[B]吃了53 做一个包子,分成两半54 包子[7]来了,被[A]吃了55 包子[7]来了,被[B]吃了56 做一个包子,分成两半57 包子[8]来了,被[A]吃了58 包子[8]来了,被[B]吃了59 做一个包子,分成两半60 包子[9]来了,被[A]吃了61 包子[9]来了,被[B]吃了

View Code

迭代器

我们已经知道,可以直接作用于for循环的数据类型有以下几种:

一类是集合数据类型,如list、tuple、dict、set、str等;

一类是generator,包括生成器和带yield的generator function。

这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。

可以使用isinstance()判断一个对象是否是Iterable对象:

>>>isinstance([], Iterable)

True>>>isinstance({}, Iterable)

True>>> isinstance('abc', Iterable)

True>>> isinstance((x for x in range(10)), Iterable)

True>>> isinstance(100, Iterable)

False

而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。

*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。

可以使用isinstance()判断一个对象是否是Iterator对象:

>>> from collections importIterator>>> isinstance((x for x in range(10)), Iterator)

True>>>isinstance([], Iterator)

False>>>isinstance({}, Iterator)

False>>> isinstance('abc', Iterator)

False

生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

把list、dict、str等Iterable变成Iterator可以使用iter()函数:

>>>isinstance(iter([]), Iterator)

True>>> isinstance(iter('abc'), Iterator)

True

你可能会问,为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

在python3中 range 就是使用的迭代器封装的,而python2中不是,xrange是它的迭代方法,

小结

凡是可作用于for循环的对象都是Iterable类型;

凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

实际上完全等价于:

# 首先获得Iterator对象:

it = iter([1, 2, 3, 4, 5])

# 循环:

while True:

try:

# 获得下一个值:

x = next(it)

except StopIteration:

# 遇到StopIteration就退出循环

break

python 内置函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值