Python学习笔记(二):函数

python英文官方文档:https://docs.python.org/3.8/tutorial/index.html
比较不错的python中文文档:https://www.runoob.com/python3/python3-tutorial.html

1. 写在前面

这几周从实践角度又学习了一遍python,温故而知新,还是有蛮多心得的, 周末再看之前记的python笔记,总觉得零零散散, 未成体系,所以后面这段时间,陆续对之前的python笔记做一次整合, 使得内容更加清晰,成体系,做到简单可依赖,既是复习,也方便以后回看回练。希望能帮助到更多的伙伴啦。

这是第二篇文章,主要整理python函数相关的内容,函数初识到高级特性再到函数式编程,层层递进。既有基础,又有新知识,这样更有意思一些。

文章很长,内容很多,各取所需即可 😉

大纲如下:

  • 1. 写在前面
  • 2. 函数基础
    • 2.1 函数初识
    • 2.2 global和nonlocal
    • 2.2 参数总结
      • 2.2.1 默认参数
      • 2.2.2 可变参数
      • 2.2.3 关键字参数
      • 2.2.4 命名关键字参数
      • 2.2.5 使用总结
      • 2.2.6 逆向参数收集
    • 2.3 值传递和引用传递
    • 2.4 高级特性
      • 2.4.1 切片、迭代、列表生成
      • 2.4.2 生成器
      • 2.4.3 迭代器
    • 2.5 给函数写说明文档
  • 3. 函数式编程
    • 3.1 高阶函数
      • 3.1.1 map/reduce
      • 3.1.2 filter
      • 3.1.3 sorted
      • 3.1.4 使用小总
    • 3.2 函数作为返回值
      • 3.2.1 函数懒加载
      • 3.2.2 闭包
    • 3.3 匿名函数
    • 3.4 装饰器
    • 3.5 偏函数
  • 4. 常用内置函数
    • 4.1 数学运算
    • 4.2 逻辑运算
    • 4.3 进制转化
    • 4.4 类型相关
    • 4.5 类相关
    • 4.6 eval和exec
  • 5. 小总

Ok, let’s go!

2. 函数基础

2.1 函数初识

函数,完成特定功能的代码封装, 一次编写多次调用,避免反复写代码。这里先整理一些基础操作。

# 1. 函数起别名: 函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量
a = abs # 变量a指向abs函数
a(-1) # 所以也可以通过a调用abs函数
1
# 这个在用Pytorch搭建神经网络的时候经常遇到这种起别名的操作

# 2. 空函数 Python中有个比较骚的操作就是可以定义一个函数,但是什么都不写
# # 那有什么用? 写程序的时候,我们往往喜欢先搭一个简单的框架出来, 把各种函数定义好放那,至于作用可能一时半会还没想好,这时候就可以放一个pass, 让代码运行起来再说
def nop():
    pass
 
if age >= 18:
	pass          # 如果这时候缺少pass,就会报语法错误


# 3. Python貌似可以返回多个值呢? 但是真的是这样吗?
def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
  
# 调用
a, b = move(x,y)
# 上面代码看起来,好像python的return可以同时返回多个值, 其实这是一种假象, python函数返回的仍然是单一值,只不过这个单一值是一个元组。 在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便

2.2 global和nonlocal

在Python中,globalnonlocal关键字用于在不同作用域内访问和修改变量。这两个关键字在处理嵌套函数或全局变量时特别有用

# 1. global关键字用于在局部作用域中声明全局变量。当你在一个函数内部想要修改外部定义的全局变量时,就需要使用global。
x = 5
def func():
    global x  # 声明x是全局变量
    x = 10  # 修改全局变量x的值
func()
print(x)  # 输出 10

# 2. nonlocal关键字用于在闭包或嵌套函数中声明一个变量指向非全局作用域,例如指向外层(但非全局)作用域的变量。它使得我们能够修改位于嵌套作用域中的变量。
def outer():
    y = 5
    def inner():
        nonlocal y  # 声明y不是局部变量,而是外层函数的变量
        y = 10
    inner()
    print(y)  # 输出 10

outer()

# 注意:
	# 1. global关键字使得局部作用域可以修改全局作用域中的变量。
	# 2. nonlocal关键字确保变量指向最近的外层作用域(非全局作用域),并且可以在那个作用域中修改它。
	# 3. 不应当滥用global和nonlocal关键字,因为它们会使得代码变得难以理解和维护。在可能的情况下,最好使用函数参数和返回值来传递和接收数据,而非依赖外部状态。
	# 4. nonlocal不能用于访问全局作用域的变量,它只适用于嵌套的局部作用域中。

如下,函数 f 里嵌套一个函数auto_increase。实现功能:不大于 10 时自增,否则置零后,再从零自增。

# 函数 f 里嵌套一个函数auto_increase。实现功能:不大于 10 时自增,否则置零后,再从零自增。
def f():
    i = 0
    def auto_increase():
        nonlocal i    # 使用 nonlocal 告诉编译器,i 不是局部变量 , 如果没有这句话, 函数会报错, 说i没有在函数里面声明赋值
        if i >= 10:
            i = 0 
        i += 1
    ret = []
    for _ in range(28):
        auto_increase()
        ret.append(i)
    print(ret)

f() # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8]

2.2 参数总结

2.2.1 默认参数

python函数定义的时候可以给出默认参数, 这样简化了函数调用的难度, 无论是简单调用还是复杂调用, 函数只需要定义一个即可。 举个例子体会一下:

# 一个一年级小学生注册的函数, 需要传入name和gender两个参数:
def enroll(name, gender):
	print(name)
	print(gender)

# 这样调用的时候只需要传入两个参数
enroll('Sarah', 'F')              # 就会输出名字和性别

但是如果我想传入年龄, 城市等信息怎么办, 上面那个就不能用了, 所以看看有默认参数的函数:

def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)

这样, 大多数学生注册的时候不需要提供年龄和城市,只提供必须的两个参数性别和姓名。 依然可以:

enroll('Sarah', 'F') 

# 但这个还可以更复杂的调用
enroll('Bob', 'M', 7)
enroll('Adam', 'M', city='Tianjin')

所以默认参数的使用还是非常方便的,在定义神经网络函数的时候,就通常会有默认的学习率, 迭代次数等参数。 但也有一个注意的点: 首先就是设置的时候, 必选参数要放在前面,默认参数要放后面, 否则解释器不知道你使用的是默认参数还是必选参数。 其次就是默认参数的顺序, 变化大的放前面, 变化小的放后面。 最后,有多个默认参数时, 调用的时候既可以按顺序提供默认参数,也可以不按顺序提供, 但此时要把默认参数的参数名加上。(上面那个例子)

关于默认参数的使用, 还会有坑:默认参数必须指向不变对象!, 这是啥意思, 下面演示一个例子:我定义了一个函数, 传入一个list

def add_end(L=[]):
	L.append('END')
	return L

# 我正常调用
add_end([1, 2, 3])    # [1, 2, 3, 'END']
add_end(['x', 'y', 'z'])    # ['x', 'y', 'z', 'END']

# 我使用默认参数调用, 加了三次end
a = add_end()
b = add_end()
c = add_end()

# 你知道执行之后, a, b, c都是什么值了吗?
print(a)     # ['END', 'END', 'END'] 
print(b)     # ['END', 'END', 'END'] 
print(c)     # ['END', 'END', 'END'] 

为什么默认参数是[], 但是函数似乎每次都“记住了”上次添加了’END’后的list呢? 这是因为Python函数在定义的时候, 默认参数L的值就被计算出来了,即[], 因为默认参数L也是一个变量, 它指向对象[], 每次调用该函数, 如果改变了L的内容, 则下次调用的时候, 默认参数的内容就变了,不再是函数定义时的[]了。所以, 默认参数必须指向不变对象!。 要修改上面例子,我们可以使用不变对象None来实现:

def add_end(L=None):
	if L is None:
		L = []
	L.append('END')
	return L

a = add_end()
b = add_end()
c = add_end()
print(a)   # ['END']
print(b)   # ['END']
print(c)    # ['END']

# 可以和上面进行一个对比

为什么要设计str、None这样的不变对象呢? 因为不变对象一旦创建, 对象内部的数据就不能修改, 这样就减少了由于修改数据导致的错误。 此外,由于对象不变, 多任务环境下同时读取对象不需要加锁,同时读问题不会产生。 我们编写程序时,如果可以设计一个不变对象, 那就尽量设计成不变的对象。 如果想查看一个函数使用了什么默认值,可以用fun_name.__defaults__查看。

2.2.2 可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。 这个之前确实不知道是啥意思,所以在这里整理一下, 以一个数学题为例子:

给定一组数字a, b, c…, 计算 a 2 + b 2 + c 2 . . . . . a^2+b^2+c^2..... a2+b2+c2.....

要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来

def calc(numbers):
	sum = 0
	for n in numbers:
		sum += n * n
	return sum

# 分分钟搞定, 然后我们调用, 得先组装成一个数组
calc([1, 2, 3])    # 14
calc((1, 3, 5, 7))   # 84

如果利用可变参数的话,我们就可以不用先组装成数组往里面传:

def calc(*numbers):
	sum = 0
	for n in numbers:
		sum = sum + n * n
	return sum

# 这时候调用
calc(1, 2, 3)
calc(1, 3, 5, 7)
# 甚至不传都可以
calc()

定义可变参数和定义一个list或者tuple参数相比,仅仅在参数前面加了一个*(可千万别认为这成了指针了, python中就没有指针一说),在函数内部, 参数numbers接收的是一个tuple, 因此函数代码完全不变,调用该函数时,可以传入任意个参数, 包括0个参数。

如果此时有了一个list或者tuple, 要调用一个可变参数怎么办?

# 可以这样做
nums = [1, 2, 3]
calc(nums[0], nums[1], nums[2])

# 但上面这样更加繁琐,所以可以直接在nums前加*, 把list或tuple元素变成可变参数传入:
calc(*nums)

这种写法也是非常常见, *nums表示把nums这个list的所有元素作为可变参数传进去。

2.2.3 关键字参数

可变参数允许传入0和或者任意个参数, 这些可变参数在调用时自动组装成一个tuple。 而关键字参数允许传入0个或者任意个含参数名的参数, 这些关键字参数在函数内部自动封装成一个dict, 就是带名字的参数,可以传入任意个, 看例子就明白了:

def person(name, age, **kw):
	print(name, age, kw)

person('Michael', 30)    # Michael  30  {}
person('Bob', 35, city='Beijing')   # Bob  35  {'city':'Beijing'}
person('Adam', 45, gender='M', job='Engineer')   # Adam 45 {'gender':'M', 'job':'Engineer'}

关键字参数有什么用呢? 它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

extra = {
   'city':'Beijing', 'job':'Engineer'}
person('Jack', 34, **extra)   # name: Jack age: 34 other: {'city': 'Beijing', 'job': 'Engineer'}

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra

2.2.4 命名关键字参数

对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数,如果要限制关键字参数的名字,就可以用命名关键字参数:

def person(name, age, *, city, job):
    print(name, age, city, job)

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符**后面的参数被视为命名关键字参数。调用的时候,必须传入参数名, 否则,解释器会报错。

person('Jack', 24, city='Beijing', job='Engineer')
person('jack', 24, 'Beijing', 'Enginneer')   # 这种会报错, 解释器会看成四个位置参数, 但其实person函数有两个位置参数, 后面的两个叫做命名关键字参数

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数。

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差。 多了,自己都不知道咋调用了! 会出现这样的一些报错:

  • SyntaxError: positional argument follows keyword argument,位置参数位于关键字参数后面
  • TypeError: f() missing 1 required keyword-only argument: 'b',必须传递的关键字参数缺失
  • SyntaxError: keyword argument repeated,关键字参数重复
  • TypeError: f() missing 1 required positional argument: 'b',必须传递的位置参数缺失
  • TypeError: f() got an unexpected keyword argument 'a',没有这个关键字参数
  • TypeError: f() takes 0 positional arguments but 1 was given,不需要位置参数但却传递 1 个

2.2.5 使用总结

在实际编程的时候,最常用的是可变参数系列。可变参数可以让函数的参数统一起来, 使得代码更加美观, 我在编程的时候非常喜欢使用**kwargs

# *args:  可以处理任意数量的位置参数, args这个名字约定俗成
# 这里的args将会是一个元组(tuple),包含了所有传递给函数的位置参数
def print_args(*args):
    for arg in args:
        print(arg)
nums = [1, 'two', 3.0]
print_args(nums[0], nums[1], nums[2])
print_args(*nums)  # *nums表示把nums这个list的所有元素作为可变参数传进去

# **kwargs: 可处理任意数量的关键字参数, kwargs这个名字约定俗成
# 这里的kwargs将会是一个字典,其中包含了所有传递给函数的关键字参数。
# 
def print_kwargs(**kwargs):
    for key, value in kwargs.items():
        print(f"{
     key} = {
     value}")

print_kwargs(a=1, b='two', c=3.0)
test = {
   "a": 1, "b": 'two', "c": 3.0}
print_kwargs(**test)  # **test表示把test这个dict的所有key-value用关键字参数传入到函数的**kwargs参数

# 实际场景使用

# 有一个平台审批流程有3条, 每一条对应的审批表单有些额外的信息不同,但基础信息一样,这时候我就希望把基础的信息写成位置参数,额外的信息用可变关键字参数使得3条审批流代码统一
def create_test_artifact_process(app_token: str, artifact: artifact_dal.ArtifactModel, start_user: str, **kwargs) -> dict:
def create_sop_release_process(app_token: str, artifact: artifact_dal.ArtifactModel, start_user: str, **kwargs) -> dict:
def create_sop_father_process(app_token: str, artifact: artifact_dal.ArtifactModel, start_user: str, **kwargs) -> dict:
# 这时候,拿额外参数的时候,只需要kwargs.get("xxx") 去拿就好

2.2.6 逆向参数收集

在Python中,逆向参数收集是指过程中的相反操作:当你有一个序列(比如列表、元组)或字典,并希望将它们的元素作为单独的参数传递给函数时使用。这可以通过*(对于序列)和**(对于字典)操作符实现,它们在调用函数时使用,将序列或字典拆解成单独的参数

# 1. 使用*对序列进行逆向参数收集: 可以将序列中的每个元素都转化为位置参数传递给函数
# 以逆向参数收集的方式,还可以给拥有可变位置参数的函数传参, 见上面
def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]

# 使用*操作符传递numbers列表中的元素作为单独的参数
result = add(*numbers)
print(result)  # 输出6

# 2. 使用**对字典进行逆向参数收集: 可以将字典中的每个键值对转化为关键字参数和对应的值传递给函数。
# 以逆向参数收集的方式,还可以给拥有可变关键字参数的函数传参, 见上面
def introduce(first_name, last_name, age):
    print(f"Hello, my name is {
     first_name} {
     last_name} and I am {
     age} years old.")

person_info = {
   "first_name":

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/779960.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Python】已解决:nltk.download(‘stopwords‘) 报错问题

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决:nltk.download(‘stopwords’) 报错问题 一、分析问题背景 在使用Python的自然语言处理库NLTK(Natural Language Toolkit)时&#xff0c…

《向量数据库指南》——Milvus Cloud检索器增强的深度探讨:句子窗口检索与元数据过滤

检索器增强的深度探讨:句子窗口检索与元数据过滤 在信息爆炸的时代,高效的检索系统成为了连接用户与海量数据的关键桥梁。为了进一步提升检索的准确性和用户满意度,检索器增强技术应运而生,其中句子窗口检索与元数据过滤作为两大…

每日一题~oj(贪心)

对于位置 i来说,如果 不选她,那她的贡献是 vali-1 *2,如果选他 ,那么她的贡献是 ai. 每一个数的贡献 是基于前一个数的贡献 来计算的。只要保证这个数的前一个数的贡献是最优的,那么以此类推下去,整体的val…

基于自编码器的时间序列异常检测方法(以传感器数据为例,MATLAB R2021b)

尽管近年来研究者对自编码器及其改进算法进行了深入研究,但现阶段仍存在以下问题亟须解决。 1) 无监督学习模式对特征提取能力的限制与有监督学习相比,无监督学习模式摆脱了对样本标签的依赖、避免了人工标注的困难,但也因此失去了样本标签的…

vue3+vite搭建第一个cesium项目详细步骤及环境配置(附源码)

文章目录 1.创建vuevite项目2.安装 Cesium2.1 安装cesium2.2 安装vite-plugin-cesium插件(非必选)2.3 新建组件页面map.vue2.4 加载地图 3.完成效果图 1.创建vuevite项目 打开cmd窗口执行以下命令:cesium-vue-app是你的项目名称 npm create…

Zkeys三方登录模块支持QQ、支付宝登录

1,覆盖到根目录,并导入update.sql数据库文件到Zkeys数据库里 2. 后台系统权限管理,配置管理员权限-系统类别-找到云外科技,全部打勾 3,后台系统设置找到云外快捷登录模块填写相应的插件授权配置和登录权限配置&#x…

【wordpress教程】wordpress博客网站添加非法关键词拦截

有的网站经常被恶意搜索,站长们不胜其烦。那我们如何屏蔽恶意搜索关键词呢?下面就随小编一起来解决这个问题吧。 后台设置预览图: 设置教程: 1、把以下代码添加至当前主题的 functions.php 文件中: add_action(admi…

Arcgis Api 三维聚合支持最新版API

Arcgis Api 三维聚合支持最新版API 最近有同学问我Arcgis api 三维聚合,官方还不支持三维聚合API,二维可以。所以依旧是通过GraphicLayers 类来实现,可支持最新Arcgis Api版本 效果图:

简单且循序渐进地查找软件中Bug的实用方法

“Bug”这个词常常让许多开发者感到头疼。即使是经验丰富、技术娴熟的开发人员在开发过程中也难以避免遭遇到 Bug。 软件中的故障会让程序员感到挫败。我相信在你的软件开发生涯中,也曾遇到过一些难以排查的问题。软件中的错误可能会导致项目无法按时交付。因此&…

初识STM32:芯片基本信息

STM32简介 STM32是ST公司基于ARM公司的Cortex-M内核开发的32位微控制器。 ARM公司是全球领先的半导体知识产权(IP)提供商,全世界超过95%的智能手机和平板电脑都采用ARM架构。 ST公司于1987年由意大利的SGS微电子与法国的Thomson半导体合并…

linux软链接和硬链接的区别

1 创建软链接和硬链接 如下图所示,一开始有两个文件soft和hard。使用 ln -s soft soft1创建软链接,soft1是soft的软链接;使用ln hard hard1创建硬链接,hard1是hard的硬链接。可以看到软链接的文件类型和其它3个文件的文件类型是不…

从“移花接木”到“提质增效”——详解嫁接打印技术

嫁接打印,是融合了3D打印与传统制造精髓的创新技术,其核心在于,通过巧妙地将传统模具加工与先进的3D打印技术相结合,实现了模具制造的“提质、增效、降本”。 嫁接打印的定义 简而言之,嫁接打印是一种增减材混合制造的…

uniapp报错--app.json: 在项目根目录未找到 app.json

【问题】 刚创建好的uni-app项目,运行微信小程序控制台报错如下: 【解决方案】 1. 程序根目录打开project.config.json文件 2. 配置miniprogramRoot,指定小程序代码的根目录 我的小程序代码编译后的工程文件目录为:dist/dev/mp…

阿里云Elasticsearch-趣味体验

阿里云Elasticsearch-趣味体验 什么是阿里云Elasticsearch阿里云Elasticsearch开通服务查看Elasticsearch实例配置Kibana公网IP登录Elasticsearch添加测试数据 Kibana数据分析查看数据字段筛选数据页面条件筛选KQL语法筛选保存搜索语句导出筛选结果指定列表展示字段写在最后 什…

multisim中关于74ls192n和DSWPK开关仿真图分析(减法计数器)

🏆本文收录于「Bug调优」专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&…

DAMA学习笔记(四)-数据建模与设计

1.引言 数据建模是发现、分析和确定数据需求的过程,用一种称为数据模型的精确形式表示和传递这些数据需求。建模过程中要求组织发现并记录数据组合的方式。数据常见的模式: 关系模式、多维模式、面向对象模式、 事实模式、时间序列模式和NoSQL模式。按照描述详细程度…

实现资产优化管理:智慧校园资产分类功能解析

在构建智慧校园的过程中,细致入微的资产管理是确保教育资源高效运作的关键一环,而资产分类功能则扮演着举足轻重的角色。系统通过精心设计的分类体系,将校园内的各类资产,从昂贵的教学设备到日常使用的办公物资,乃至无…

S32DS S32 Design Studio for S32 Platform 3.5 代码显示行号与空白符

介绍 NXP S32DS,全称 S32 Design Studio,s32 系列芯片默认使用 S32 Design Studio for S32 Platform 作为 IDE 集成开发环境,当前版本 S32 Design Studio for S32 Platform 3.5,IDE 可以简称 s32DS 使用 S32DS,可以认…

数据结构算法-排序(一)-冒泡排序

什么是冒泡排序 冒泡排序:在原数组中通过相邻两项元素的比较,交换而完成的排序算法。 算法核心 数组中相邻两项比较、交换。 算法复杂度 时间复杂度 实现一次排序找到最大值需要遍历 n-1次(n为数组长度) 需要这样的排序 n-1次。 需要 (n-1) * (n-1) —…

240706_昇思学习打卡-Day18-基于MindSpore的GPT2文本摘要

240706_昇思学习打卡-Day18-基于MindSpore的GPT2文本摘要 今天做一个根据一段文章提取摘要的提取器,基于nlpcc2017摘要数据,内容为新闻正文及其摘要,就是训练集及标签。 首先我们来预装以下MindSpore环境 %%capture captured_output # 实验…