百木园-与人分享,
就是让自己快乐。

Python中你所不知道的关于函数的秘密,原来函数这么简单

前言

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。

PS:如有需要Python学习资料的小伙伴可以点击下方链接自行获取

Python免费学习资料、代码以及交流解答点击即可加入

 

一、函数的初识

1.1、面向过程

1)获取任意一个字符串的元素的个数

s1 = \'fdskjlgfdgfdjkslgdfjkjafdsajk\'
count = 0
for i in s1:
count += 1
print(count)

2)获取列表的元素的个数

l1 = [1, 2, 3]
count = 0
for i in l1:
count += 1
print(count)

面向过程缺点:

# 1. 代码重复。
# 2. 代码可可读性不高。

1.2、初识函数

l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
print(count)

new_len() #函数的调用

函数优点:

# 1、函数:函数是以功能为导向,一个函数封装一个功能。登录,注册,文件的改的操作.....
# 2、函数减少代码的重复性,增强了代码的可读性

1.3、函数的结构

l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
print(count)

new_len()
\'\'\'
def 关键字: 定义一个函数。紧跟一个空格。
new_len函数名:与变量命名规范一致。一定要具有可描述性。
():结构需要,传参使用。
: 分割符。
tab键:四个空格。缩进。函数体

\'\'\'

1.4、函数的调用

l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
print(count)

new_len() # 函数名() 函数的执行者。调用者。
new_len() # 函数名() 函数的执行者。
new_len() # 函数名() 函数的执行者。
new_len() # 函数名() 函数的执行者。
new_len() # 函数名() 函数的执行者。

# -----------------------------------------------
l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
print(count)

for i in range(3):
new_len() # 函数名():函数的执行者。调用者。

1.5、函数的返回值

return关键字作用:

# 1、结束函数
# 2、给函数的执行者返回具体的值
1.函数中没有return或者只写一个return,函数的执行者得到的是None。
2.函数中return后面是单个值,函数的执行者得到的是这个值(不改变值的类型)。
3.函数中return后面是多个值,函数的执行者得到的是一个元组。

# return 第一个作用:结束函数。
l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
return count

print(new_len())

# ------------------------------------------------------------------------
# return第二个作用:给函数的执行者返回具体的值。
\'\'\'
1.函数中没有return或者只写一个return,函数的执行者得到的是None。
2.函数中return后面是单个值,函数的执行者得到的是这个值(不改变值的类型)。
3.函数中return后面是多个值,函数的执行者得到的是一个元组。
\'\'\'
l1 = [1, 2, 3]

def new_len():
count = 0
for i in l1:
count += 1
return

print(new_len()) # None

# ------------------------------------

def func():
print(111)
# return 100 # 100 <class \'int\'>
# return [1, 2, 3] # [1, 2, 3] <class \'list\'>
return {\'name\': \'太白\'} # {\'name\': \'太白\'} <class \'dict\'>

ret = func()
print(ret, type(ret))

# ------------------------------------
def func():
print(111)
return 1, \'AAA\', [22, 33] # 返回一个元祖

ret = func()
print(ret, type(ret)) # (1, \'AAA\', [22, 33]) <class \'tuple\'>

# ------------------------------------
def func():
print(111)
return 1, \'AAA\', [22, 33]

a, b, c = func() # 元祖的解构
print(a, b, c) # 1 AAA [22, 33]

# ------------------------------------
def func():
print(111)
# return 1+1+2
return 2 > 1

ret = func()
print(ret) # True

二、函数的传参

2.1、参数的种类

def new_len(a): # 定义函数时:参数:形参。
count = 0
for i in a:
count += 1
return count

l1 = [1, 2, 3]
s1 = \'fdsjaklsfjgfds\'
print(new_len(l1)) # 函数的调用者:参数 实参。
print(new_len(s1)) # 函数的调用者:参数 实参。
print(len(s1))

\'\'\'
实参角度:
1. 位置参数。
2. 关键字参数。
3. 混合参数。
形参角度:
1. 位置参数。
2. 默认参数。
3. 动态参数。
4. 仅限关键字参数。(了解)
\'\'\'

2.2、实参角度

2.2.1、位置参数

从左至右,按照顺序,一一对应

def meet(sex, age, job):
print(f\'性别{sex},年龄{age}岁,{job}\')

meet(\'女\', \'18~25\', \'讲师\')

# --------------------------------------
# 写一个函数,接收两个数字的参数,将较大的数字返回。
def comp(a, b):
if a > b:
return a
else:
return b

ret = comp(1, 2000)
print(ret)

# --------------------------------------
# 三元运算符:简单的if else。
def comp(a, b):
# ret = a if a > b else b
# return ret
return a if a > b else b

ret = comp(1, 2000)
print(ret)

2.2.2、关键字参数

def meet(sex, age, job, hight, weight, ):
print(f\'性别{sex},年龄{age}岁,身高{hight},体重{weight},工作{job}\')

meet(sex=\'女\', job=\'学生\', weight=120, hight=170, age=\'18~25\')

2.2.3、混合参数

# 关键字参数一定要在位置参数后面,一一对应
def meet(sex, age, job, hight, weight, ):
print(f\'性别{sex},年龄{age}岁,身高{hight},体重{weight},工作{job}\')

meet(\'男\', 27, \'ITC语言\', weight=120, hight=175, )

2.3、形参角度

2.3.1、位置参数

# 位置参数:与实参角度位置参数一样
def meet(sex, age, job):
print(f\'性别{sex},年龄{age}岁,{job}\')

meet(\'女\', \'18~25\', \'讲师\')

2.3.2、默认参数

# 默认参数: 一定在位置参数后面,不传参数即沿用默认的参数
# open的源码
open(\'文件的改\', encoding=\'utf-8\')
def open(file, mode=\'r\', buffering=None, encoding=None, errors=None, newline=None, closefd=True)

# --------------------------
def meet(age, job, sex=\'女\'):
print(f\'性别{sex},年龄{age}岁,{job}\')

meet(\'18~25\', \'幼师\') #

# 更改默认参数
meet(\'18~25\', \'幼师\', sex=\'laddy_boy\')
meet(\'18~25\', \'幼师\', \'laddy_boy\')

特别注意:

def func(a,b=False):
print(a)
print(b)
func(1,True)

# 当你的默认参数如果是可变的数据类型,你要小心了。
def func(a,l=[]):
l.append(a)
return l
print(func(1)) # [1]
print(func(2)) # [1, 2]
print(func(3)) # [1, 2, 3]

2.3.3、动态参数

动态参数分为两种:动态接受位置参数 *args,动态接收关键字参数 **kwargs

2.3.3.1、*args

# *会将实参所有的位置参数接收,放置在一个元组中,并将这个元组赋值给args这个形参
def eat(*args):
print(\'我请你吃:\', args)

eat(\'蒸羊羔儿\', \'蒸熊掌\', \'蒸鹿尾儿\', \'烧花鸭\', \'烧雏鸡\', \'烧子鹅\')

# ------------------------------------------------
def my_max(*args):
n = 0
for i in args:
n += i
return n

print(my_max(1, 2, 3, 4)) # 10

2.3.3.2、**kwargs

# **kwargs,是接受所有的关键字参数然后将其转换成一个字典赋值给kwargs这个形参
def func(**kwargs):
print(kwargs)

func(name=\'太白金星\', sex=\'男\') # {\'name\': \'太白金星\', \'sex\': \'男\'}

2.3.3.3、*args和 **kwargs结合

def func(*args, **kwargs):
print(args) # (\'蒸羊羔儿\', \'蒸熊掌\', \'蒸鹿尾儿\')
print(kwargs) # {\'name\': \'太白金星\', \'sex\': \'男\'}

func(\'蒸羊羔儿\', \'蒸熊掌\', \'蒸鹿尾儿\', name=\'太白金星\', sex=\'男\')

2.3.3.4、* 的魔性用法

1)聚合作用

def eat(args):
print(\'我请你吃:\', args) # 我请你吃: 蒸羊羔儿

eat(\'蒸羊羔儿\')

def eat(*args):
print(\'我请你吃:\', args)

eat(\'蒸羊羔儿\', \'蒸熊掌\', \'蒸鹿尾儿\') # 我请你吃: (\'蒸羊羔儿\', \'蒸熊掌\', \'蒸鹿尾儿\')

2)打散

s1 = \'alex\'
l1 = [1, 2, 3, 4]
tu1 = (\'武sir\', \'太白\', \'女神\',)

def func(*args):
print(args) # (\'alex\', [1, 2, 3, 4], (\'武sir\', \'太白\', \'女神\'))

func(s1, l1, tu1)

# -----------
s1 = \'alex\'
l1 = [1, 2, 3, 4]
tu1 = (\'武sir\', \'太白\', \'女神\',)

def func(*args):
print(args) # (\'a\', \'l\', \'e\', \'x\', 1, 2, 3, 4, \'武sir\', \'太白\', \'女神\')

func(*s1, *l1, *tu1) # 打散

# -----------
dic1 = {\'name\': \'太白\', \'age\': 18}
dic2 = {\'hobby\': \'喝茶\', \'sex\': \'男\'}

def func(**kwargs):
print(kwargs) # {\'name\': \'太白\', \'age\': 18, \'hobby\': \'喝茶\', \'sex\': \'男\'}

func(**dic1, **dic2)

def func(*args, **kwargs):
print(args, kwargs)

# -----------
l1 = [1, 2, 3]
l2 = [\'太白\', \'wusir\', \'景女神\']
# func(l1, l2) # ([1, 2, 3], [\'太白\', \'wusir\', \'景女神\']) {}
#
# func(*l1, *l2) # (1, 2, 3, \'太白\', \'wusir\', \'景女神\') {}
# func(*[1, 2, 3], *(11, 22), *\'fdsakl\') # (1, 2, 3, 11, 22, \'f\', \'d\', \'s\', \'a\', \'k\', \'l\') {}
# func(*[1, 2, 3], *(11, 22), name=\'aaa\', age=\'18\') # (1, 2, 3, 11, 22) {\'name\': \'aaa\', \'age\': \'18\'}

# ----------------------------------------------------------

def func(*args, **kwargs):
print(args, kwargs)

# 当函数的执行时:**dict 代表打散。
# func(**{\'name\': \"alex\"}, **{\'age\': 73, \'hobby\': \'吹\'}) # () {\'name\': \'alex\', \'age\': 73, \'hobby\': \'吹\'}

3)处理剩下的元素

# 分别赋值
a, b = (1, 2)
print(a, b) # 1 2

# 其实还可以这么用:
a, *b = (1, 2, 3, 4,)
print(a, b) # 1 [2, 3, 4]
*rest, a, b = range(5)
print(rest, a, b) # [0, 1, 2] 3 4
print([1, 2, *[3, 4, 5]]) # [1, 2, 3, 4, 5]

2.3.4、仅限关键字参数

# 仅限关键字参数
# 这样传参是错误的,因为仅限关键字参数c只接受关键字参数
# def func(a, b, *args, c):
# print(a, b) # 1 2
# print(args) # (4, 5)

# func(1, 2, 3, 4, 5)

# 这样就正确了:
def func(a, b, *args, c):
print(a, b) # 1 2
print(args) # (3, 4)
print(c) # 5

func(1, 2, 3, 4, c=5)

2.3.5、形参最终顺序

形参角度的所有形参的最终顺序为:**位置参数, *args,默认参数,仅限关键字参数,kwargs。

def foo(a, b, *args, c, sex=None, **kwargs):
print(a, b, c, sex, args, kwargs)

foo(1, 2, 3, 4, c=6) # 1 2 6 None (3, 4) {}
# foo(1, 2, sex=\'男\', name=\'alex\', hobby=\'old_woman\') # TypeError: foo() missing 1 required keyword-only argument: \'c\'
# foo(1, 2, 3, 4, name=\'alex\', sex=\'男\') # TypeError: foo() missing 1 required keyword-only argument: \'c\'
foo(1, 2, c=18) # 1 2 18 None () {}
foo(2, 3, [1, 2, 3], c=13, hobby=\'喝茶\') # 2 3 13 None ([1, 2, 3],) {\'hobby\': \'喝茶\'}
foo(*[1, 2, 3, 4], **{\'name\': \'太白\', \'c\': 12, \'sex\': \'女\'}) # 1 2 12 女 (3, 4) {\'name\': \'太白\'}

三、名称空间及作用域

3.1、名称空间

在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了, 至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空.我们首先回忆一下Python代码运行的时候遇到函数是怎么做的,从Python解释器开始执行之后,就在内存中开辟里一个空间,每当遇到一个变量的时候,就把变量名和值之间对应的关系记录下来,但是当遇到函数定义的时候,解释器只是象征性的将函数名读如内存,表示知道这个函数存在了,至于函数内部的变量和逻辑,解释器根本不关心。等执行到函数调用的时候,Python解释器会再开辟一块内存来储存这个函数里面的内容,这个时候,才关注函数里面有哪些变量,而函数中的变量回储存在新开辟出来的内存中,函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存中的所有内容也会被清空。

我们给这个‘存放名字与值的关系’的空间起了一个名字-------命名空间。

代码在运行伊始,创建的存储“变量名与值的关系”的空间叫做全局命名空间;

在函数的运行中开辟的临时的空间叫做局部命名空间也叫做临时名称空间。

现在我们知道了,py文件中,存放变量与值的关系的一个空间叫做全局名称空间,而当执行一个函数时,内存中会临时开辟一个空间,临时存放函数中的变量与值的关系,这个叫做临时名称空间,或者局部名称空间。

其实python还有一个空间叫做内置名称空间:内置名称空间存放的就是一些内置函数等拿来即用的特殊的变量:input,print,list等等,

Python中你所不知道的关于函数的秘密,原来函数这么简单

来源:https://www.cnblogs.com/python147/p/14530350.html
图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Python中你所不知道的关于函数的秘密,原来函数这么简单

相关推荐

  • 暂无文章