【百度领航团/飞桨/AI Studio】Python 学习笔记 —— 03

前言:第三节课的重点是讲述函数(对象)。之前在这一块很是迷惑。因为带着学过c#的思维理解(而且没学过函数指针),所以一直不能理解python中将函数或是类当作参数传来传去的操作。甚至是返回的参数是就是一个函数或是一个类,一个对象这类的。经过这一节课后,懂了不少。


———————————————

《百度飞桨领航团零基础Python速成营》 课程笔记 —— 03

笔记依据 / 老师讲义:
课节3: Python函数基础
https://aistudio.baidu.com/aistudio/projectdetail/1521458

一、函数 - 定义语法

  • 定义/声明(混淆名词了)一个函数的格式
  • 函数可以返回复数个任何东西,甚至能返回函数或是类的对象。同理,传入的参数也是。
  • 大致格式和C#差不多,别忘了冒号。
def name():
	pass
	return 

him = name()

二、函数 - 参数传递

  • 涉及内容较多,特别不建议混合使用。能打包就打包。有优先级等麻烦问题。以下括号外的专业名词,括号内的是我个人理解的名词。

1)位置参数 - (普通参数)

  • 位置参数是最简单的一种函数调用的方式。位置参数须以正确的顺序传入函数、数量必须和声明时的一样。
def student_name_and_age(name, age):
    print('姓名:%s 年龄 %s' %(name, age))

student_name_and_age('张三', 18)    

2)缺省参数 - (默认参数)

  • 调用函数时,缺省参数的值如果没有传入,则被认为是默认值。
def student_name_and_age(name, age='不愿透露'):
    "设置默认参数"
    print('姓名:%s 年龄 %s' %(name, age))

student_name_and_age('张三')
# 也可以为默认参数赋值
student_name_and_age('张三', 18)

3)可变参数 - (任意数量参数/元组参数)

  • 顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
def all_student_names(*names):
    for name in names:
        print('姓名:', name)
        
all_student_names('张三','李四','王五')        
  • 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个元组(tuple)。
  • 所以下面这个和上面的使用是等效的。
def all_student_names(names):
    for name in names:
        print('姓名:', name)
        
names = ('张三','李四','王五')
all_student_names(names)        

4)关键字参数 - (任意数量参数/字典参数)

  • 关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个字典(dict)。
  • 传入时需要写上参数名 。如果不写就会报错。
def score_info(name, **kw):
    if '语文成绩' in kw:
        print(name, '的语文成绩', kw['语文成绩'])
    if '数学成绩' in kw:
        print(name, '的数学成绩', kw['数学成绩'])
        
def person_info(name, age, **kw):
    print('姓名:', name, '年龄',age)
    score_info(name, **kw)    

score_cfg = {
    
    '语文成绩':65, '数学成绩':60}
person_info('张三', 18, **score_cfg)

5)命名关键字参数 - (限定参数名 的 普通参数)

  • 如果要限制关键字参数的名字,就可以用命名关键字参数。
  • 和普通参数差不多,因为都是有限定数量的,且不输入就会报错。
  • 不同的就是,限定了要指定参数名才能输入。这避免了参数错位,挺好的。不过也麻烦了。在默认参数之间权衡选择使用。
def print_person_info(name, age, *, height, weight):
    print('我的名字叫:', name, '年龄:', age,'身高', height, '体重', weight)
    
print_person_info('张三', 18, height=180)

6)参数的组合

  • 在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
  • 但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def student_info(name, age=18, *books, **kw):
    print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
    if 'city' in kw:
        print('来自:', kw['city'])
    for book in books:
        print('我有',book,'书')

# 理解,先“顺序参数”(个人起的理解名词),再没有参数名的可变参数,再到有参数名的关键字参数。
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)    
  • 位置参数和缺省参数都是“顺序参数”(个人起的理解名词),按顺序一一对应填入。
  • 然后可变参数和关键字参数就是“集合参数”(个人起的理解名词),得到的一堆参数,不强调各个参数之间的顺序,或对应的顺序关系。
def student_info(name, age=18, *books, city, **kw):
	# 注意:!!!特殊要求。
    # 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
    print('我的名字叫:', name, '年龄:', age,'其它信息:',kw)
    print('来自:', city)
    for book in books:
        print('我有',book,'书')
# **顺序必须**是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
student_info('张三', 18, '语文','数学','计算机', city='北京', height=180, weight=75)

三、变量的作用域和全局(global)变量

1.局部变量 作用域:在函数内
2.全局变量 作用域:在函数外
函数优先使用局部变量 在没有局部变量的情况下, 使用全局变量

  • 和C#的情况一致,需要注意的就是类中的变量了。放到下一节讲类时再讲。

四、lambda匿名函数

python 使用 lambda 来创建匿名函数。
lambda 只是一个表达式,函数体比 def 简单很多。
lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
lambda 函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

  • 第一感觉就是类似C#中的宏定义,但是宏定义的本质只是在预处理时替换,并没有起到实际影响代码运行的功能。
  • Python 的匿名函数返回的就是一个函数,只是这个函数在定义时写的代码比较少,看起来比较整洁。而且只能定义时即创建,不能再创建第二个了。
  • 语法上,只有输入输出,没有中间处理过程,只能使用小体量计算。
# 加法运算 接受两个参数,返回参数之和
add = lambda arg1, arg2: arg1 + arg2
add(1,2)

五、高阶函数

  • 这是一个Python的概念词(个人理解),对于“一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数。
  • 在Python中,把函数作为参数传入或返回,都是很正常普遍的操作。所以大部分时候遇到的都是高阶函数。
  • 如果没有这概念的话,刚从C#转战Python就会很懵,不知道为什么一个参数能使用内置方法等。之后有了高阶函数的概念。遇事不决想不通就把它当高阶函数了。在前期理解中能起重要的“定心丸”作用。(个人体会)
# print本身是一个内建函数
print('hello!')

# 函数名其实就是指向函数的变量!
my_print = print 
my_print('a')

# 那么,函数的名字也可以作为一个变量,传入其它函数
def func_x(x, f):
    return f(x)

# 一个函数可以接收另一个函数作为参数,这种函数就称之为高阶函数。
int2str = lambda x : str(x)
func_x(-112, int2str)

1)map / reduce

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。
在这里插入图片描述

ls = [1,2,3,4,5,6,7,8,9]
# 定义一个(匿名)函数,快速创建的好处
fx = lambda x:x**2

# 方法一:
ms = []
for l in ls:
    ms.append(fx(l))

# 方法二:
ms = map(fx, ls)

#以上2者是等效的,都是输出一个列表:[1, 4, 9, 16, 25, 36, 49, 64, 81]

reduce: 用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,依此类推,最后得到一个结果。在这里插入图片描述

# 可能是不常用了?变成模块内的函数了。
# 从python3开始,reduce函数移动到了functools这个包,每次使用前要先import
from functools import reduce

mul_xy = lambda x, y: x*y
reduce(mul_xy, [1, 3, 5, 7, 9])
# 输出:945   # (输出的是一个数,而不是一个列表)

2)sorted - 排序

排序也是在程序中经常用到的算法。无论使用冒泡排序还是快速排序,排序的核心是比较两个元素的大小。如果是数字,我们可以直接比较,但如果是字符串或者两个dict呢?直接比较数学上的大小是没有意义的,因此,比较的过程必须通过函数抽象出来。

菜鸟教程 - Python3 sorted() 函数
https://www.runoob.com/python3/python3-func-sorted.html

sorted([36, 5, -12, 9, -21])
# 输出:[-21, -12, 5, 9, 36]

sorted([36, 5, -12, 9, -21], reverse=True)
# 输出:[36, 9, 5, -12, -21]

# 按绝对值排序key指定的函数将作用于list的每一个元素上,并根据key函数返回的结果进行排序
sorted([36, 5, -12, 9, -21], key=abs)   
# 输出:[5, 9, -12, -21, 36]

六、装饰器

  • 它们是修改其他函数的功能的函数。修改前就要先作为参数传入,所以也就是属于高阶函数。(函数作为返回值

  • 先说一下闭包的概念。

1)闭包

python中的闭包从表现形式上定义(解释)为:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).

  • 从代码上感觉,就是函数内定义函数,多层套娃。
  • 返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
# 一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了f()才执行。
def count():
    fs = []
    for i in range(1, 4):
        def f():
            # print(id(i))
            return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
def count():
    def f(j):
        def g():
            # print(id(j))
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
    return fs
    
# 此时,f1内的还是函数,是 def g() 函数。
f1, f2, f3 = count()

2)装饰器

顾名思义,从字面意思就可以理解,它是用来"装饰"Python的工具,使得代码更具有Python简洁的风格。换句话说,它是一种函数的函数,因为装饰器传入的参数就是一个函数,然后通过实现各种功能来对这个函数的功能进行增强。

菜鸟教程 - Python 函数装饰器
https://www.runoob.com/w3cnote/python-func-decorators.html

# 装饰器输入一个函数,输出一个函数
def print_working(func):
    def wrapper():
        print(f'{func.__name__} is working...') 
        func()
    return wrapper

# 使用方法一
def worker1():
    print('我是一个勤劳的工作者!')
def worker2():
    print('我是一个勤劳的工作者!')
def worker3():
    print('我是一个勤劳的工作者!')

worker1 = print_working(worker1)
worker1()
worker2= print_working(worker2)
worker2()
# 输出:
"""
worker1 is working...
我是一个勤劳的工作者!
worker2 is working...
我是一个勤劳的工作者!
"""

# 使用方法二
@print_working
def worker1():
    print('我是一个勤劳的工作者!')
@print_working
def worker2():
    print('我是一个勤劳的工作者!')
@print_working
def worker3():
    print('我是一个勤劳的工作者!')

worker1()
worker2()
worker3()
# 输出:
"""
worker1 is working...
我是一个勤劳的工作者!
worker2 is working...
我是一个勤劳的工作者!
worker3 is working...
我是一个勤劳的工作者!
"""
  • 从代码上看。其目的是,调用时可以做到在执行函数的同时执行另一部分东西。
  • 主要用途是打印一些信息。其中方法二用到了@修饰,可能实战中比较常用。

装饰器最大的优势是用于解决重复性的操作,其主要使用的场景有如下几个:

  • 计算函数运行时间
  • 给函数打日志
  • 类型检查
    当然,如果遇到其他重复操作的场景也可以类比使用装饰器。
def arg_decorator(func):
    def wrapper(*args, **kw):
        print(f'{func.__name__} is working...')
        func(*args, **kw)
    return wrapper

# 带参数的装饰器
@arg_decorator
def student_info(name, age=18, *books, **kw):
    print(f'我的名字叫{name}, 今年{age}岁,我有很多本书:')
    for book in books:
        print(book)
    print(kw)

student_info('Molly',18, '语文书','数学书',height=170)

3)偏函数 - partial

通过设定参数的默认值,降低函数调用的难度

# 这个函数也在新版python被归类到模块内了
from functools import partial

def student_info(name, age, city):
    print(f'我的名字叫{name}, 今年{age}岁,来自{city}')

# 使用 partial 设置默认参数
student_info_beijing = partial(student_info, city='北京')

# 调用时就可以输入或不输入
student_info_beijing('Molly',18, city='上海')
student_info_beijing('Molly',18)

七、模块

1)导入

  • 常用的就三个导入模块的指令。其他的不赘述了。
import … 语句
fromimport/ * 语句 
importas … 语句

2)__name__属性

一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。

# 说明: 每个模块都有一个__name__属性,当其值是'__main__'时,表明该模块自身在运行,否则是被引入。
if __name__ == '__main__':
   print('程序自身在运行')
else:
   print('我来自另一模块')

3)dir() 函数

内置的函数 dir() 可以找到模块内定义的所有名称。以一个字符串列表的形式返回:

import fibo, sys
# 如果没有给定参数,那么 dir() 函数会罗列出当前定义的所有名称:
dir(fibo)
dir(sys)
# 输出一堆内容,包含内置隐藏或是不隐藏的所有属性或方法等的名称。

4)安装/卸载第三方模块

pip install / uninstall
conda install / uninstall

  • 起初不知道 conda是什么指令(虽然现在也不清楚,可以用来创建环境空间,也能用来安装),使用conda指令安装一直显示连接失败。后来才知道,教程说的是可以选择pip安装或是conda安装,二选一。果断选pip

八、大作业

  • 第三天课程布置了一个“大作业”。要求是:统计英语6级试题中所有单词的词频,并返回一个如下样式的字典。
  • 按着第二节课的知识,试了几个函数终于完成了。听说用正则表达式更简单。看了另一位大佬的总结,果然如此。
  • 不用正则表达式写的话,大致流程都一样的,我不另列了。“程序员最讨厌重复劳动了”。

[Paddle领航团python基础课程大作业一]英文词频的统计任务
https://blog.csdn.net/weixin_45623093/article/details/113746031

猜你喜欢

转载自blog.csdn.net/Lovely_him/article/details/113748392