Python基础(四)函数

一、函数简介

  • 函数也是一个对象。
  • 对象是内存中专门用来存储数据的一块区域。
  • 函数用来保存一些可执行代码,并且在需要时,可以重复调用。
  • 创建函数:

def 函数名( [形参1,形参2,.....形参n ] ):

        代码块

函数名必须要符合标识符规范

        可以包含字母、数字、下划线,但不能以数字开头。

  • 函数中保存的代码,需要被调用才会执行。 
  • 调用函数:

函数对象()

二、函数参数

  • 定义函数时,可以在函数名后定义数量不等的形参,多个形参以,隔开。

2.1 形参的定义

  • 定义形参时,可以为形参指定默认值。若调用者没有传值,则使用默认值。
def fn(a=5, b=10):
    print("a=", a)
    print("b=", b)

2.2 实参的传递

  • 位置参数
    • 将对应位置的实参赋值给对应的形参。
fn(100, 200)
  • 关键字参数
    • 可以不按照形参定义的顺序,而是根据参数名传递。
fn(b=222, a=111)
  • 位置参数和关键字参数可以混合使用
    • 混合使用时,必须将位置参数写在前面
def fn(a=5, b=10, c=15):
    print("a=", a)
    print("b=", b)
    print("c=", c)


fn(3, 6, c=9)

2.3 实参的类型

  • 函数在调用时,解析器不会检查实参的类型。
  • 实参可以传递任意类型的对象。
  • 如果形参执行的是一个对象,通过形参修改对象时,会影响到所有指向该对象的变量。

2.4 不定长参数

  •  在形参前边加上*,这样这个形参将会获取到所有的实参。

  • 它会将所有的实参保存到一个元组中。

def sum(*a):
    result = 0
    # 遍历元组
    for n in a:
        result += n
    print(result)


sum(1, 2)
sum(5, 15, 25)
sum(6, 66, 666)
  • 带*的形参只能有一个。
  • 可以和其他参数配合使用。 
def fn(a,b,*c):
    print("a=",a)
    print("b=",b)
    print("c=",c)


fn(1,2,3,4,5)
# a= 1
# b= 2
# c= (3, 4, 5)
  • 如果在形参开头直接写一个*,则要求所有的参数必须以关键字形式传递。
def fn(*, a, b, c):
    print("a=", a)
    print("b=", b)
    print("c=", c)

fn(a=1, b=2, c=3)
  •  *形参只能接受位置参数,不能接收关键字参数。
  • **形参可以接受其他的关键字参数,它会将这些参数统一保存到字典中。
    • 字典的key就是参数的名,value就是参数的值
  • **形参只能有1个,且必须在所有参数最后
def fn(b, c, **a):
    print("a=", a)
    print("b=", b)
    print("c=", c)


fn(b=1, d=2, c=3, e=10, f=20)

# a= {'d': 2, 'e': 10, 'f': 20}
# b= 1
# c= 3

2.5 参数的解包(拆包)

  • 传递实参时,可以在序列类型的参数前添加*,这样会自动将序列解包,传递给形参。
  • 要求序列中元素的个数必须和形参个数一致。
def fn(a, b, c):
    print("a=", a)
    print("b=", b)
    print("c=", c)


t = (10, 20, 30)
fn(*t)
  • 通过**对字典进行解包。
d = {"a": 100, "b": 200, "c": 300}
fn(**d)

三、函数返回值

  • return 后面跟什么值,函数就返回什么值。
  • 返回值可以是任意对象,甚至可以是函数。
  • return 后的代码不会执行。
def fn():
    def fn2():
        print("hello")

    return fn2()

四、文档字符串(doc str)

  • help() 是python的内置函数,可以查询函数的用法。

help(函数对象)

  • 在定义函数时,可以在函数内部编写文档字符串,即为函数的说明。
    • 当编写了文档字符串时,调用help()就可以来查看函数的说明。
    • 直接在函数的第一行写一个字符串,就是文档字符串。
def fn(a:int, b:str, c:bool) ->int:
    '''
    :param a:作用,类型,默认值...
    :param b:作用,类型,默认值...
    :param c:作用,类型,默认值...
    :return:10
    '''
    return 10

def fn(a:int, b:str, c:bool) ->int: 

表示希望传参的类型 a为int,b为str,c为bool,但是不强制

返回值时int 

五、作用域与命名空间

5.1 作用域(scope)

  • Python中共有2中作用域
    • 全局作用域
      • 在程序执行时创建,在程序执行结束时销毁。
      • 所有函数以外的区域都是全局作用域。
      • 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置访问。
    • 函数作用域
      • 在函数调用时创建,在调用结束时销毁。
      • 函数每调用一次就会产生一个新的作用域。
      • 在函数作用域中定义的变量,都是局部变量,它只能在函数的内部被访问。
  • 在函数中为变量赋值,默认都是为局部变量赋值。
a = 20
def fn():
    a = 10
    print("函数内部a=", a)

fn()
print("函数外部a=", a)

# 输出结果
# 函数内部a= 10
# 函数外部a= 20
  • 如果希望在函数内部修改全局变量,则需要使用关键字global来声明变量。 
a = 20
def fn():
    global a
    a = 10
    print("函数内部a=", a)

fn()
print("函数外部a=", a)

# 输出结果
# 函数内部a= 10
# 函数外部a= 10

5.2 命名空间(namespace)

  • 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
  • 每一个作用域都会有一个它对应的命名空间。
    • 全局命名空间用来保存全局变量。
    • 函数命名空间用来保存函数中的变量。
  • 命名空间实际上就是一个字典,是一个专门用来存储变量的字典。

  • locals():来获取当前作用域的命名空间
    • 如果在全局作用域中调用locals()则获取全局命名空间;
    • 如果在函数作用域中调用locals()则获取函数命名空间;
    • 返回一个字典。
  • globals():在任意位置获取全局命名空间

a = 100
scope = locals()  # 当前命名空间
print(scope) 
#{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CF5B1F6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:\\developer\\idea\\workspace\\PythonBase\\lesson_05\\code\\06.作用域与命名空间.py', '__cached__': None, 'a': 100, 'scope': {...}}


def fn4():
    a = 10
    scope = locals()  # 函数内部命名空间
    print(scope) # {'a': 10}

    global_scope = globals()  # 全局命名空间
    print(global_scope)
    #{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001CF5B1F6CD0>, '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:\\developer\\idea\\workspace\\PythonBase\\lesson_05\\code\\06.作用域与命名空间.py', '__cached__': None, 'a': 100, 'scope': {...}}
  
fn4()

六、递归

  • 简单理解为在函数中自己调用自己。
  • 递归式函数的两个条件
    • 基线条件
      • 问题可以被分解为的最小问题,当满足基本条件时,递归就不再执行。
    • 递归条件
      • 将问题分解的条件。
#定义阶乘函数
def factorial(n):
    if n == 1:
        return 1
    return n * factorial(n - 1)


print(factorial(4))

练习1

创建一个函数power来为任意数字做幂运算 n**i。

def power(n, i):
    if i == 1:
        return n
    return n * power(n, i - 1)

练习2

创建一个函数,用来检查一个任意的字符串是否是回文字符串。如果是返回True,否则返回False。回文字符串:字符串从前往后和从从后往前都是一样的,abcba。

def check(str):
    # 字符串长度小于2,一定是回文
    if (len(str) < 2):
        return True
    # 第一个字符串跟最后一个不一样,不是回文
    if (str[0] != str[-1]):
        return False
    # 递归检查第二个到倒数第二个的子字符是否是回文
    return check(str[1:-1])

七、高阶函数

  • Python中,函数是一等对象
    • 一等对象一般有以下特点
      • 对象在运行时创建
      • 能赋值给变量或作为数据结构中的元素
      • 能作为参数传递
      • 能作为返回值返回
    • 这就意味着Python支持函数式编程
  • 高阶函数至少要符合以下特点中的一个
    • 接收1个或多个函数作为参数
    • 将函数作为返回值返回
  • 当使用一个函数作为参数时,实际上时将指定的代码传递进了目标函数。
list = [1, 2, 3.4, 5, 6, 7, 8, 9, 10]

# 检查一个任意数是否是偶数
def fn2(i):
    if i % 2 == 0:
        return True
    return False


# 检查一个任意数是否大于5
def fn3(i):
    if i > 5:
        return True
    return False


# 定义函数:返回一个子列表
def fn(func,list):
    new_list = []

    for n in list:
        if (func(n)):
            new_list.append(n)

    return new_list


print(fn(fn2,list))  #[2, 6, 8, 10]
print(fn(fn3,list))  #[6, 7, 8, 9, 10]


  • filter() 可以从序列中过滤出符合条件的元素,保存到新序列中 
  • 参数:
    • 函数,根据该函数来过滤序列
    • 需要过滤的序列(可迭代的结构)
  • 返回值:
    • 过滤后的新序列(可迭代的结构)

上面的 print(fn(fn3,list))  等价于:

print(list(filter(fn2, ls)))

匿名函数lambda

  • 专门创建一些简单的函数,只调用一次。

lambda 参数列表:返回值

ls = [1, 2, 3.4, 5, 6, 7, 8, 9, 10]
# 判断奇偶函数
def fn2(i):
    if i % 2 == 0:
        return True
    return False

# fn2改造成lombda
lambda i: i % 2 == 0
r = filter(lambda i: i % 2 == 0, ls)
print(list(r))

# 输出结果
# [2, 6, 8, 10]

map()函数

  • 可以对可迭代对象中所有元素做指定操作,返回一个新对象
ls = [1, 2, 3.4, 5, 6, 7, 8, 9, 10]
r = map(lambda i: i + 1, ls)
print(list(r))

# 输出结果
# [2, 3, 4.4, 6, 7, 8, 9, 10, 11]

sort()方法

  • 对列表元素进行排序。
  • 默认直接比较元素的大小。
  • sort() 可以接受一个关键字参数,key
    • key需要一个函数作为参数,当设置了函数作为参数
    • 每次都会以列表中的一个元素来调用函数,并且使用函数的返回值来比较元素的大小。
ls = ["bb", "aaaa", "c", "ddddddd", "fff"]
ls.sort(key=len)
print(ls)


# 输出结果
['c', 'bb', 'fff', 'aaaa', 'ddddddd']

 sorted()函数

  • 与sort()用法基本一致
  • 区别:
    • 可以对任意序列进行排序
    • 不会影响原来的对象,而是返回新对象
ls = ["bb", "aaaa", "c", "ddddddd", "fff"]
r = sorted(ls, key=len)
print(ls)
print(r)

# 输出结果
['bb', 'aaaa', 'c', 'ddddddd', 'fff']
['c', 'bb', 'fff', 'aaaa', 'ddddddd']

闭包 

  • 函数嵌套。
  • 将内部函数作为返回值返回。
  • 内部函数必须要使用外部函数的变量。
def make_avg():
    nums = []

    def avg(n):
        nums.append(n)
        return sum(nums) / len(nums)

    return avg


averager = make_avg()
print(averager(10))
print(averager(20))
print(averager(30))

#-------------------------
#输出结果
10.0
15.0
20.0

你可能感兴趣的:(Python基础(四)函数)