python 函数

函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。

函数分类

1. 内置函数。如 str()、list()、len()等这些都是内置函数,我们可以拿来直接使用;
2. 标准库函数。通过 import 语句导入库,然后使用其中定义的函数;
3. 第三方库函数。Python 社区也提供了很多高质量的库。下载安装这些库后,也是通过 import 语句导入,然后可以使用这些第三方库的函数;
4. 用户自定义函数。用户根据需求自己定义的函数。下面主要介绍自定义函数。

函数定义和调用

定义:

  • 函数代码块以 def 关键词开头,后接函数名称和 ()
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。返回多个返回值,可使用列表、元组、字典、集合将多个值“存起来”即可。

调用:

  • 调用函数时,参数值和参数名称是按函数声明中定义的顺序匹配。
#定义函数
def sum(a,b): #a,b是形参
    '''求和函数'''
    return a+b
#调用函数
s = sum(1,2) # 1,2是对应形参的实参
print(s)

在以上简单示例中,形参是在定义函数使用的形式参数,无需定义参数类型,在实际调用函数时,传入的是实际参数,顺序与形参一一对应。

函数也是对象

Python 中“一切皆对象”。执行 def 定义函数后,系统就创建了相应的函数对象。

def sum(a,b):
    return a+b

v = sum
s2 = v(2,3)
print(s2)

print(id(sum))
print(type(sum))  #<class 'function'>

def定义了一个函数,系统中会创建函数对象,并通过 sum这个变量进行引用。执行v= sum后,将sum变量的值赋给v,即v与sum变量同时指向了同一个函数对象,因此,执行v(2,3)与执行sum(2,3)是调用的同一个函数对象。圆括号表示调用,没有圆括号的情况下,只是将函数当作普通对象。

全局变量与局部变量

全局变量:

  1. 在函数和类定义之外声明的变量。作用域为定义的模块,从定义位置开始直到模块结束。
  2. 全局变量降低了函数的通用性和可读性。应尽量避免全局变量的使用。
  3. 全局变量一般做常量使用。
  4. 函数内要改变全局变量的值,使用 global 声明一下

局部变量:

  1. 在函数体中(包含形式参数)声明的变量。
  2. 局部变量的引用比全局变量快,优先考虑使用。
  3. 如果局部变量和全局变量同名,则在函数内隐藏全局变量,只使用同名的局部变量

1.定义的函数内部的变量名如果是第一次出现, 且在=符号前,那么就可以认为是被定义为局部变量。在这种情况下,不论全局变量中是否用到该变量名,函数中使用的都是局部变量。

num = 100
def func():
    num = 123
    print(num)
func()  #123

如果局部变量没有定义,报错“UnboundLocalError: local variable 'num' referenced before assignment”

  num = 100
  def func():
    num += 100
    print num
  func()

2.函数内部的变量名如果是第一次出现,且出现在=符号后面,且在之前已被定义为全局变量,则这里将引用全局变量。

num = 100
def func():
    x = num + 100
    print(x)
func()  #200

如果变量名num在之前没有被定义为全局变量,则会出现错误提示:NameError: name 'num' is not defined。

def func():
    x = num + 100
    print(x)
func()

3.函数中使用某个变量时,如果该变量名既有全局变量也有局部变量,则默认使用局部变量。

num = 100
def func():
    num = 200
    x = num + 100
    print(x)
func() #300

4.函数中将某个变量定义为全局变量时需要使用关键字global

num = 100
def func():
    global num
    num = 200
    print(num)
func() #200
print(num) #200

输出局部变量和全局变量

num = 100
def func():
    num = 200
    print(locals())
    print(globals())
func() 

结果为:

{'num': 200}
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000027186774F98>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/root/workspace/******.py', '__cached__': None, 'num': 100, 'func': <function func at 0x0000027186671EA0>}

参数传递

Python 中参数的传递都是“引用传递”,不是“值传递”。具体操作时分为两类:
1. 对“可变对象”进行“写操作”,直接作用于原对象本身。
2. 对“不可变对象”进行“写操作”,会产生一个新的“对象空间”,并用新的值填充这块空间。

浅拷贝与深拷贝

浅拷贝:不拷贝子对象的内容,只是拷贝子对象的引用
深拷贝:会连子对象的内存也全部拷贝一份,对子对象的修改不会影响源对象
浅拷贝示例如下:

def testCopy():
    a = [1,2,[3,4]]
    b = copy.copy(a)
    print('a:',a)
    print('b:',b)
    b.append(5)
    b[2].append(6)
    print('a-->',a)
    print('b-->',b)

testCopy()

结果为:

a: [1, 2, [3, 4]]
b: [1, 2, [3, 4]]
a--> [1, 2, [3, 4, 6]]
b--> [1, 2, [3, 4, 6], 5]

深拷贝示例:

def testDeepCopy():
    a = [1,2,[3,4]]
    b = copy.deepcopy(a)
    print('a:',a)
    print('b:',b)
    b.append(5)
    b[2].append(6)
    print('a-->',a)
    print('b-->',b)
testDeepCopy()

结果为:

a: [1, 2, [3, 4]]
b: [1, 2, [3, 4]]
a--> [1, 2, [3, 4]]
b--> [1, 2, [3, 4, 6], 5]

传递可变对象(例如:列表、字典、自定义的其他可变对象等),实际传递的是对象的引用。在函数体中不创建新的对象拷贝,而是可以直接修改所传递的对象。

传递参数是不可变对象(例如:int、float、字符串、元组、布尔值),实际传递的还是对象的引用。在”赋值操作”时,由于不可变对象无法修改,系统会新创建一个对象。传递不可变对象时,如果发生拷贝,用的是浅拷贝。

传递不可变对象中包含可变子对象时,在修改这个可变子对象的时候,源对象也修改。

a = (1,2,[3,4]) #元组对象不可修改
print('a:',id(a))

def test(m):
    print('m:',id(m))
    m[2][0] = 666 #修改元组中的列表元素
    print(m)
    print('m-->',id(m))

test(a)

结果为:

a: 1447904202040
m: 1447904202040
(1, 2, [666, 4])
m--> 1447904202040

参数类型

位置参数

函数调用时,实参默认按位置顺序传递,需要个数和形参匹配。按位置传递的参数,称为“位置参数”。
 

默认值参数

某些参数设置默认值,默认值参数放到位置参数后面

命名参数

按形参的名称传递参数,称为“命名参数”,也称“关键字参数”。

def test(a,b,c):
    print(a,b,c)

test(c=2,b='a',a=(1,2))

可变参数

可变参数指的是“参数的数量可变”。分两种情况:
1. *param(一个星号),将多个参数收集到一个“元组”对象中。
2. **param(两个星号),将多个参数收集到一个“字典”对象中。
 

def f1(a,b,*c):
    print(a,b,c)

def f2(a,b,**c):
    print(a,b,c)

def f3(a,b,*c,**d):
    print(a,b,c,d)

f1(1,2,3,4)
f2(1,2,name='zhangsan',age=12)
f3(1,2,3,4,name='zhangsan',age=12)

结果为:

1 2 (3, 4)
1 2 {'name': 'zhangsan', 'age': 12}
1 2 (3, 4) {'name': 'zhangsan', 'age': 12}

强制命名参数

带星号的“可变参数”在前,必须使用强制命名参数

def f1(*c,a,b,):
    print(a,b,c)

f1(12,1,a=2,b=3)

lambda表达式和匿名函数

lambda 表达式可以用来声明匿名函数。lambda 函数是一种简单的、在同一行中定义函数的方法。lambda 函数实际生成了一个函数对象。lambda 表达式只允许包含一个表达式,不能包含复杂语句,该表达式的计算结果就是函数的返回值。
lambda 表达式的基本语法:lambda arg1,arg2,arg3... : <表达式>

arg1/arg2/arg3 为函数的参数。<表达式>相当于函数体。运算结果是:表达式的运算结果。
如:lambda a,b,c:a+b+c

嵌套函数(内部函数)

函数内部有函数

def f1(name,age,score):
    def f2(a,b):
        print('{0}-{1}'.format(a,b))

    if name == 'zhangsan':
        f2(name,age)
    if name == 'lisi':
        f2(name,score)

f1('zhangsan',12,90)
f1('lisi',15,100)

nonlocal

nonlocal 用来声明外层的局部变量。
global 用来声明全局变量。
 

a = 100
def outer():
    b = 50
    def inner():
        nonlocal b
        print('inner b:',b)
        b = 500
        
        global  a
        a = 200

    inner()
    print('outer b:',b)

outer()
print('a:',a)

结果为:

inner b: 50
outer b: 500
a: 200

LEGB规则

Python 在查找“名称”时,是按照 LEGB 规则查找的:Local-->Enclosed-->Global-->Built in

  • Local 指的就是函数或者类的方法内部
  • Enclosed 指的是嵌套函数(一个函数包裹另一个函数,闭包)
  • Global 指的是模块中的全局变量
  • Built in 指的是 Python 为自己保留的特殊名称
     

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值