Python函数

文章目录

  • Python函数
    • 1、函数是什么
    • 2、函数的定义和调用
    • 3、代码警告的处理
    • 4、函数的参数
    • 5、函数的返回值
    • 6、变量的作用域
    • 7、函数的执行过程
    • 8、函数的链式调用和嵌套调用
    • 9、局部变量和函数栈帧
    • 10、函数递归
    • 11、函数形参的默认值
    • 12、函数的关键字参数

Python函数

1、函数是什么

函数,一段可以被重复使用的代码

  1. 复制代码,必须要非常仔细的进行细节调整,尤其是数据不同的情况下.
  2. 一旦复制过的代码,需要调整,复制了几份就得调整几次~(搞不清楚这个代码究竟被复制了几份了)
    因此,尽量还是不要复制代码,尽量做好代码"重用"
# 定义函数
def calcSum(beg, end):
    sum = 0
    for i in range(beg, end+1):
        sum += i
    print(sum)


# D调用函数
calcSum(1, 10)
calcSum(1, 100)
calcSum(300, 500)

2、函数的定义和调用

定义格式

def 函数名 (形参列表):
	函数体
	return 返回值

调用

函数名(实际参数列表)
or
返回值=函数名(实际参数列表)

Python中要求,函数定义写在前面,函数调用写在后面,先定义后调用

3、代码警告的处理

  • 警告:提示你的代码可能存在问题,但是并不影响程序编译执行
  • 错误:代码中实打实的有问题!

这两个事情严重程度是完全不同的!

PEP8这是Python里面一套非常流行的编程规范,也就是写代码中的一些"软性要求"

4、函数的参数

在函数定义的时候,可以在()中指定"“形式参数”(简称形参),然后在调用的时候,由调用者把"实际参数"(简称实参)传递进去。这样就可以做到一份函数,针对不同的数据进行计算处理。

函数的调用是可以有多次的,同时每次调用的实参,也是可以不同的
实参和形参的关系就像签合同的甲方乙方和真实的人名一样!

C++ Java 里面,不光要求形参和实参的个数要匹配,还要求类型也要匹配,但是在Python里,只是要求个数,对类型没有要求(动态类型)

def add(x, y):
    return x+y


print(add(1, 2))
print(add(1.1, 2.2))
print(add("hello", "world"))

也不是说,随便传入啥类型都行,只要保证传入的参数类型,在函数体里面能够支持对应的运算操作即可!

5、函数的返回值

函数的参数可以视为是函数的"输入",则函数的返回值,就可以视为是函数的"输出"。

此处的"输入",“输出”是更广义的输入输出,不是单纯指通过控制台输入输出。
我们可以把函数想象成一个"工厂”。工厂需要买入原材料,进行加工,并生产出产品。
函数的参数就是原材料。函数的返回值就是生产出的产品。

  • 一个函数可以有多个return 语句
def isOdd(num):
    if num % 2 == 0:
        return False
    else:
        return True


print(isOdd(20))
print(isOdd(9))
  • 执行到return 语句,代码就会立即返回,而是回到调用的位置

  • Python 中的一个函数可以返回多个值(非常香的特性!!,C++,Java都馋哭了)|

C++要想返回多个值,可以通过输出型参数(指针/引用)
Java 要想返回多个值,需要把多个值给包装成一个对象,返回这个对象

# 写一个函数,返回坐标上的一个点


def getPoint():
    x = 10
    y = 10
    return x, y


a, b = getPoint()
print(a, b)
_, c = getPoint()
print(c)

Golang在设计的时候,(多元赋值)也把这个机制给引入过来了!
虽然现在返回了多个值,但是我只想用其中的一部分,不关注其他的,可以使用_来进行占位!
_, c = getPoint()不要x了,只要y,把y赋值给b即可!

6、变量的作用域

变量的作用域!
一个变量名的有效范围是一定的!只在一个固定的区域内生效
函数内部的变量名,只能在函数内部生效。出了函数,就无效了!

函数内部和函数外部是可以使用同名的变量的.虽然变量名相同,但是是不同的变量!

x = 10


def test():
    x = 20
    print(f'函数内部x={x}')


test()
print(f'函数外部x={x}')

结果:
Python函数_第1张图片
在函数里尝试读取全局变量,是可以的!当函数中尝试访问某个变量的时候,会先尝试在局部变量中查找,如果找到,就直接访问如果没找到,就会往上一级作用域中进行查找。

使用这个函数,把全局的x改为20

x = 10


def test():
    global x
    x = 20

test()
print(f"x={x}")

结果:
Python函数_第2张图片

另外:if, else, while, for这些关键字也会引入"代码块”,但是这些代码块不会对变量的作用域产生影响!在上述语句代码块内部定义的变量,可以在外面被访问!

for i in range(1, 11):
    print(i)

print(i)

7、函数的执行过程

执行到函数调用的时候,就会跳转到函数体内部来进行执行。
当函数内部执行完毕(运行完了/遇到return),就回到之前调用的位置,继续往下执行

调试执行,相比于正常的运行,最大的区别,可以随时停下来,方便程序猿观察程序的中间过程!
Python函数_第3张图片

8、函数的链式调用和嵌套调用

链式调用

把一个函数的返回值,作为另一个函数的参数,这种操作称为链式调用.这是一种比较常见的写法.

print(isOdd(10))

嵌套调用

函数内部还可以调用其他的函数,这个动作称为"嵌套调用”。

def test():
    print("hello")


test()

9、局部变量和函数栈帧

def a():
    num1 = 10
    print("函数a")


def b():
    num2 = 20
    a()
    print("函数b")


def c():
    num3 = 30
    b()
    print("函数c")


def d():
    num4 = 40
    c()
    print("函数d")


d()

调试器的左下角,能够看到函数之间的“调用栈"。
调用栈里面描述了当前这个代码的函数之间调用关系是啥,每一层这个调用关系就称为"函数的栈帧",每个函数的局部变量就在这个栈帧中体现的。

每一层栈帧,你选中了之后,都能看到里面的局部变量每个函数的局部变量就保存在对应的栈帧中,调用函数,则生成对应的栈帧,函数结束,则对应的栈帧消亡(里面的局部变量也就没了)

10、函数递归

函数递归,就是一个函数,自己调用自己

求n的阶乘

# 求n的阶乘

def factor(n):
    if n == 1:
        return 1
    return n*factor(n-1)


print(factor(5))

Python函数_第4张图片

虽然都是n,但是n是函数形参,形参相当于函数的局部变量!局部变量在函数自己的栈帧上的!虽然两个函数的局部变量名相同,但是是不同的栈帧,是不同的内存空间也就是不同的变量了!另一方面,看起来是同一个函数,但是这里的两次调用,其实是两个栈帧。

递归的代码,不会无限的往下执行,会在每一次递归的时候,都逐渐逼近递归的结束条件 if n==1

递归的代码,虽然很多时候看起来写法很简单,但是执行过程可能会非常复杂!!在分析递归代码的时候,光用脑子想,是很困难!

  • 画图
  • 调试器

递归代码要有两个要素:

  1. 递归结束条件
  2. 递归的递推公式

可以类比数学归纳法:

  1. 初始条件
  2. 递推公式

递归的缺点:

  1. 执行过程非常复杂,难以理解
  2. 递归代码容易出现"栈溢出”的情况的
  3. 递归代码一般都是可以转换成等价的循环代码的,并且,循环的版本通常运行速度要比递归的版本有优势(函数调用也是有开销的)

递归的优点:
代码非常简洁!!尤其是处理一些"问题本身就是通过递归的方式定义的")

11、函数形参的默认值

Python中的函数,可以给形参指定默认值。
带有默认值的参数可以在调用的时候不传参。

def add(x=1, y=1, debug=False):
    if debug == True:
        print(f"x={x},y={y}")
    return x+y


res = add(10, 20)
print(res)
print(add())

形参的默认值,带有默认值的形参就可以在调用函数的时候,不必传参
通过这样的默认值,就可以让函数的设计更灵活。
要求带有默认值的形参,得在形参列表的后面而不能在前面or中间!

12、函数的关键字参数

按照先后顺序来传参,这种传参风格,称为“位置参数”,这是各个编程语言中最普遍的方式。

关键字传参,按照形参的名字来进行传参!非常明显的告诉程序猿,你的参数要传给谁!!另外可以无视形参和实参的顺序!

def test(x, y):
    print(f"x={x}")
    print(f"y={y}")


test(10, 20)
test(x=10, y=20)
test(y=200, x=100)

结果:
Python函数_第5张图片
总结
位置参数关键字参数还能混着用,只不过混着用的时候要求位置参数在前,关键字参数在后
关键字参数,一般也就是搭配默认参数来使用的

一个函数,可以提供很多的参数,来实现对这个函数的内部功能做出一些调整设定,为了降低调用者的使用成本,就可以把大部分参数设定出默认值,当调用者需要调整其中的一部分参数的时候,就可以搭配关键字参数来进行操作。

你可能感兴趣的:(Python,python,开发语言)