python的函数和模块详解

python函数详解

函数

引言:

​ 比如植物大战僵尸,这个游戏本身也是由代码编写,现在假设有一种豌豆射手,每发射一次 炮弹会执行100行逻辑代码

​ 如果我在程序,每当需要发射炮弹的时候,都要编写100行逻辑代码,就会觉得该程序过于冗余, 代码重复度较高。

解决方案:

​ 如果我将这100行代码放到一个区域中,然后给这个区域起一个名字,今后在需要发射炮弹的代码 逻辑中,通过这个名字就可以调用起这100行代码。这个区域【代码段】在python中称之为函 数,先将函数定义出来,并对该函数起一个名字,将来在合适的地方通过函数名调用该函数,执行 该函数的内部逻辑。

函数的定义

  • 语句定义格式:

    # 使用python中的关键字 def
    def 函数名(...):
        函数代码逻辑
    

函数的使用特点

  • 函数不调用不执行
  • 定义函数必须在调用之前出现

函数的参数

  • 参数种类

    • 形式参数:指的是函数定义时,小括号中定义的参数

    • 实际参数:指的是将来调用函数时,实际传入进去的具体的值

      def fun1(hhs, zcy):  # hhs zcy是形式参数,名字自定义
          print(hhs + zcy)
      a1 = int(input("请输入第一个数值:"))
      b1 = int(input("请输入第二个数值:"))
      fun1(a1,b1)  # a1 b1 是实际参数,可以是变量,也可以是具体的值本身
      
      
  • 参数的传值方式

    • 位置传参
    def show1(a, b, c):
        print(f"a:{a},b:{b},c:{c}") # a:11,b:22,c:33
    show1(11, 22, 33)
    
    • 关键字传参【通过传参的名字传参】

      def show1(a, b, c):
          print(f"a:{a},b:{b},c:{c}")
      show1(b=100, c=200, a=300)
      
      
    • 混合传参

      def show1(a, b, c):
          print(f"a:{a},b:{b},c:{c}")
      show1(100, c=200, b=300)
      
      

      注意:混合传参的时候,前面没有关键字的实参是会按照形参的位置来的,后面关键字传参可以顺序不一样。

      函数传参的场景【扩展知识】

      # 未使用函数
      '''
      编写登录时的逻辑代码
      '''
      编写发送邮件的代码 50'''
      编写注册时的逻辑代码
      '''
      编写发送邮件的代码 50
      # 使用函数
      def send_email(xxx,xxx):
      编写发送邮件的代码
      '''
      编写登录时的逻辑代码
      '''
      send_email(xxx,xxx)
      '''
      编写注册时的逻辑代码
      '''
      send_email(xxx,xxx)
      
      
      def send_email(msg_to, send_info):
      import smtplib
      from email.mime.text import MIMEText
      from email.header import Header
      msg_from = 'XXXXXXX@qq.com'  # 发送方邮箱
      passwd = 'XXXXXXXXXXXXXXX'  # 填入发送方邮箱的授权码(填入自己的授权码,相当于邮
      箱密码)
      # msg_to = ['','','']
      subject = "33期邮件信息"  # 主题
      # 生成一个MIMEText对象(还有一些其它参数)
      msg = MIMEText(send_info)
      # 放入邮件主题
      msg['Subject'] = subject
      # 也可以这样传参
      # msg['Subject'] = Header(subject, 'utf-8')
      # 放入发件人
      msg['From'] = msg_from
      # 放入收件人
      # 通过ssl方式发送,服务器地址,端口
      s = smtplib.SMTP_SSL("smtp.qq.com", 465)
      # 登录到邮箱
      s.login(msg_from, passwd)
      # 发送邮件:发送方,收件方,要发送的消息
      s.sendmail(msg_from, msg_to, msg.as_string())
      print('成功')
      p = input("请输入要接收邮件的qq邮箱地址:")
      info = input("请输入要发送的内容:")
      send_email(p, info)
      
      
    • 默认值传参

      需求:调用一个函数,传入一个大字符串和一个小字符串,查找小字符串在大字符串中出现 的次数,调用函数的时候,可以不传小字串,默认查找字符’a’在大字符串中的出现次数。

      def str_number(big_str, small_str='a'): # 定义函数时,可以设置形式参数的值,作为默
      认值
          # dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja
          list1 = list(big_str)
          counts = list1.count(small_str)
          print(f"{small_str}在大字符串中总共出现了{counts}次。。。")
          
      str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja') # 调用时若不传入第二个
      参数,使用的就是定义时的默认值
      str_number('dadqwwfwqfjwqaoiaiosijpoaospjfqwasaapjosaja','f') # 若传入第二个参
      数,使用的就是实际传入的值
      
      
    • 动态传参

      未使用动态参数时,解决需求,比较麻烦,参数需要另外定义一个函数

      # 需求1:定义一个函数,将来传入两个int类型的值求和
      def sum1(a, b):
          print(a + b)
      sum1(10, 20)
      def sum2(a, b, c):
          print(a + b + c)
      # 需求2:定义一个函数,将来传入三个int类型的值求和
      sum2(10, 20, 30)
      

      使用动态参数,只需要定义一个函数就可以了

      def sum1(*num):
          # 这里的num 是一个元组,接收若干个将来调用时传入的实参
          n = 0
          for i in num:
              n = n + i
          print(f"总和为:{n}")
      sum1(10, 20) # (10, 20)
      sum1(10, 20, 30) # (10, 20, 30)
      sum1(10, 20, 30, 40) # (10, 20, 30, 40)
      

      使用动态参数时的注意事项

    • 传参的内容,多个参数的类型可以是不一样的

      def sum1(*num):
          # 这里的num 是一个元组,接收若干个将来调用时传入的实参
          # n = 0
          # for i in num:
          #     n = n + i
          # print(f"总和为:{n}")
          print(num, type(num))
      # sum1(10, 20) # (10, 20)
      # sum1(10, 20, 30) # (10, 20, 30)
      # sum1(10, 20, 30, 40) # (10, 20, 30, 40)
      # sum1(11) # (11,)
      # sum1(11, '小虎', [11, 22, 33]) # (11, '小虎', [11, 22, 33])
      sum1((11,22,33)) # ((11, 22, 33),)
      
      

      传入两个**的动态参数

      def sum1(**num):
          print(num, type(num))
      sum1(name='小虎', age=18)
      
      

      结论:

      * : 表示传入的每一个单独的元素都被封装成一个元组
      ** : 表示传入的是一个一个的键值对,所有的键值对会被封装成一个字典
      我们今后开发的时候,定义动态参数时,起名字是固定的,若一个*的动态参数,名字起为
      *args,**的动态参数,名字起为**kwargs
      动态参数定义的时候,必须
      
      def show1(a, b, *args, **kwargs):
          print(args, type(args))
          print(kwargs, type(kwargs))
      # show1(11,22,33,44,name='小虎',address='合肥')
      show1(11, 22, 33, 44, name='小虎', address='合肥')
      
      

函数的返回值

有些函数,我们调用完之后,是能够得到结果的,理论上来说,python中所有的函数都有返回值

python中提供了一个关键字给我们在函数中使用,表示调用完后返回的值,这个关键字叫做return

  • 例子

    def sum1(a, b):
        c = a + b
        return c
    res1 = sum1(10, 20)
    print(res1)
    print(res1+20)
    
    
  • 函数返回值的特点

    • 一个函数中如果没有写return,默认情况下,这个函数最后一句话会有一个return None

    • return和print的区别?

      • return是调用完函数时,可以返回一个值给调用者
      • print就直接输出了,没有返回值
    • 一个函数中,如果遇到return,那么这个函数就结束了,函数后续代码不执行

      def fun1(a, b):
          print("今天是星期二")
          c = a + b
          return c
          print("明天自习") # 不执行
      res1 = fun1(10, 20)
      print(res1)
      
      
    • 一个函数只能有一个return

      def fun1(a, b):
          print("今天是星期二")
          c = a + b
          return c
          print("明天自习") # 不执行
          return 100  # 无效代码
      res1 = fun1(10, 20)
      print(res1)
      
      def fun1():
          for i in range(1,11):
              return i
      res1 = fun1()
      print(res1)  # 1
      
      
    • 函数返回值return后面,要返回的类型可以是任意的类型

  • 函数参数和返回值的练习

    • 定义 两个函数,第一个函数用户循环输入要累加的数值,函数内部将用户输入的值封装成一 个列表返回;第二个函数将第一个函数返回的列表当作参数传入,返回列表中所有数据之和的 结果。

      def get_list():
          list1 = []
          while True:
              n = int(input("请输入一个数值:"))
              if n == -1:
                  break
              list1.append(n)
          return list1
      def sum_list(l2):
          n = 0
          for i in l2:
              n += i
          return n
      l1 = get_list()
      print(l1)
      res2 = sum_list(l1)
      print(res2)
      
      
  • 函数返回值的一些进阶用法

    • 直接返回多个值,多个值之间用英文逗号分隔,实际返回的内容是一个元组

      def show1():
          return 11, 22, 33
      res1 = show1()
      print(res1, type(res1))
      
    • 分别接收每个返回元素的值

      def show1():
          return 11, 22, 33
      a1, a2, a3 = show1()
      print(f"a1:{a1}")
      print(f"a2:{a2}")
      print(f"a3:{a3}")
      
      
      
      def show1():
          return 11, ['hello','world','python'], 33
      a1, a2, a3 = show1()
      print(f"a1:{a1}") # a1:11
      print(f"a2:{a2}") # a2:['hello', 'world', 'python']
      print(f"a3:{a3}") # a3:33
      

函数的分类

  • 无参无返回值

    def login():
        # 登录的操作逻辑
        
    login()
    
    
  • 无参有返回值

    def get_number():
        # 随机生成一个数
        return num
    n = get_number()
    print(n)
    
    
  • 有参无返回值

    def sum1(a,b):
        print(a+b)
    sum1(10,20)
    
  • 有参有返回值

    def fun1(s1):
        return "shujia:" + s1
    res1 = fun1('hello')
    

函数可以进行嵌套

  • 嵌套调用

    def fun1():
        print("hello world 1")
    def fun2():
        return 100
    def fun3(a1, b1):
        fun1()  # 调用fun1函数
        res1 = fun2()  # 调用fun2函数
        return a1 + b1 + res1
    res2 = fun3(11,22)
    print(res2)
    
    
  • 嵌套定义

    def fun1():
        a = 10
        def fun2():
            print("hello world")
        print(a)
        fun2() # 不调用 不执行
    fun1()
    fun2()  # 报错,调用不了函数内部定义的函数
    
    
  • 函数练习2:定义一个函数,传入一个文本路径,和一个关键词,将文本中包含关键词的那一句话 拿出来放在一个列表中返回该列表

    import os
    def get_word_list(file_os, word):
        res_list = []
        if os.path.exists(file_os):
            f = open(file_os, 'r', encoding='UTF-8')
            line_list = f.readlines()
            for line in line_list:
                if word in line:
                    res_list.append(line.strip())
        else:
            print("该路径不存在!!")
        return res_list
    list1 = get_word_list('data/words.txt', 'shujia')
    print(list1)
    
    def get_word_list(file_os, word):
        res_list = []
        if not os.path.exists(file_os):
            print("该路径不存在!!")
            return res_list
        f = open(file_os, 'r', encoding='UTF-8')
        line_list = f.readlines()
         for line in line_list:
            if word in line:
                res_list.append(line.strip())
        return res_list
    list1 = get_word_list('data/words.txt', 'shujia')
    print(list1)
    

函数的传值问题

在python中,调用函数时,传入的是对象的引用。

  • 不可变对象【str, int, float, bool】

    def fun1(x, y):
        print(f"x:{x}, y:{y}") # x:hello, y:world
        x = y
        x = x + x
        print(f"x:{x}, y:{y}")  # x:worldworld, y:world
    s1 = "hello"
    s2 = "world"
    print(f"s1:{s1}, s2:{s2}")  # s1:hello, s2:world
    fun1(s1,s2)
    print(f"s1:{s1}, s2:{s2}")  # s1:hello, s2:world
    

在这里插入图片描述

不可变对象:指的是函数内的操作不会影响到函数外的变量值

  • 可变对象【list, tuple, dict, set, 类】

    def fun1(x, y):
        print(f"x:{x}, y:{y}") # x:['hello'], y:['world']
        x = y
        x.append('java')
        print(f"x:{x}, y:{y}")  # x:['world','java'], y:['world','java']
    s1 = ['hello']
    s2 = ['world']
    print(f"s1:{s1}, s2:{s2}")  # s1:['hello'] , s2:['world']
    fun1(s1,s2)
    print(f"s1:{s1}, s2:{s2}")  # s1:['hello'], s2:['world', 'java']
    
    

    在这里插入图片描述

可变对象函数内部可以进行操作,改变可变对象中存储的值,间接影响到函数外变量的引用

作用域和变量

  • 在python中,作用域分为两个区域

    • 函数外是一个作用域
    • 函数内部是一个作用域
  • 全局变量:将变量定义在函数外

  • 局部变量:将变量定义在函数内部

  • 全局变量和局部变量使用特点

    • 局部作用域中可以使用到全局变量【可以使用函数外部定义的变量】
    • 函数与函数内部的作用域是相互独立的,不能互相调用函数内部创建的局部变量
    if 1==1:
        a=10
    print(f"a:{a}")
    for i in range(11):
        pass
    print(f"i:{i}")
    
  • python中提供了一个关键字 global, 在函数内部定义一个全局变量,出了函数也是可以被访问到 的。

    def fun1():
        global a
        a = 100
    fun1()
    print(a)
    
    

    注意:如果函数内部有变量被global修饰,需要先调用该函数,让内存中出现这个变量,后 续才能去使用。

进阶:函数名也可以当作一个变量使用

  • 用法场景1:

    def fun1():
        print("好好学习,天天向上!")
    fun2 = fun1
    fun2()
    

    赋值的时候,注意有没有小括号,方法名直接赋值,相当于给函数另起了一个名字;如果加了小括 号,相当于调用函数的结果赋值。

  • 用法场景2:变量可以存储在容易中,比如列表

    def fun1():
        print("鹅鹅鹅")
    def fun2():
        print("曲项向天歌")
    def fun3():
        print("白毛浮绿水")
    def fun4():
        print("红掌拨清波")
    fun_list = [fun1, fun2, fun3, fun4]
    flag = input("请输入开始:")
    for i in fun_list:
        i()
    
    
  • 用法场景:将函数作为返回值使用

    def fun1():
        print("鹅鹅鹅")
    def fun2():
        print("曲项向天歌")
    def fun3():
        print("白毛浮绿水")
    def fun4():
        print("红掌拨清波")
    fun_list = [fun1, fun2, fun3, fun4]
    def show1():
        for i in fun_list:
            i()
    def function1():
        return show1
    res1 = function1()
    res1()
    
  • 用法场景4:将函数作为参数传递

    def fun1():
        print("鹅鹅鹅")
    def fun2():
        print("曲项向天歌")
    def fun3():
        print("白毛浮绿水")
    def fun4():
        print("红掌拨清波")
    fun_list = [fun1, fun2, fun3, fun4]
    def show1():
        for i in fun_list:
            i()
    def function1(s):
        s()
    function1(show1)
    

作业:登录注册的案例

  • main函数要有,用户自己选择要做的功能,根据选择调用不同的函数
  • 用户注册的信息需要使用一个文件存储,登录需要判断用户是否存在,密码是否正确
  • 注册的时候,需要发送邮件

函数和模块

在python开发中,我们需要利用python语言完成现实生活中的场景,python提供了许多内置的函 数和模块给我们使用,完善我们的程序,比如time,random等等模块,如果我们还想要学习其他 的模块,就需要使用第三方模块了。所以在python开发行业中,我们将python开发程序员称之为 调包侠。

内置函数

在这里插入图片描述

  • 数学类函数

    • abs() 求绝对值

      n = -12
      print(abs(n))
      
      
    • sum() 求和 字符串类型的元素不行

      list1 = [11,22,33,44,55]
      res1 = sum(list1)
      print(res1)
      
    • divmod() 传入两个数值,前一个除以后一个,得到两个值:一个商,一个是余数

      s, y = divmod(16, 5)
      print(s)
      print(y)
      
      
    • round() 四舍五入

      n = 12.765
      print(round(n,2)) # 12.77
      
    • pow 求幂次方

      print(pow(2,3))
      
  • 聚合类函数

    • max() 求最大值

      list1 = [123,53,225,1123,52,5,3,14]
      res1 = max(list1)
      print(res1)
      
    • min 求最小值

      list1 = [123,53,225,1123,52,5,3,14]
      res1 = min(list1)
      print(res1)
      
      
    • all 判断一个列表中是否出现一个False

      # 只要存在一个元素转bool类型结果是False,all()的结果就是False
      list1 = [12,45,124,'','hello',12.34]
      print(all(list1))
      
      
    • any 判断一个列表中是否出现一个True

      # 只要存在一个元素转bool类型结果是True,all()的结果就是True
      list1 = [12,45,124,'','hello',12.34]
      print(any(list1))
      
  • 和进制相关的函数

    • 二进制

      bin() 将十进制的值转二进制\

      print(bin(136)) # 0b10001000
      

      int() 将某一种进制转10进制

      print(int('0b10001000',2))
      
    • 八进制

      oct() 将十进制转八进制

      print(oct(136)) # 0o210
      
      
    • 十进制

      整数默认都是十进制

    • 十六进制

      hex() 将十进制转16进制

      print(hex(136)) # 0x88
      

      练习:将ip地址先转二进制,再转回十进制【点分十进制法】

  • 字符类函数

    • ord() 将一个字符转成ASCII码数值

      • ‘0’ - 48

      • ‘A’ - 65

      • ‘a’ - 97

        print(ord('0')) 
        print(ord('A'))
        print(ord('a'))
        
        
    • chr() 将数值转成对应的ASCII码字符

      print(chr(97))
      
  • 类型转换相关函数

    • int()

    • str()

    • bool()

    • list()

    • dict()

    • tuple()

    • set()

    • bytes()

    • float()

      # s1 = '中国'
      # b1 = s1.encode('UTF-8')
      # print(b1, type(b1))
      b2 = bytes('中国','UTF-8')
      print(b2)
      
      
  • 获取输出类函数

    • input()

    • print()

    • len()

    • open()

    • 获取索引和元素

      list1 = [1,2,3,4]
      for i,j in enumerate(list1):
          print(i,j)
      
    • id() 获取对象的地址值

    • callable() 判断一个变量是否是一个函数

      list1 = [1,2,3,4]
      def fun1():
          pass
      print(callable(fun1))
      
      
    • sorted() 排序

      list1 = [34,12,5,12,344,53]
      print(f"list1:{list1}")
      list2 = sorted(list1)
      print(f"list1:{list2}") # list1:[5, 12, 12, 34, 53, 344]
      
      

      自定义排序依据:

      list1 = ['小虎:1007', '黄沪生:1009', '查镕贤:1001', '黄涛:1004', '方直:1002']
      def fun1(e):
          return int(e.split(':')[1])
      list2 = sorted(list1, key=fun1)
      print(f"list1:{list2}")
      
      
    • zip() 将两个序列中的元素一一对应

      list1 = [1001, 1002, 1003, 1004, 1005]
      list2 = ['小虎', '黄沪生', '查镕贤', '黄涛', '方直']
      for i,j in zip(list1,list2):
          print(f"学号:{i}, 姓名:{j}")
      
      

函数生成式

python中提供了一个关键字可以让我们在函数中使用 yield

def fun1():
    yield 1
    yield 2
    yield 3
    yield 4
    yield 5
res1 = fun1()
print("hello world")
print(res1.__next__())
# 若干行代码后
print(res1.__next__())

有yield关键字的函数,结果是可以使用for循环的

def fun1():
    print("hello 1")
    yield 1
    print("hello 2")
    yield 2
    print("hello 3")
    yield 3
    print("hello 4")
    yield 4
    print("hello 5")
    yield 5
res1 = fun1()
for i in res1:
    print(i)
    print("-----------")

def fun1():
   for i in range(1,11):
       yield i
res1 = fun1()
for i2 in res1:
    print(i2)
    print("-----------")

模块

简单理解为就是一个.py后缀的一个文件

  • 内置模块
  • 第三方模块
  • 自定义模块

模块导入的方式

  • import 直接将一个模块导入进来

    import day06.utils.login_tools as t  # 导入login_tools模块并起了一个别名叫做t
    
    
  • from xxx import xxx 从一个模块中,导入具体的工具

    from lxml import etree
    
    from day06.utils.login_tools import rand_yzm # 从模块login_tools中导入某一个函数
    
    
    from day06.utils.login_tools import rand_yzm,send_email # 一次从模块中导入多个
    
    from day06.utils.login_tools import *  # 导入模块中所有的内容
    
    
    from day06.utils.login_tools import rand_yzm as t1 # 导入模块中的函数并重新命名
    
  • 注意: 切记,自己定义的模块名不要和内置或第三方的模块名重名!!!!!

内置模块 random学习

  1. 理论上,python模块中,任意一个地方都可以进行导入
  2. 但是规范上,我们开发潜规则上,将导入的部分放在python模块文件最开始的位置编写
  • randint() 随机生成一个范围内的整数

    n = random.randint(1000,2000)
    print(n)
    
    
  • uniform() 随机生成一个范围内的小数

    n = round(random.uniform(0, 1),2)
    print(n)
    
  • choice() 随机抽取列表中的一个元素

    res1 = random.choice(list1)
    print(res1)
    print(list1)
    
  • sample() 随机抽取列表中若干个元素

    list1 = ['张三','李四','王五','赵六','王麻子','小李子']
    # res1 = random.choice(list1)
    # print(res1)
    # print(list1)
    n = random.sample(list1,2)
    print(n, type(n))
    
    
  • shuffle() 随机打乱列表中的元素

    list1 = ['张三','李四','王五','赵六','王麻子','小李子']
    # res1 = random.choice(list1)
    # print(res1)
    # print(list1)
    # n = random.sample(list1,2)
    # print(n, type(n))
    random.shuffle(list1)
    print(f"list1:{list1}")
    

练习:使用random模块以及之前学习的知识,编写一个抽奖程序。

# 使用random模块以及之前学习的知识,编写一个抽奖程序。
list1 = ['小虎', '张阳', '黄涛', '方一', '杨东', '黄生', '查贤']
jiang_xiang = [
   ('一等奖', 1, 'mate70 pro'),
   ('二等奖', 1, '小米手环'),
   ('三等奖', 2, '按摩仪'),
   ('四等奖', 2, '京东购物卡')
]
def chou_jiang(l1):
    for i, num, goods in jiang_xiang:
        print(f"正在抽取{i}".center(50, '-'))
        name_list = random.sample(l1,num)
        # 将中奖名单从原名单中删除
        for n in name_list:
            if n in l1:
                l1.remove(n)
        info = f"恭喜{','.join(name_list)} 中得{i}!!!!"
        yield info
res1 = chou_jiang(list1)
input("开始抽一等奖....按下回车开始!")
print(res1.__next__())
input("开始抽二等奖....按下回车开始!")
print(res1.__next__())
input("开始抽三等奖....按下回车开始!")
print(res1.__next__())
input("开始抽四等奖....按下回车开始!")
print(res1.__next__())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值