python-函数的简单介绍

1、函数的基本概念

函数: 是一段可以重复多次调用的代码,通过输入的参数值,返回需要的结果。通俗地说,函数就是完成特定功能的一个语句组,这组语句可以作为一个单位使用,并且给它取一个名字,这样,我们就可以通过函数名在程序的不同地方多次执行(这通常叫做函数调用),却不需要在所有地方都重复编写这些语句。另外,每次使用函数时可以提供不同的参数作为输入,以便对不同的数据进行处理;函数处理后,还可以将相应的结果反馈给我们。

2、定义函数:

2.1、函数定义的语法:

def function_name(argument1[=default_value1], argument2[=default_value2]...):
    ''' docString '''
    pass
    return expression
  • def 关键字:definition 的缩写,表示后面定义的是一个函数或方法。
  • 函数名:以字母、数字或下划线组成的字符串,但是不能以数字开头。推荐全部使用小写字母,单词之间以下划线隔开
  • 文档字符串:是包, 模块, 类或函数里的第一个语句。 这些字符串可以通过对象的 __doc__ 成员被自动提取, 并且被 pydoc 所用。
  • 函数的参数:放在一对圆括号中,参数的个数可以有零个、一个或多个,参数之间用逗号隔开。
    • 形参、实参:在定义函数时,函数名后面圆括号中的变量名称叫做“形式参数”,或简称为“形参”;在调用函数时,函数名后面圆括号中的变量名称叫做“实际参数”,或简称为“实参”。
    • 缺省参数:在定义函数时,我们可以用赋值符号给某些形参指定默认值,这样当调用该函数的时候,如果调用方没有为该参数提供值的话,则使用默认值;如果调用该函数的时候为该参数提供了值的话,则使用调用方提供的值 -- 像这样的参数我们称之为缺省参数。
  • return 语句:return 语句的作用是结束函数调用,并将结果返回给调用者。不过,对于函数来说,该语句是可选的,并且可以出现在函数体的任意位置;对于没有使用 return 语句的函数,它实际上也向调用者返回一个值,那就是 None。

2.2、定义一个空函数:

def function_name(argument1[=default_value1], argument2[=default_value2]...):
    pass

pass 语句什么都不做,只是用来作为占位符,比如:现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

3、函数调用:

3.1、函数调用语法:

function_name(argument1, argument2...)

在交互式命令行,比如说想要获得 print 函数的帮助信息,可以执行如下命令

>>> help('print')

3.2、参数传递的方法

  • 标准调用:标准调用方式,传递的值按照形参定义的顺序相应地赋给它们。
  • 关键字调用:即在调用函数时同时给出形式参数和实际参数。解释器能通过给出的关键字来匹配参数的值,所以这样就允许参数缺失或者不按定义函数时的形式参数的顺序提供实际参数。
  • 默认值参数:只有在形参表末尾的那些参数可以有默认参数值,也就是说你不能在声明函数形参的时候,先声明有默认值的形参而后声明没有默认值的形参。这是因为赋给形参的值是根据位置而赋值的。例如,def func(a, b=1) 是有效的,但是 def func(a=1, b) 是无效的。

注:

默认参数的值是不可变的对象,比如 None、True、False、数字或字符串

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

def print_info( a , b = [] ):
    print("value: %s, id: %d" %(b, id(b)))
    return b

if __name__ == '__main__':
    result = print_info(1)

    result.append('error')

    print_info(2)

执行结果:

value: [], id: 42733832
value: ['error'], id: 42733832

3.2、参数检查:

  • 个数检查:调用函数时,如果参数个数不对,Python 解释器会自动检查出来,并抛出 TypeError

  • 类型检查:内置函数 isinstance 可以用来判断对象的类型,基本语法如下:

isinstance(object, class-or-type-or-tuple) -> bool

第二个参数可以是一个类型名或一个元组,如果是元组的话,对象类型与元组中类型名之一相同即返回True。

判断一个对象是否是字符串

>>> s = 'abc'
>>> isinstance(s,basestring)
True
 
>>> s = 3
>>> isinstance(s,basestring)
False

检查到错误之后,我们可以通过 raise 自己触发一个异常

3.4、变量的作用域

在 Python 中的任何变量都有其特定的作用域,比如在一个函数中定义的变量一般只能在该函数内部使用,这些只能在程序的特定部分使用的变量我们称之为局部变量;比如在一个文件顶部定义的变量可以供该文件中的任何函数调用,这些可以为整个程序所使用的变量称为全局变量。

上面是从空间的角度来考察变量的局部性和全局性,如果从时间的角度来看,不妨简单地认为在程序运行的整个过程中,全局变量一直占据着内存,并且它的值可以供所有函数访问;而局部变量则是只有在其所在函数被调用时才给它分配内存,当函数返回时,其所占内存就会被释放,所以它只能供其所在的函数所访问——换句话说,当某个函数退出时,其局部变量原先所占的内存将被分配给其它函数的局部变量。打个不太贴切的比方,全局变量就好比您自己买的房子,通常一家人要在那里住上好几十年,如果我要找您要债,我会老往您家里跑;而局部变量好像旅馆,今天您租住这件房间,我可以到这个房间来找您,但是到明天再来这间房间的话,找到的可能就是别人了。

在同一个源文件中,全局变量和局部变量同名时,在局部变量的作用范围内,全局变量不起作用。像下面这个例子,在函数 func 外部定义的变量 x ,和在函数内部定义的 x 互不影响

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

def func(x):
    print("x 在函数内,改变前:%d, x is %d" %(id(x), x))
    x = 2
    print("x 在函数内,改变后:%d, x is %d" %(id(x), x))

if __name__ == '__main__':
    
    x = 50  
    print("x 在函数外:%d, x is %d" %(id(x), x))
    func(x)
    print('x 在函数外:%d, x is still %d' %(id(x), x))

输出:

x 在函数外:500593664, x is 50
x 在函数内,改变前:500593664, x is 50
x 在函数内,改变后:500592128, x is 2
x 在函数外:500593664, x is still 50

这个过程,用文字描述如下:

  • “x = 50”:新建了一个整形对象 50,分配了内存地址为:500593664,并且将函数外变量 x 绑定到了这个对象上。
  • “func(x)”:新建了一个函数内变量 x,并且将 x 绑定到这个对象上,所以此时,对象内存地址未变
  • “x = 2”:新建了一个整型对象 2,分配了内存地址:500592128,并将函数内变量 x 重新绑定到了这个对象上

如果你想要为一个定义在函数外的变量赋值,那么你就得告诉 Python 这个变量名不是局部的,而是全局的。我们使用 global 语句完成这一功能。
global 语句的作用是将某些变量声明为全局变量,变量名可以是一个,也可以是多个。当关键词 global 后面跟随多个变量名称时,各名称之间要用逗号分隔开来。

#!/usr/bin/python
# Filename: func_global.py

def func():
    global x

    print 'x is', x
    x = 2
    print 'Changed local x to', x

x = 50
func()
print 'Value of x is', x

输出

]# python func_global.py
x is 50
Changed global x to 2
Value of x is 2

注1:

在 Python 中,字符串,整形,浮点型,tuple 是不可更改的对象,而 list , dict 等是可以更改的对象。

  • 不可更改的类型:类似 c++ 的值传递,如:整数、字符串、元组。如fun(a),传递的只是 a 的值,没有影响 a 对象本身。比如在 fun(a) 内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
  • 可更改的类型:类似 c++ 的引用传递,如:列表,字典。如 fun(a),则是将 a 真正的传过去,修改后 fun 外部的 a 也会受影响
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

def chagne_list( b ):
    print('函数中一开始 b 的值:{}, id 值为:%d' .format( b ) %id(b))
    b.append(1000)
    print('函数中 b 赋值后的值:{}, id 值为:%d' .format( b ) %id(b))

if __name__ == '__main__':
    b = [1, 2, 3, 4, 5]
    chagne_list(b)
    print('最后输出 b 的值:{}, id 值为:%d'.format(b) %id(b))

执行结果为:

函数中一开始 b 的值:[1, 2, 3, 4, 5], id 值为:42799368
函数中 b 赋值后的值:[1, 2, 3, 4, 5, 1000], id 值为:42799368
最后输出 b 的值:[1, 2, 3, 4, 5, 1000], id 值为:42799368

注2:

如果要避免上面这种情况发生,可以向函数传递一个字典或列表的副本,而不是它本身

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

import copy
def chagne_list( b ):
    print('函数中一开始 b 的值:{}, id 值为:%d' .format( b ) %id(b))
    b.append(1000)
    print('函数中 b 赋值后的值:{}, id 值为:%d' .format( b ) %id(b))

if __name__ == '__main__':
    b = [1, 2, 3, 4, 5]
    print('函数外一开始 b 的值:{}, id 值为:%d'.format(b) % id(b))
    chagne_list(copy.deepcopy(b))

执行结果为:

函数外一开始 b 的值:[1, 2, 3, 4, 5], id 值为:43472904
函数中一开始 b 的值:[1, 2, 3, 4, 5], id 值为:43473096
函数中 b 赋值后的值:[1, 2, 3, 4, 5, 1000], id 值为:43473096

注3:

上面这个例子,又涉及到了 python 的浅拷贝和深拷贝,再举一个例子来说明一下:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

import copy

if __name__ == '__main__':

    original = [[1], "test"]
    shallow_copy = copy.copy(original)
    deep_copy = copy.deepcopy(original)

    print("改变前:")
    print("original 值为:{}, id 为:{}".format(original, id(original)))
    print("shallow_copy 值为:{}, id 为:{}".format(shallow_copy, id(shallow_copy)))
    print("deep_copy 值为:{}, id 为:{}".format(deep_copy, id(deep_copy)))

    original[0].append(2)

    print ("改变后:")
    print("original 值为:{}, id 为:{}".format(original, id(original)))
    print("shallow_copy 值为:{}, id 为:{}".format(shallow_copy, id(shallow_copy)))
    print("deep_copy 值为:{}, id 为:{}".format(deep_copy, id(deep_copy)))

执行结果:

改变前:
original 值为:[[1], 'test'], id 为:43338056
shallow_copy 值为:[[1], 'test'], id 为:43339336
deep_copy 值为:[[1], 'test'], id 为:43339272
改变后:
original 值为:[[1, 2], 'test'], id 为:43338056
shallow_copy 值为:[[1, 2], 'test'], id 为:43339336
deep_copy 值为:[[1], 'test'], id 为:43339272

3.5、传递长度可变的参数:

预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用如下两个关键字。

  • 在函数的参数前使用标识符 *:通常的写法 *args,可以将数量不定的,以位置参数方式传入的参数打包一个元组中。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

def print_everything(*args):
    for count, thing in enumerate(args):
        print('{0}. {1}'.format(count, thing))

if __name__ == '__main__':
    print_everything('apple', 'banana', 'cabbage')

输出:

0. apple
1. banana
2. cabbage
  • 在函数的参数前使用标识符 **:通常的写法 **kwargs,可以将数量不定的,以关键字方式传入的参数打包到一个字典中。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# environment:python3.6.4

def greet_me(**kwargs):
    for key, value in kwargs.items():
        print("{0} == {1}".format(key, value))

if __name__ == '__main__':
    greet_me(name="yasoob",age=15)

输出

name == yasoob
age == 15

4、函数的返回

python 函数返回值有两种形式:

  1. 返回一个值

现看看返回一个值的吧。

def firstvalue(a,b):
    c = a + b
    return c

print firstvalue(1,2)

结果:

3
  1. 返回多个值。

再看看返回多个值的:

def secondvalue(a,b):
    c = a + b
    return (a,b,c)
   
x,y,z = secondvalue(1,2)
print 'x:',x,'y:',y,'z:',z

结果:

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

推荐阅读更多精彩内容