py---------初始函数

一、函数

为什么要用函数?

现在python届发生了一个大事件,len方法突然不neng直接使用了了。。。

然后现在有个一个需求,让你计算"hello world"的长度,你怎么计算?

这个需求真的不难,现在你的水平轻飘飘的就完成,来写一下

s1 = "hello world"
length = 0
for i in s1:
    length = length + 1
print(length)

好了,功能实现了,非常perfect,然后现在又有个需求了,需要再计算另外一个字符串的长度,"“hello zhishu”,于是代码就变成下面这样了:

复制代码
s1 = "hello world"
length = 0
for i in s1:
    length = length + 1

print(length)
s2
= "heelo zhizhu" length = 0 for i in s2: length += 1 print(length)
复制代码

这样确实是实现了len需求功能,但是如果有壹佰亿个难道写壹佰亿个for循环吗?

首先,之前只要我们执行len方法就直接可以拿到一个字符的长度了,现在为了实现这个功能需要把重复的代码写好多遍----- 代码冗余

其次,之前的读起来也很简单,一看代码就只到是计算长度,上面的代码却不容易读懂----- 可读性差

 

print(len(s1))
print(len(s2))

然zhishu就开始想了,怎么能像使用len一样计算我们这段代码呢,就想把这段代码起一个名字,然后用它的话就直接调用它的的名字,是不是很完美?

 

二、初识函数定义与调用

现在交大家一个技能,把代码封装起来。

def mylen():
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    print(length)

我们来分析下这段代码做额什么。

其实除了 def 这一行和后面的进行缩进,其他代码的好像没有啥变化。我来执行一下,搜嘎,好像啥也没发生。

刚刚我们已将说过,这是把代码装起来的过程。你现在只会往里面装,还不会往出拿。那么应该怎么往出拿呢? 

我来告诉大家:

mylen()

是不是很简单? 是不是似曾相识过呢? 这就是代码取出来的过程。刚刚就写了一个函数,并且我们成功的调用了它。

函数的定义和调用:

复制代码
#h函数定义
def mylen():
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    print(length)

#函数调用
mylen()
复制代码

总结一:

定义:def  关键词开头,空格之后接函数名称和圆括号(),最后还有一个 “:”。 

   def  是固定的,不能变,必须是连续的 def 三个字母,不能分开。。。

   空格: 是为了将 def关键字和函数名分开,必须空(四声),当然你可以空2格、3格,但是正常人还是空1格。

   函数名函数名只能包含字符串、下划线和数字且不能以数字开头。虽然函i数名可以随便起,但我们给函数起名字还是尽量要简短,并能表达函数意义,然人一看就知道是定义的什么函数。

   括号:是必须加的,先别问为啥要有括号,总之加上就对了!

注释:每一个函数都对应该对功能和参数进行相应的说明,应该写在函数的上面第一行。以增强代码可读性。

调用: 就是 函数名() 要记得加上括号。好么好么好么。

 

三、函数的返回值

刚刚我们就写了一个函数,这个函数可以帮助我们计算字符的长度,并且把结果打印出来。但是,这和我们 len 方法还是不太一样。哪里不一样呢?以前我们调用 len 方法会得到一个值,我们必须用一个变量来接收这个值。

str_len = len("hello world")

这个 str_len 就是“hello world”的长度。那我们自己写的函数能做到这一点吗?我们也来试一下。

复制代码
#定义函数
def mylen():
    '''计算s1长度'''
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    print(length)

#函数调用
str_len=mylen()
print('str_len:%s'%str_len)

11
str_len:None
函数调用的结果
复制代码

很遗憾,执行上面的代码,得到str_len 值为None, 这说明我们的这段代码什么也没有返回给我们。

那如何让它也跟 len一样返回值呢?

复制代码
#定义函数
def mylen():
    '''计算s1长度'''
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    return length

#函数调用
str_len=mylen()
print('str_len:%s'%str_len)
View Code
复制代码

我们只需要在函数的最后加上一个return,return后面加上你要返回的值就可以了。

接下来,我们研究一下 return 的用法。

return关键字的作用

  return是一个关键字,在pycharm 里,你会看到它变成蓝色。你必须 一字不差的把这个单词背下来。

  这个中文意思就是 “返回”,所以我们管写在 return 后面的值叫 “返回值”。

要研究返回值,我们还要知道返回值有几种情况: 没有返回值、返回一个值、返回多个值

没有返回值:

  不写 return 的情况下,默认会返回一个None;我们写的第一个程序,就没有写return,这也属于没有返回值的一种情况。

复制代码
#定义函数
def mylen():
    '''计算s1长度'''
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    print(length)

#函数调用
str_len=mylen()
#因为没有返回值,此时str_len结果为None
print('str_len:%s'%str_len)
不写 return
复制代码

  只要我们写return,后面不写其他内容,也会返回一个None,有的同学会奇怪了,既没有要返回值,完全可以不写 return,为什么还要写个 return 呢?这里我们要说明一下 return 的其他用法,就是一旦遇到return,结束整个函数运行。

复制代码
def ret_demo():
    print(111)
    return
    print(222)

ret = ret_demo()
print(ret)

111
None
只写 return
复制代码

return None:和上面的两种情况一样,我一般不会这么写。

复制代码
def ret_demo():
    print(111)
    return None
    print(222)

ret = ret_demo()
print(ret)
return None
复制代码

返回一个值:

  刚刚我们已经写过一个返回一个值的情况,只需要在 return 后面写上要返回的内容就可以了。

 

复制代码
#函数定义
def mylen():
    '''计算s1长度'''
    s1 = "hello world"
    length = 0
    for i in s1:
        length += 1
    return length

#函数调用
str_len = mylen()
print('str_len:%s'%str_len)
返回一个值
复制代码

 

返回多个值:

  可以返回任意多个。任意数据类型的值

 

复制代码
def ret_demo1():
    '''返回多个值'''
    return 1,2,3,4

def ret_demo2():
    '''返回多个任意类型的值'''
    return 1,['a','b'],3,4

ret = ret_demo1()
print(ret)
ret2 = ret_demo2()
print(ret2)
返回多个值
复制代码

 

  返回的多个值会被组织成元祖被返回,也可以用多喝值来接受

复制代码
def ret_demo2():
    return 1,['a','b'],3,4

#返回一个值,用一个变量接收
ret2 = ret_demo2()
print(ret2)

#返回多个值,用多个变量接收
a,b,c,d = ret_demo2()
print(a,b,c,d)

#用多个值接收返回值:返回几个值,就用几个变量接收
a,b,c,d = ret_demo2()
print(a,b,c)
多个返回值的接收
复制代码

  原因:

>>> 1,2        #python中把用逗号分割的多个值就认为是一个元组。
(1, 2)
>>> 1,2,3,4,
(1, 2, 3, 4)
>>> (1,2,3,4)
(1, 2, 3, 4)
复制代码
#序列解压一
>>> a,b,c,d = (1,2,3,4)
>>> a
>>> b
>>> c
>>> d
#序列解压二
>>> a,_,_,d=(1,2,3,4)
>>> a
>>> d
>>> a,*_=(1,2,3,4)
>>> *_,d=(1,2,3,4)
>>> a
>>> d
#也适用于字符串、列表、字典、集合
>>> a,b = {'name':'eva','age':18} 
>>> a
'name'
>>> b
'age'
序列解压扩展
复制代码

 

四、函数的参数

  现在,我们已经把函数返回值相关的事情研究清楚了,我们自己已经完成一个可以返回字符串长度的函数。但是现在这个函数还是不完美,之前我们只用 len 函数的时候是 length= len(“hello world”),这样我可以想计算谁就计算谁的长度。但是现在我们写的这个函数,只能计算一个"hello world"的长度,换一个字符串就不可以了。想什么办法呢?

复制代码
#函数定义
def mylen(s1):
    """计算s1的长度"""
    length = 0
    for i in s1:
        length += 1
    return length

#函数调用
str_len = mylen("hello world")
print('str_len : %s' %str_len)
带参数的函数
复制代码

  我们告诉 mylen 函数要计算的字符串是谁,这个过程就叫传递参数,简称传参,我们调用函数的时传递的这个"hello world"和定义函数时的 s1 就是 参数。

 

实参与形参

参数还有分别:

我们 调用 函数时传递的这个 “hello world” 被简称为实际参数。因为这个是实际的要交给函数的内容,简称实参。

定义函数时的s1,只是一个变量的名字,被称为形式参数,因为在定义函数的时候它只是一个形式,表示这里有一个参数,简称形参

传递多个参数:

参数可以传递多个,多个参数之间用过逗号分隔。

复制代码
def mymax(x,y):
    the_max = x if x > y else y
    return the_max

ma = mymax(10,20)
print(ma)
传递多个参数
复制代码

正是因为需要传递多个参数,才有了后面一系列有关参数的小故事。。。

 

位置参数

站在实参角度

  1、按照位置传值

 

def mymax(x,y):
    #此时x=10,y=20
    the_max = x if x > y else y
    return the_max

ma = mymax(10,20)
print(ma)

 

  2、按照关键字传值

复制代码
def mymax(x,y):
    #此时x=10,y=20
    the_max = x if x > y else y
    return the_max

ma = mymax(y=10,x=20)
print(ma)
按照关键字传参
复制代码

  3、位置,关键字形式混合用

复制代码
def mymax(x,y):
    #此时x=10,y=20
    the_max = x if x > y else y
    return the_max

ma = mymax(10,y=20)
print(ma)
位置,关键字混合传参
复制代码

正确用法

问题1:位置参数必须在关键字参数前面

问题2:对于一个形参只能赋值一次

 

站在实参角度:

  位置参数必须传值

复制代码
def mymax(x,y):
    print(x,y)
    the_max = x if x > y else y
    return the_max

#调用mymax不传递参数
ma = mymax()
print(ma)


#结果
TypeError: mymax() missing 2 required positional arguments: 'x' and 'y'
位置参数必须传参
复制代码

 

关键字参数(指定参数)

复制代码
>>> def ret(a,b,c):
...  print(a,"a")
...  print(b,"b")
...  print(c,"c")
...
>>> ret(b="bbb",a="aaa",c="ccc")
aaa a
bbb b
ccc c
关键字参数
复制代码

默认情况在再函数ret括号内如果要输入函数参数的值,是要按照顺序来的,但是如果在ret括号内制定的参数的值,那么就不需要按照顺序来了。

=========

关键字实参需要注意的问题是:

def foo(name,age,sex):
    print(name)
    print(age)
    print(sex)

问题1:语法规定位置实参必须在关键字实参的前面

foo('egon',sex='male',age=18)    #正确

问题2:一定不要对同一个形参传多次值

foo('egon',sex='male',age=18,name='egon1')    #报错

 

默认参数

1、正常使用

  使用方法

  为什么要有默认参数:将变化比较小的值设置成默认参数

2、默认参数定义

  给函数的值指定一个默认值,指定函数的默认值需要在def这一行指定,制定之后,当调用这个函数的时候就不需要输入函数值了。

复制代码
def stu_info(name,sex = "male"):
    """打印学生信息函数,由于班中大部分学生都是男生,
       所以设置默认参数 sex de 的值为 'male'
    """
    print(name,sex)

stu_info('zhishu')
stu_info('eva','female')       # 如果值指定默认值,那么实际参数替换掉形式参数

zhishu male 
eva female 
复制代码

默认参数需要注意的问题:

问题1:默认参数必须放在位置参数之后

复制代码
def foo(y=1,x):        #报错
    print(x,y)

def foo1(x,y=1):       #正确
    print(x,y)
foo1(3)
View Code
复制代码

问题2:默认参数只在定义阶段赋值一次,而且仅一次

复制代码
x=100
def foo(a,b=x):
    print(a,b)
x=123123
foo('egon')

egon 100     #结果x=123123 没有生效
View Code
复制代码

 

参数陷阱:默认参数是个可变数据类型。(所有必须定义一个不可变类型)

复制代码
def default_param(a,l=[]):
    l.append(a)
    print(l)

default_param('alex')
default_param('egon')

['alex']
['alex', 'egon']   #会把原来的值一同赋值过来,在传参还会
赋值
参数陷阱
复制代码

 

动态参数

  按位置传值多余的参数都有args统一接收,保存成一个元祖形式,每个参数都是元祖中一个元素。

第一种动态参数

定义第一种动态参数需要在参数前面加上一个*

def mysum(*args):
    the_sum = 0
    for i in args:
        the_sum += i
    return the_sum

the_sum = mysum(1,2,3,4,5)    #(*args)接收所有mysum传的值
print(the_sum)

 第二种动态参数

定义第二种动态参数需要在参数前面加上两个*号,给参数传参的时候是一个key对应一个value的,相当于一个字典的键值对,而且返回的类型就是字典类型。

复制代码
#例1
def stu_info(**kwargs):
    print(kwargs)
    print(kwargs['name'],kwargs['sex'])

stu_info(name='alex',sex='male')

#例2
def ret(**kwargs):
    print(kwargs,type(kwargs))

ret(k1=123,k2=456)


#结果
{'name': 'alex', 'sex': 'male'}
alex male
{'k1': 123, 'k2': 456} <class 'dict'>
**kwags应用
复制代码
复制代码
def ret(**kwargs):   #1
    print(kwargs)        #4   #4-1

dic = {'name':"zhishu",'age':"17"}   #2

ret(dic2= dic)        #3-1

ret(**dic)            #3
字典小例子
复制代码

第三种动参数 (万能的动态参数)

复制代码
def ret(*args,**kwargs):
    print(args)
    print(kwargs)

ret(11,22222,33,44,k1=111,name='zhishu',age='17')
View Code
复制代码

 

本章小结

面向过程编程的问题:代码冗余、可读性差、可扩展性差(不易修改)

定义函数的规则:

复制代码
1、定义:def 关键之开头,空格之后接函数名称和圆括号()。

2、参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号隔开。

    参数也可以定义多个,也可以不定义参数

    参数有很多种,如果涉及到多种参数定义,定义顺序为:位置参数、*kwargs、默认参数、**kwargs顺序定义。

    如上述定义过程中哪个参数缺省,其他参数依旧按顺序定义。

3、注释:函数第一行语句应该添加注释。

4、函数体:函数内容以 冒号 开始,并且缩进。

5、返回值:return [表达式] 结束函数。不带表达式的 return 相当于返回 return None

def 函数名(参数1,参数2,*args,默认参数,**kwargs):
    """注释:函数功能和函数参数"""
    函数体
    ......
    return 返回值
复制代码

调用函数规则:

复制代码
1.函数名()
    函数名后面+圆括号就是函数的调用

2.参数:
    圆括号用来接受参数。
    若传入多个参数值:
        应按先位置来传值,在按关键字传值
        具体的传入顺序按照定义的参数而定

3.返回值
    若果函数有返回值,还应该定义“变量”接收返回值
    若果返回值多个,也可以用多个变量来接收,变量应和返回值数目一致
    
无返回值的情况:
函数名()

有返回值的情况:
变量 = 函数名()

多个变量接收多个返回值:
变量1,变量2,... = 函数名()
复制代码

 



 

 

 

  

     

 

 

 

 

 

 

 

测试题

第一题

简述普通参数、指定参数、默认参数、动态参数的区别

普通参数即是用户在调用函数是填入的参数,且参数位置必须与参数保持一致。

指定参数即在用户调用函数的时候不需要按照函数中参数的位置中所填写,指定参数是需要制定参数对应的值。

默认参数可以写在定义参数的后面,如果用户调用函数是没有制定参数,那么就会用默认参数,如果用户指定了参数,那么用户指定的参数就会代替默认参数。

动态参数可以接受用户输入的任何参数,包括字典、列表、元组等数据类型。

第二题

计算传入字符串中数字、字母、空格以及其他的个数

复制代码
def var(s):
    all_num = 0
    spance_num = 0
    digit_num = 0
    others_num = 0
    for i in s:
        # 检测数字
        if i.isdigit():
            digit_num += 1
        # 检测空格
        elif i.isspace():
            spance_num += 1
        # 检测字母
        elif i.isalpha():
            all_num += 1
        else:
            # 其他
            others_num += 1
    return ("字母:",all_num,"空格:",spance_num,"数字",digit_num,"其他字符",others_num)
num = var("21323 asd*%^*^% &*213asdasdasda sdasdasd")
print(num)
复制代码

执行结果

C:\Python35\python.exe F:/Python_code/sublime/operation/Day05/c.py
('字母:', 21, '空格:', 3, '数字', 8, '其他字符', 8)

第三题

写函数,判断用户传入的对象(字符串、列表、元组)长度是否大于5,如果大于5就返回True,如果小于5就返回False

复制代码
# 定义一个函数num
def num(x):
    # 判断函数的值如果长度大于5就返回True
    if len(x) > 5:
        return True
    # 否则就返回False
    else:
        return False
ret = num(["asd","asdasd","asdasd","asdasd"])
print(ret)
ret = num("asdasdasd")
print(ret)
复制代码

第四题

写函数,检查用户传入的对象(字符串、列表、元组)的每一个元素是否含有空内容,如果有空就返回False

复制代码
# 定义一个函数num
def num(x):
    # 循环输出num内的所有内容
    for n in x:
        # 数据类型转换为字符串
        n = str(n)
        # 如果有空格就返回False
        if n.isspace():
            return False
ret = num(" ")
print(ret)
ret = num("asdasd")
print(ret)
ret = num(["asd","312",123," "])
print(ret)
复制代码

第五题

写函数,检查传入列表的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

def num(x):
    # 如果列表中的长度大于2,那么就输出列表前两个内容,否则就返回一个空
    if len(x) > 2:
        return x[:2]
    else:
        return ""
print(num(["11","22","33"]))
print(num(["33"]))

第六题

写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者。

复制代码
def num(x):
    # 定义一个空列表用于接收奇数位的元素
    resule = []
    # 循环输出列表中的所有元素值
    for n in range(len(x)):
        # 如果列表中的位置为奇数就把值添加到resule列表中
        if n % 2 == 1:
            resule.append(x[n])
    # 然会resule列表中的内容
    return resule
ret = num([11,22,33,44,55,66])
print(ret)
复制代码

第七题

写函数,检查传入字典的每一个value的长度,如果大于2,那么仅保留前两个长度的内容,并将新内容返回给调用者。

dic = {"k1": "v1v1", "k2": [1111,22,33,44]}

PS:字典中的value只能是字符串或列表

代码

复制代码
def dictt(x):
    # 循环字典中所有的key
    for k in x.keys():
        # 如果字典中k对应的元素是字符串类型就下面的判断
        if type(x[k]) == str:
            # 如果元素的长度大于2
            if len(x[k]) > 2:
                # 那么就让这个元素重新赋值,新的值只保留原来值的前两个
                x[k]=x[k][0:2]
        # 如果字典中k对应的元素类型是列表,就进入下面的判断
        elif type(x[k]) == list:
            # 先把列表中的值全部for循环
            for i in x[k]:
                # 把元素转换为字符串
                string = str(i)
                # 如果元素的长度大于2
                if len(string) > 2:
                    # 获取元素的索引值
                    num = x[k].index(i)
                    # 先把这个元素给删除
                    x[k].pop(x[k].index(i))
                    # 然后再添加一个新的元素,新元素的只保留原来元素的前两个
                    x[k].insert(num,string[:2])
    # 把结果return出来
    return dic
ret = dictt(dic)
print(ret)
复制代码
  • 执行结果

C:\Python35\python.exe F:/Python_code/sublime/operation/Day05/h.py
{'k1': 'v1', 'k2': ['11', 22, 33, 44]}

#

 

posted @   王竹笙  阅读(221)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示