python函数

函数是什么?

函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,在C中只有function,在Java里面叫做method

定义

函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可

在python如何具体定义一个函数

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
#函数
def func1():
    """testing1"""
    print('in the func1')
    return 0

#过程
def func2():
    '''testing2'''
    print('in the func2')

x=func1()
y=func2()

print('from func1 return is %s' %x)
print('from func2 return is %s' %y)
in the func1
in the func2
from func1 return is 0
from func2 return is None
import time


def logger():
    time_format = '%Y-%m-%d %X'
    time_current = time.strftime(time_format)
    with open('a.txt','a+') as f:
        f.write('%s end action\n' % time_current)


def test1():
    print('in the test1')
    logger()
    

def test2():
    print('in the test2')
    logger()
    
    
def test3():
    print('in the test3')
    logger()


test1()
test2()
test3()

函数返回值

def test1():
    """
    空函数
    """
    pass

def test2():
    return 0

def test3():
    return 0,'hello',['a','b','c'],{'name':'alex'}

def test4():
    """
    返回值为函数test2,test3
    """
    return  test2 ,test3


x = test1()
y = test2()
z = test3()
a = test4()

print('from test1 return is %s' %x)
print('from test2 return is %s' %y)
print('from test3 return is first: %s ,second: %s , third : %s , fourth :%s' %(z[0],z[1],z[2],z[3]))
print(a)
a[1]()


from test1 return is None
from test2 return is 0
from test3 return is first: 0 ,second: hello , third : ['a', 'b', 'c'] , fourth :{'name': 'alex'}
(<function test2 at 0x7efe4c0dcb70>, <function test3 at 0x7efe4c1596a8>)





(0, 'hello', ['a', 'b', 'c'], {'name': 'alex'})

函数参数

形参(parameter)变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量

实参(argument)可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值

关键参数

给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可

关键参数必须放在位置参数之后

def test(x,y,z):
    """
    :param x:
    :param y:
    :param z:
    :return:None
    """
    print([x,y,z])


a = test(3,z=2,y=6)
b = test(z=2,y=6,x=3) ##与形参顺序无关
c = test(3,6,2)  ##与形参一一对应
print(a,b,c)
[3, 6, 2]
[3, 6, 2]
[3, 6, 2]
None None None

默认参数

默认参数特点:调用函数的时候,默认参数非必须传递

def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

这样,当我们调用power(5)时,相当于调用power(5, 2):

print(power(5))
print(power(5,2))
25
25

而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)

print(power(5,3))
125

可变参数

可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个

我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

但是调用的时候,需要先组装出一个list或tuple:

print(calc([1, 2, 3]))
print(calc((1, 3, 5, 7)))
14
84

如果利用可变参数,调用函数的方式可以简化成这样:

 calc(1, 2, 3)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-23-a264e91a6ec5> in <module>
----> 1 calc(1, 2, 3)


TypeError: calc() takes 1 positional argument but 3 were given

所以,我们把函数的参数改为可变参数:

*args:接受N个位置参数,转换成元组形式

def calc(*numbers):
    print(type(numbers),numbers)
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

print(calc(1, 2, 3))
print(calc([1, 2, 3]))
<class 'tuple'> (1, 2, 3)
14
<class 'tuple'> ([1, 2, 3],)



---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-37-96186b5ccf26> in <module>
      7 
      8 print(calc(1, 2, 3))
----> 9 print(calc([1, 2, 3]))


<ipython-input-37-96186b5ccf26> in calc(*numbers)
      3     sum = 0
      4     for n in numbers:
----> 5         sum = sum + n * n
      6     return sum
      7 


TypeError: can't multiply sequence by non-int of type 'list'
nums = [1, 2, 3]
print(calc(nums[0], nums[1], nums[2]))
<class 'tuple'> (1, 2, 3)
14

所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

print(calc(*[1, 2, 3]))
<class 'tuple'> (1, 2, 3)
14
def printinfo( arg1, *vartuple ):
    """
     打印任何传入的参数
    """
    print ("输出: ")
    print (arg1)
    print (vartuple)
    
printinfo( 70, 60, 50 )
输出: 
70
(60, 50)

还可以有一个**kwargs

会把多传入的参数变成一个dict形式

def test2(**kwargs):
    print(kwargs)
    print(kwargs['name'])
    print(kwargs['age'])

test2(name='alex',age=8,sex='F')

{'name': 'alex', 'age': 8, 'sex': 'F'}
alex
8
test2(**{'name':'alex','age':8})
{'name': 'alex', 'age': 8}
alex
8

参数组合

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

    
#*后面的参数被视为命名关键字参数
def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
f1(1, 2, 3, "a", "b")
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}

变量作用域

Python的作用域一共有4种,分别是:

  • L (Local) 局部作用域
  • E (Enclosing) 闭包函数外的函数中
  • G (Global) 全局作用域
  • B (Built-in) 内建作用域

以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。

x = int(2.9)  # 内建作用域
 
g_count = 0  # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域
        

Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:

if True:
    msg = 'I am from Runoob'
print(msg)
I am from Runoob

实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。

如果将 msg 定义在函数中,则它就是局部变量,外部不能访问:

def test():
    msg_inner = 'I am from Runoob'
print(msg_inner)
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-76-0d1b8ba12928> in <module>
      1 def test():
      2     msg_inner = 'I am from Runoob'
----> 3 print(msg_inner)


NameError: name 'msg_inner' is not defined

全局变量和局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:

a = 10
def test():
    a = a + 1
    print(a)
test()
---------------------------------------------------------------------------

UnboundLocalError                         Traceback (most recent call last)

<ipython-input-90-4212688e84b0> in <module>
      3     a = a + 1
      4     print(a)
----> 5 test()


<ipython-input-90-4212688e84b0> in test()
      1 a = 10
      2 def test():
----> 3     a = a + 1
      4     print(a)
      5 test()


UnboundLocalError: local variable 'a' referenced before assignment
a = 10
def test(a):
    a = a + 1
    print(a)
test(a)
11

total = 0 # 这是一个全局变量
# 可写函数说明
def sum( arg1, arg2 ):
    #返回2个参数的和."
    total = arg1 + arg2 # total在这里是局部变量.
    print ("函数内是局部变量 : ", total)
    return total
 
#调用sum函数
sum( 10, 20 )
print ("函数外是全局变量 : ", total)
函数内是局部变量 :  30
函数外是全局变量 :  0
name = "sun1"
 
def change_name():
    name = "sun2"
 
    def change_name2():
        name = "sun3"
        print("第3层打印",name)
 
    change_name2() #调用内层函数
    print("第2层打印",name)
 
 
change_name()
print("最外层打印",name)
第3层打印 sun3
第2层打印 sun2
最外层打印 sun1

global 和 nonlocal关键字

num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num) 
    num = 123
    print(num)
fun1()
print(num)
1
123
123

如果要修改嵌套作用域(enclosing 作用域,外层;非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:

name = "sun1"

#内嵌函数
def change_name():
    name = "sun2"
 
    def change_name2():
        nonlocal name
        name = "sun3"
        print("第3层打印",name)
 
    change_name2() #调用内层函数
    print("第2层打印",name)
 
 
change_name()
print("最外层打印",name)
第3层打印 sun3
第2层打印 sun3
最外层打印 sun1

如果要修改外层全局作用域(非enclosing 作用域)中的变量则需要 global 关键字了,如下实例:

name = "sun1"
 
def change_name():
    name = "sun2"
 
    def change_name2():
        global name
        name = "sun3"
        print("第3层打印",name)
 
    change_name2() #调用内层函数
    print("第2层打印",name)
 
 
change_name()
print("最外层打印",name)
第3层打印 sun3
第2层打印 sun2
最外层打印 sun3
name = "sun1"
 
def change_name():
    global name
    name = "sun2"
 
    def change_name2():
        global name
        name = "sun3"
        print("第3层打印",name)
 
    change_name2() #调用内层函数
    print("第2层打印",name)
 
 
change_name()
print("最外层打印",name)
第3层打印 sun3
第2层打印 sun3
最外层打印 sun3

闭包函数

闭包是一种满足特定要求的内嵌函数,当子函数体内有对母函数体定义的变量的引用时我们称这个子函数为一个闭包

g_count = 0  # 全局作用域
def outer():
    o_count = 2  # 闭包函数外的函数中
    def inner():
        i_count = 4  # 局部作用域
        print(i_count,o_count,g_count)
        return i_count * o_count
    return inner()

a= outer()
print(a)
4 2 0
8
g_count = 0  # 全局作用域
def outer():
    o_count = 2  # 闭包函数外的函数中
    def inner():
        i_count = 4  # 局部作用域
        print(i_count,o_count,g_count)
        return i_count * o_count
    return inner

a= outer()
print(a)
print(a())
<function outer.<locals>.inner at 0x7efe4c08cd08>
4 2 0
8

递归

在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数

def fun1(x):
    fun1(x-1)
    
def fun2(x):
    if x > 0:
        fun2(x+1)


def fun3(x):
    if x > 0:
        print(x)
        fun3(x-1)
        

def fun4(x):
    if x > 0:
        fun4(x-1)
        print(x)

def calc(n):
    print(n)
    if n//2 ==0:
        
        return n
    return calc(n//2)
 
calc(10)
10
5
2
1





1
def calc(n):
    
    if n//2 ==0:  
        return n
    calc(n//2)
    print(n)


print(calc(10))
2
5
10
None

递归函数实际应用案例,二分查找

data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
 
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 :# 找的数在mid左面
            print("\033[31;1m找的数在mid[%s]左面\033[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:# 找的数在mid右面
            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)
 
 
binary_search(data,66)
[1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35]
[32;1m找的数在mid[18]右面[0m
[20, 21, 22, 23, 30, 32, 33, 35]
[32;1m找的数在mid[30]右面[0m
[32, 33, 35]
[32;1m找的数在mid[33]右面[0m
[35]
没的分了,要找的数字[66]不在列表里

匿名函数

匿名函数就是不需要显式的指定函数

匿名函数主要是和其它函数搭配使用


print('lambda匿名函数'.center(50,"*"))
f = lambda a, b, c: a + b + c
print(f(1, 2, 3))
********************lambda匿名函数********************
6
f = lambda a,b,c:a+b+c 中的关键字lambda表示匿名函数
冒号:之前的a,b,c表示它们是这个函数的参数。
匿名函数不需要return来返回值,表达式本身结果就是返回值
print('无参匿名函数'.center(50,"*"))
t = lambda : True
print(t())
**********************无参匿名函数**********************
True

print('带参匿名函数'.center(50,"*"))
t = lambda x: x**3
print(t(1))
t = lambda x,y,z:x+y+z
print(t(1,2,3))
t = lambda x,y=3: x*y
print(t(1))
print(t(1,2))
t = lambda *z:z
print(t('Testing1', 'Testing2'))
t = lambda **Arg: Arg
print(t(a=1,b=2))
**********************带参匿名函数**********************
1
6
3
2
('Testing1', 'Testing2')
{'a': 1, 'b': 2}
print('直接后面传递实参'.center(50,"*"))
t= (lambda x,y: x if x> y else y)(101,102)
print(t)

t= (lambda x:x**2)(3)
print(t)

*********************直接后面传递实参*********************
102
9

lambda嵌套到普通函数中,lambda函数本身做为return的值

print('嵌套使用'.center(50,"*"))
def increment(n):return lambda x: x+n
f=increment(4)
print(f)
print(f(2))

def say():
    title = 'Sir,'
    action = lambda x: title + x
    return action
act = say()
print(act('Smith!'))
***********************嵌套使用***********************
<function increment.<locals>.<lambda> at 0x7fd9d4073840>
6
Sir,Smith!

filter函数

filter(function, sequence)

对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String/Tuple(取决于sequence的类型)返回:

print('filter(function, sequence)'.center(50,"*"))
def f(x):
    return x % 2 != 0 and x % 3 != 0
t= filter(f, range(2, 25))
print(t)
print(list(t))
************filter(function, sequence)************
<filter object at 0x7fd9c67e4128>
[5, 7, 11, 13, 17, 19, 23]

找出1到10之间的奇数

t= filter(lambda x:x%2!=0,range(1,11))
print([i for i in t])
[1, 3, 5, 7, 9]
t= filter(lambda x:x%3==0,[1,2,3,4,5,6])
# print(list(t))
print([i for i in t])
[3, 6]

map函数

map(function, sequence)

对sequence中的item依次执行function(item),见执行结果组成一个List返回:

print('map(function, sequence)'.center(50,"*"))
def cube(x): return x*x*x
t=  map(cube, range(1, 11))
print(t)
print(list(t))
*************map(function, sequence)**************
<map object at 0x7fd9c67e80b8>
[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]
def cube(x) : return x + x
t=  map(cube , "abcde")
print(list(t))
def add(x, y): return x+y
t=  map(add, range(8), range(8))
print(list(t))
['aa', 'bb', 'cc', 'dd', 'ee']
[0, 2, 4, 6, 8, 10, 12, 14]

reduce函数

reduce(function, sequence, starting_value)

reduce函数会对参数序列中元素进行累积

对sequence中的item顺序迭代调用function,如果有starting_value,还可以作为初始值调用,例如可以用来对List求和:

#在Python 3里,reduce()函数已经被从全局名字空间里移除了,
#它现在被放置在fucntools模块里 用的话要 先引 入
from functools import reduce

def add(x,y): return x + y
t= reduce(add, range(1, 11))
print(t)
55
t = reduce(add, range(1, 11), 20)
print(t)
75
#求1到10的累加
t= reduce(lambda x,y:x+y,range(1,11))
print(t)
55

高阶函数

变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数

def add(a,b,f):

    return f(a)+f(b)

res = add(3,-6,abs)
print(res)

实例练习

例01: 字符串联合,有默认值,也可以x=(lambda…)这种格式

x = (lambda x="Boo",y="Too",z="Zoo": x+y+z)
print(x("Foo"))
FooTooZoo

例02: 和列表联合使用

x = L = [lambda x:x**2,lambda x:x**3,lambda x:x**4]
print([f(2) for f in L])
[4, 8, 16]
#也可以如下面这样调用
print(L[0](3))
9

例03: 和字典结合使用

key = 'B'
dic = { 'A': lambda: 2*2, 'B': lambda: 2*4, 'C': lambda: 2*8}
print(dic[key]())
8

例04: 求最小值

lower = lambda x,y: x if x<y else y
t= lower('aa','ab')
print(t)
aa

例05: 和map及list联合使用

import sys
showall = lambda x:list(map(sys.stdout.write,x))
a = showall(['Jerry\n','Sherry\n','Alice\n'])
b = showall(['Jerry','Sherry','Alice'])
print("\n",a,b)
Jerry
Sherry
Alice
JerrySherryAlice
 [None, None, None] [None, None, None]

例06: lambda和map联合使用

out = lambda *x: sys.stdout.write(' '.join(map(str,x)))
a = out('This','is','a','book!\n')
print(a)
This is a book!
None

例07: 判断字符串是否以某个字母开头

print((lambda x: x.startswith('B'))('Bob'))
Names = ['Anne', 'Amy', 'Bob', 'David', 'Carrie', 'Barbara', 'Zach']
B_Name= filter(lambda x: x.startswith('B'),Names)
print(list(B_Name))

True
['Bob', 'Barbara']

例08:lambda和map,filter联合使用

squares = map(lambda x:x**2,range(10))
filters = filter(lambda x:x>5 and x<50,squares)
print(list(filters))
[9, 16, 25, 36, 49]

例09:lambda和sorted联合使用

#按death名单里面,按年龄来排序
#匿名函数的值返回给key,进来排序
death = [ ('James',32),('Alies',20),('Wendy',25)]
t= sorted(death,key=lambda age:age[1])
print(t)
[('Alies', 20), ('Wendy', 25), ('James', 32)]

例10. 求字符串每个单词的长度

sentence = "Welcome To Beijing!"
words = sentence.split()
lengths = map(lambda x:len(x),words)
print(list(lengths))
[7, 2, 8]
print(list(map(lambda x:len(x),'Welcome To Beijing!'.split())))
[7, 2, 8]
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值