函数

定义函数

定义函数用def语句,格式:def 函数名(自变量) :函数名称的定义规则和变量定义规则相同。在缩进板块中编写函数体,最后用return返回一个值。

求n的阶乘
def f(x) :
    """
    计算阶乘

    :param x: 一个非负整数

    :return: x的阶乘
    """
    y = 1
    for n in range(1, x + 1) :
        y *= n
    # return表示返回一个值,同时结束此函数
    return y

注意:函数内部一旦执行到return,该函数就会停止执行,并将结果返回。如果没有return语句,函数执行完毕就会停止,返回的是一个空值none。

求最大公约数
def gcd(x, y):
    """
    计算两个数的最大公约数

    :param x: 一个非负整数
    :param y: 一个非负整数

    :return: x,y的最大公约数
    """
    (x, y) = (y ,x) if x > y else (x, y)
    for factor in range(x, 0, -1):
        if x % factor == 0 and y % factor == 0:
            return factor
判断素数
def is_prime(x):
    """
    判断素数

    Parameters:
        x - 一个非负整数
        y - 一个非负整数

    Returns:
         如果num是素数返回True,反之返回False
    """
    for num in range (2,int(sqrt(x)) + 1):
        if x % num == 0:
            return False
    # return True
    # 排除1的写法:
    return True if x != 1 else False
  • 函数自变量的四种定义方式:

1.不设定自变量

def main():
    pass

2.自变量为确定个数的参数,如上面的is_prime函数,自变量为1个,即x;gcd函数,自变量为2个,即x,y
3.自变量为不确定的参数
如下举例说明:
在参数数量不确定的情况下,求多个数的和
利用*args 定义可变参数:*args 参数数量不确定,可为0个,也可为多个。在调用函数add时,输入的自变量为多少个,函数就求多少个数的和。

def add(*args):
    """
    参数数量不确定的情况下,求多个数的和

    :param argus:
        *args 定义可变参数:*args 参数数量不确定,可为0个,也可为多个

    :return: 多个参数的和
    """
    total = 0
    for value in args:
        total += value
    return total


if __name__ == '__main__':
   # 直接传入可变参数
   # 求的是1+3+2+2+2+2的和
    print(add(1,3,2,2,2,2))
   # 传入列表,求列表中各个元素的和
    mylist = [1, 3, 5, 2, 10]
   # 如果传入的直接就是一个列表,必须在列表前面加上*,才能取到列表中各个元素,否则会被视为只传入了一个值,即列表
    print(add(*mylist))

4.自变量设定了默认值
定义摇n个色子,求每次色子点数之和的函数,假设我们给自变量一个默认值,可设置为“n=2”格式,如下:


def roll_dice(n=2):
    total = 0
    for _ in range (n) :
        total += randint(1, 6)
    return total

if __name__ == '__main__':
    # 调用函数,但未定义自变量,自变量取默认值2
    roll_dice()
    # 调用函数,定义自变量的值为3
    roll_dice(3)

注意:在定义函数自变量时,官方建议不要用空格,如定义自变量为n,并给n赋一个默认值2,官方建议的书写格式为:n=2,而不是n = 2。但在其他情况下,官方建议的书写格式为:n = 2。


空函数

如果想定义一个什么事也不做的空函数,可以用pass语句。pass语句的意义:什么都不做,实际上是用来做占位符。比如现在还没有想好怎么写函数的代码,就可以先放一个pass,程序可以顺利运行。
举例说明:

def nop():
    pass

pass还可以放在其他语句中,如:

if x<1:
    pass

函数的调用

一个文件就是一个模块,一个模块中可能有1个或任意多个函数

  • 当前模块中调用函数

调用函数时,若函数就在当前文本,则可以直接进行调用。格式为:函数名(变量)。由于很多时候这一个函数会被其他文本调用,为了让其他文本在调用此函数时不执行其他的代码,可以使用下面的if条件语句,让其他文本在导入此模块时不执行下面的代码,原理:只有本文件执行时,name = main,当其他文件执行时,name = 这个文件的命名,则name != main,if条件不成立,代码不执行。

  • 其他模块调用函数

若当前文本需要调用其他文本的函数,则需要引入调用的函数模块。
1.同一跟目录下的两个文本函数之间调用:from 要调用的函数所在文本的名称 import 函数名称
2.不同根目录下的两个文本函数直接的调用:from 要调用的函数所在文本的路径(如day01.practice.prime,表示day01包下面的practice包下面的prime文本)import 函数名称
3.一个文本可能存在多个函数,若需要调用此文本的所有函数,可写作如下格式:import combination * 导入combination中所有模块

#导入 combination文件中所有模块
import combination *

4.直接引入函数所在文本,每次调用时再输入:文件名.函数名称。若原本的文件名太过复杂,还可临时给他命一个新的名字(别名):import combination as com 此处把combination命为com,在调用时,写作com.f

import combination 
#调用cobination的f(x)函数
print(com.f(5))
  • 实例说明

1.直接调用输出内容
打印100以内的素数:
if __name__ == '__main__':
    for num in range(1,100):
        # 当is_prime(num)函数返回的值为True时,if条件语句才会执行
        if is_prime(num):
            print(num)
调用求阶乘函数:f(x),求组合数C(m, n)
    m = int(input('m = '))
    n = int(input('n = '))
    # 调用函数f(x)
    print(f(m) // f(n) // f(m - n))

2.调用函数构造新的函数

求最小公倍数,lcm函数调用cgd函数
def lcm(x,y):
    """
    计算两个数的最小公倍数

    Parameters:
        x - 一个非负整数
        y - 一个非负整数

    Returns:
        x,y的最小公倍数
    """
    return x * y // gcd(x, y)

3.函数的递归调用

函数的递归调用指的是函数直接或间接调用函数自身,构造这样的递归函数必须满足以下几点:
1.收敛条件 - 让递归在有限的次数完成或者进行回溯
2.如果递归无法在有限次数内收敛就有可能导致RecursionError,而且栈的空间很小,必须控制此函数的递归深度在栈的递归深度内。
3.递归公式
在进入函数调用之前要保存当前的执行现场,函数的执行现场是保存在一种称为栈(stack)的内存空间上,栈是一种先进后出(FILO)的存储结构。所以函数在做递归调用时,会一层一层向下递归,最后在一层一层回溯。

求最大公约数
def gcd(x, y):
    if x > y:
        return gcd(y, x)
    elif y % x == 0:
        return x
    else:
        return gcd(y % x, x)
求1到100的和
def add(n):
    if n == 1 :
        return 1
    return n + add(n - 1)
计算走楼梯有多少种方式

10级楼梯,1次可选择1,2,3层台阶,走完这10层台阶,问有多少种走法

def way(n):
    if n < 0:
        return 0
    elif n == 0:
        return 1
    return way(n - 1) + way(n - 2) + way(n - 3)
汉诺塔
def hanoi(n, a, b, c):
    if n > 0:
        hanoi(n - 1, a, c, b)
        print(a,'---->', b)
        hanoi(n - 1, c, b, a)

函数命名冲突

当有多个函数命名冲突时,后面的函数自动覆盖前面相同名称的函数。

  • 自己设定的函数和python内置的函数冲突:

如自己编写了一个求最大公约数的函数gcd,和math中的内置的gcd函数冲突

from combination import gcd,
from math import gcd

调用gcd函数时,如果直接书写gcd(),文本会自动调用写在后面的那个函数,如上就会调用math中的gcd,为了避免这种情况,可以按照以下方式调用:

# 方法一
import combination
import math

print(math.gcd())
print(combination.gcd())

# 方法二
from combination import gcd
# 调用的是conbinaion中的gcd函数
print(gcd())
from math import gcd
# 调用的是math中的gcd函数
print(gcd())

函数变量的作用域

变量的作用域有三种:
1.全局(global)作用域的变量:定义在函数外部的变量,此变量可在全局范围内被调用
2.嵌套(enclosed)作用域的变量:当一个函数调用另一个函数时,定义在外层函数中的变量,此变量可被内外层函数调用
3.局部(local)作用域:当一个函数嵌套在另一个函数内部时,定义在内层函数中的变量,此变量只能被内层函数调用
4.内置(build-in)作用域
Python 搜索一个变量的方式是从局部作用域到嵌套作用域再到全局作用域,如果都没有搜索到,则会搜索内置函数,简称为LEGB(Local - Enclosed - Global - Build-in),如果想改变搜索范围,可以使用global和nonlocal关键字改变变量的作用域。
举例说明:

# 在函数外面定义的a是一个全局变量
# 实际开发时一定要减少对全局变量的使用
# global variable
a = 100


def foo():
    # 把foo函数内的变量a改为全局变量,这时如果在函数外调用a,当搜索到此处的a = 200时,原本变量a不能在函数外被调用,但此处变量a改为了全局变量,则能被函数外的代码调用
    global a
    a = 200
    # local variable
    # 函数内部的局部变量 离开foo函数变量是无法访问的
    b = 'hello'

    def bar():
        # 把局部作用域bar中的变量b改为嵌套作用域foo中的局部变量b,这时如果在foo中调用b,则搜索到的是b = 'good',而不是之前的b = 'hello'
        nonlocal b
        b = 'good'
        print(a)
        print(b)

    bar()
    print(b)


# foo()函数运行结果:200 good good
foo()
# 运行结果:200
print(a)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 1、c语言的函数有以下特点: (1)才源程序由函数组成,一个主函数main()+若干其他函数 C程序中的函数类似文...
    滕王阁序阅读 1,335评论 0 6
  • 函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。 上面代码检查函数l...
    呼呼哥阅读 3,363评论 0 1
  • 1.函数参数的默认值 (1).基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法。
    赵然228阅读 684评论 0 0
  • 原文链接:https://github.com/EasyKotlin 值就是函数,函数就是值。所有函数都消费函数,...
    JackChen1024阅读 5,957评论 1 17
  • 你 能欣赏我的好 也能容忍我的坏。 我不用小心翼翼地迁就你 你也不用费尽心思地迎合我 你不会老想着改变我 我也不会...
    A疯丫头阅读 227评论 0 0