【永利官网ylg客户端】Python开垦【第五篇】:函数

全局变量和局部变量:

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。

当全局变量与局部变量同名时:在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。

 

name='reese'
def change_name():
    print('我的名字',name)
change_name()


def change_name():
    name='帅'
    print('我的名字',name)
change_name()
print(name)


def change_name():
    global name
    name='帅'
    print('我的名字',name)
change_name()
print(name)

#输出结果:
我的名字 reese
我的名字 帅
reese
我的名字 帅
帅

 #
如果函数内部无global关键字,优先读取局部变量,能读取全局变量,无法对全局变量重新赋值;

   
但对于可变类型(除数字、字符串、元祖,其他都可变),可对内部元素进行操作。

#
如果函数内部有global关键字,变量本质上是全局变量,可读取可赋值。

#
一般全局变量名用大写,局部变量名用小写。

 

  1. 函数基本语法及特性

  2. 参数与局部变量

  3. 返回值

2.2.5 偏函数

  functools 模块提供了很多功能,其中一个就是偏函数。

  当函数的参数个数太多,需要简化时,使用 functools.partial
创建一个偏函数,这个新的函数可以固定住原函数的部分参数,从而调用更简单。

语法结构:

from functools import partialfunc2 = partial(func, *args, **kwargs)  # 第一个参数:要固定的函数,第二个:原函数的位置参数,第三个:关键字参数

  第一个参数可以是自定义的函数,也可以是内置函数。

  int() 函数可以把字符串转换为整型,默认按照十进制转换:

>>> int('123')123

  int() 函数还额外提供一个 base 参数,如果传入 base,就可以做 N
进制转换:

>>> int('123', base=8)      # 按照八进制转换83

内置函数

  假如要转换大量的二进制字符串,每次都要传入
base,就会很繁琐。我们可以利用偏函数将 base=2
固定住,定义一个新的函数,每次只需要传入要转换的字符串即可:

>>> from functools import partial>>> int2 = partial(int, base=2)     # 将 base = 2 固定住>>> int2('100')     # 相当于 kw={'base': 2}  int('100', **kw)4

自定义函数

  当我们调用某个函数,已知某个参数的值时,可以将其固定住:

from functools import partialdef add:    return x % yadd2 = partial  # 自动将 5 作为 *args 的一部分放在最左边,也就是 5 % 100print)# 101
  • 形参:只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。
  • 实参:可以是常量、变量、表达式、函数等,在进行函数调用时,都必须有确定的值,以便把这些值传给形参。 

 

2.2 高阶函数

  函数式编程的两个特征:函数即变量,返回值是函数,只需满足其中一个条件,即可成为高阶函数。

def add:    return fprint(add(-5, 6, abs))11

  上面例子中,内置函数 abs 作为参数传入函数 add。

 

嵌套函数

1.5.1 函数和过程

  在 Python 中函数和过程是分开的,函数与过程(procedure)的区别:

  • 函数:有返回值
  • 过程:简单、特殊且无返回值

  严格来说 Python
没有过程,只有函数,因为即使没有返回值,也会默认返回一个 None。

def func():    print('Hi')res = func()printHiNone

 

4.递归

2.2.3 reduce 函数

  reduce(function, sequence[, initial])函数三个参数:第一个为函数,第二个为序列,第三个可选为初始值。

  Python3 把 reduce 函数集成到 functools
模块中,因此每次使用时,需要from functools import reduce。它可以把一个函数作用在一个序列上,这个函数必须接收两个参数。首先将序列中的前两个元素取出,传入函数中,返回值再与序列中接下来的元素做累积计算,直至序列中的每个元素都被循环。

  求列表中所有元素的乘积:

  常规:

nums = [1, 2, 3, 100]def reduce_test(func, array):    res = array.pop    for i in array:        res = func    return ress = reduce_test(lambda x,y: x*y, nums)print600

  reduce:

from functools import reducenums = [1, 2, 3, 100]res = reduce(lambda x,y : x*y, nums)print600

  首先将 nums 前两个元素,即 1、2 传入lambda x,y: x*y中,返回
x*y。再将 3 传入,最后将 100 传入,相当于*100)

指定初始值:

from functools import reducenums = [1, 2, 3, 100]res = reduce(lambda x,y : x*y, nums, 6)     # 相当于 *3)*100print3600

  累加计算:

from functools import reducereduce(lambda x,y: x+y, [1, 2, 3, 4, 5])15

reduce函数:

处理一个序列,然后把序列进行合并操作

#  reduce函数
from functools import reduce

num = [1, 2, 3, 4, 5]
print(reduce(lambda x, y: x + y, num, ))

#输出:
15

 

5.匿名函数

2.2.6 练习

  将列表中年龄小于等于 18 岁的人过滤出来。

people = [    {'name': 'rose', 'age': 18},    {'name': 'lila', 'age': 30},    {'name': 'tom', 'age': 60}]res = filter(lambda p: p.get('age') <= 18, people)print)[{'name': 'rose', 'age': 18}]

 

2.函数参数与返回值  

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

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

函数返回值

#面向过程
def func1():
    "test function1"
    print("hello test 1")

#面向函数
def func2():
    "test function2"
    print("hello test 2")
    return 0

def func3():
    "test function3"
    print("hello test 3")
    return 1,"haha",[1,3],{"name":"hl","age":"26"},("a","b")    #返回函数执行结果,返回的是一个元组

x=func1()
y=func2()
z=func3()
print(x,y,z)

 

2.2.2 filter 函数

  filter(function or None, iterable)函数有两个参数:第一个可以是函数也可以是
None,第二个为可迭代对象。

  • 第一个参数为函数:将序列中每个元素取出作为参数,传入第一个参数中,判断,并把为
    True 的值返回
  • 第一个参数为 None:将序列中为 True 的元素返回

  第一个参数为函数:

# 过滤掉以 123 结尾的名字names = ['rose_123', 'lila_123', 'john']def filter_123:    return not x.endswith('123')        # 返回没有以 123 结尾的名字res = filter(filter_123, names)listjohn

  使用 lambda 表达式简写:

res = filter(lambda x: not x.endswith('123'), names)list

  第一个参数为 None:

res = filter(None, [1, 2, 0, True, False])list[1, 2, True]

 

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

特性:

  1. 减少重复代码
  2. 使程序变的可扩展
  3. 使程序变得易维护

语法定义

def sayhi():        #函数名
    print("Hello,World!")

sayhi()        #函数调用

可以带参数

#下面这段代码
a, b = 5, 8
c = a ** b
print(c)

#改成用函数写
def calc(x, y):
    res = x ** y
    return res    #返回函数执行结果

c = calc(a, b)    #结果赋值给c变量
print(c)

 

1.3.2 位置参数和关键字参数

  普通的参数即为位置参数,在调用时实参必须与形参一一对应。而关键字参数,可以不用考虑位置的关系,只需要名字相同即可。

def func(name, words):    print(name: words)func('Hello', words='world')    # 第一个为位置参数,第二个为关键字参数func(words='World', name='Hello')   # 不用考虑位置

Tips:位置参数必须在关键字参数后面

 

本节内容

1.5.3 闭包

  闭包是函数式编程中的一个重要数据结构,Python
中认为如果在一个内部函数里,对在外部作用域的变量进行引用,那么这个内部函数就是闭包。

def fun1:    def fun2:        return x * y    return fun2a = fun1         # a 接收的是 fun2() 的内存地址printb = a            # a 相当于调用 fun2# 上述可以简写# res = fun1# print<function fun1.<locals>.fun2 at 0x00000000026F48C8>30

  从上面的例子可以看出,内部函数 fun2()对外部函数 fun1()的变量 x
进行了引用,那么 fun2()即是闭包。

  nonlocal 关键字

  但需要注意的是不能在外部函数外面调用内部函数,对外部函数的局部变量只能进行访问,不能修改。

def fun1():    name = 'rose'    def fun2():        name = 'tom'        return name    print    return fun2fun1rose        # 外部函数局部变量 name = ‘rose' 并没有被修改

  如果在内部函数中想修改外部函数的局部变量可以用 nonlocal
关键字,但是需要注意的是它不能修改全局变量。

def fun1():    name = 'rose'    def fun2():        nonlocal name       # 添加 nonlocal 关键字        name = 'tom'        return name    print    return fun2fun1tom     # 外部函数局部变量 name = ‘rose' 已经被修改

过程:就是没有返回值的函数

4. 递归

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

def calc(n):
    print(n)
    if n/2 > 0:
        return calc(int(n/2))
    print(n)

calc(10)

递归特性:

  1. ylg娱乐官网,必须有一个明确的结束条件

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

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

 

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

ylg娱乐官网 1ylg娱乐官网 2

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("33[31;1m找的数在mid[%s]左面33[0m" % dataset[mid])
            return binary_search(dataset[0:mid], find_num)
        else:# 找的数在mid右面
            print("33[32;1m找的数在mid[%s]右面33[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)

View Code

1.3.1 默认参数

  形参又分为:默认参数、位置参数、关键字参数以及可变长参数,而默认参数即在函数定义时默认赋予某个形参一个值。若函数调用时,不传入实参,函数使用默认值,否则使用实参。

def func:      # x 默认为 2    return x + 2res = func()        # 即使不传入实参函数也能正常运行print

 

局部变量和全局变量

在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。

全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。

当全局变量与局部变量同名时:

在定义局部变量的子程序内,局部变量起作用;在其它地方全局变量起作用。

age = 26
name = "hl"
list_1 = ["alex","oldboy"]
def change_name(age,name):
    print("before change:", age, name, list_1)
    age = 18
    name = "HL"
    list_1[0] = "Alex"
    print("after change:",age , name, list_1)

change_name(age,name)
print("globe",name)
print("globe",age)
print("globe",list_1)

#字符串,整数,局部变量的修改不会影响全局变量
#列表,字典,集合,局部变量的修改会影响全局变量

1.3.3 可变长参数

  可变长参数是一种参数组,它可以是多个参数,只需要在参数前加上星号即可。它可以增加函数可拓展性,当你不知道定义的函数需要定义几个参数时,使用它很方便。

  可变长参数分为:*args 和 **永利官网ylg客户端,kwargs两类:

  • *agrs:将参数们收集起来,打包成一个元组,再一一传递给函数使用
  • **kwargs:将参数们收集并打包成一个字典

*args

  *args 、**kwargs 是 Python
官方定义的参数名,也可以是其他名字,但是最好使用它,以便于辨认。

def func:    print    print('有 %d 个参数' % len    print('第三个参数是:', args[2])func('P', 'y', 't', 'h', 'o', 'n')func('Python', 123, '爬虫')

('P', 'y', 't', 'h', 'o', 'n')有 6 个参数第三个参数是: t('Python', 123, '爬虫')有 3 个参数第三个参数是: 爬虫

Tips:如果可变长参数后面还有参数,要将其定义为关键字参数,否则会被收集成可变长参数里面。建议在使用可变长参数时,可将其他参数设置为默认参数,或关键字参数,这样不易混淆。

def func(*args, extra=16):# def func(*args, extra):    print    printfunc#func(5,6, extra=18)1618

  星号既可用来收集打包参数,也可以用来“解包”参数。当传入的参数时列表、元组、字典以及集合时,可变长参数将会将其整个打包成只有一个元组的参数,而在其前面添加一个星号,就可以将里面的元素一个个都解出来。

def func:    printl = [1, 2, 3]t = d = {'name':'rose', 'age': 18}funcfuncfuncfuncfuncfunc

([1, 2, 3],),)({'name': 'rose', 'age': 18},)('name', 'age')

**kwargs

  另一种可变长参数就是
**kwargs,它将传入的实参打包成一个字典,同样地也支持 “解包”。

def func(x, **kwargs):    print    print    print('总共有 %d 个参数' % len    print('这些参数分别为:', kwargs)func(20, name='rose', age=18)

20{'name': 'rose', 'age': 18}总共有 2 个参数这些参数分别为: {'name': 'rose', 'age': 18}

  解包,当传入的参数是字典时:

def func(gender, **kwargs):    print    print    print('总共有 %d 个参数' % len    print('这些参数分别为:', kwargs)t = {'name': 'rose', 'age': 18}func('female', **t)

female{'name': 'rose', 'age': 18}总共有 2 个参数这些参数分别为: {'name': 'rose', 'age': 18}

  当既有 *args,又有 **kwargs,以及位置参数和位置参数时:

def func(gender, country='China', *args, **kwargs):    print(gender, country)    print    printfunc('male', 'America', 20, 30, name='rose', age=19)

male America{'name': 'rose', 'age': 19}

发表评论

电子邮件地址不会被公开。 必填项已用*标注