抽象,自定义函数,递归

6.1懒惰是一种美德

如果你 在一个地方编写了一些代码,但需要在另一个地方再次使用,该如何办呢?

假设你编写了一段代码,它计算一些斐波那契数(一种数列,其中每个数都是前两个数的和)。

现在的数列包含10个斐波那契数。

如果要使用这些数字做其他事情,该如何办呢?我们肯定不愿意再重新写一遍代码。我们可以让程序更抽象。要让前面的程序更抽象,可以像下面这样做:

大家可以看见,我在确定num后直接可以打印出fibs。其实如果把整体封装起来,就可以直接调用。

6.2抽象和结构 

抽象可节省人力,但实际上还有个更重要的优点:抽象是程序能够被人理解的关键所在。

人和计算机的差别在于,计算机本身喜欢具体而明确的指 令,但人通常不是这样的。

例如:如果你向人打听怎么去电影院,就不希望对方回答:“向前走10步,向左转90度,接着走5步,再向右转45度,然后走123步。”(这是计算机希望听见的)。“沿这条街往前走,看到过街天桥后走到马路对面,电影院就在你左边。”(这是人希望听见的)。这里的关键是你知道如何沿街往前走,也知道如何过天桥,因此不需要有关这些方面的具体说明。

组织计算机程序时,你也采取类似的方式。程序应非常抽象,如下载网页、计算使用频率、打印每个单词的使用频率。

看到这些代码,任何人都知道这个程序是做什么的。但是其中到底如何做,其中的细节会在其他地方给出。

6.3自定义函数

函数执行特定的操作并返回一个值,你可以调用它(调用时可能需要提供一些参数——放在圆括号中的内容)。一般而言,要判断某个对象是否可调用,可使用内置函数callable。

此时说明x是不可以调用的,y是可以的。(并非所有的函数都返回值)

函数是结构化编程的核心。那么如何定义函数呢?使用def(表示定义函数)语句。

上面两行是对于函数的简单定义,最下面是对函数的调用。

 那现在回到斐波那契数,如果编写一个函数,返回一个由斐波那契数组成的列表呢?

前5行都是对于斐波那契数整个函数的定义,最后一行是对其进行调用。

其实我们不难发现,除了def一直需要外,我们在每个定义def中都有一个return语句。return语 句用于从函数返回值(在前面的hello函数中,return语句的作用也是一样的)。

6.3.1给函数编写文档

要给函数编写文档,以确保其他人能够理解,可添加注释(以#打头的内容)。

放在函数开头的字符串称为文档字符串(docstring),将作为函数的一部分存储起来。

代码前三行是定义,其中包含了我们的注释。最后一行我们先是调用了下函数进行计算,同时也读取了函数定义的文档字符串。(注意 __doc__是函数的一个属性。)

特殊的内置函数help很有用。在交互式解释器中,可使用它获取有关函数的信息,其中包含函数的文档字符串。

6.3.2其实并不是函数的函数

数学意义上的函数总是返回根据参数计算得到的结果。在Python中,有些函数什么都不返回。

什么都不返回的函数不包含return语句,或者包含return语句,但没有在return后面指定值。

这里虽然包含了return,但是其实return部分没有返回任何值,只是为了结束语句(第二个打印的go没有打印出来)(这有点像在循环中使用break,但跳出的是函数)

6.4参数魔法

函数使用起来很简单,创建起来也不那么复杂,但要习惯参数的工作原理就不那么容易了。

6.4.1值从哪里来

定义函数时,你可能心存疑虑:参数的值是怎么来的呢?

编写函数旨在为当前程序(甚至其他程序)提供服务,你的职责是确保它在提供的参数正确时完成任务,并在参数不对时以显而易见的方式失败。参数通常不需要担心。

在def语句中,位于函数名后面的变量通常称为形参,而调用函数时提供的值称为实参。很多情况下我们会将实参称为值,以便将其与类似于变量的形参区分开来。

6.4.2我能修改参数吗

参数不过是变量而已,行为与你预期的完全相同。在函数内部给参数赋值对外部没有任何影响。

在try_to_change内,将新值赋给了参数n,但如你所见,这对变量name没有影响。说到底,这是一个完全不同的变量。

这样可能更加直观,在有返回值的情况下,在定义里面修改参数会导致返回值的变化,但是但是重要的是它不会去修改我们的name。变量n变了,但变量name没变。同样,在函数内部重新关联参数(即给它赋值)时,函数外部的变量不受影响(参数存储在局部作用域内)。

字符串(以及数和元组)是不可变的(immutable),这意味着你不能修改它们(即只能替换为新值)。因此这些类型作为参数没什么可说的。但如果参数为可变的数据结构(如列表)呢?

唉?例子也是在函数内修改了参数,为什么函数外部的names发生变化了?大家先看下面:

这样的情况大家应该都见过,将同一个列表赋给两个变量时,这两个变量将同时指向这个列表。就这么简单。

这就解释了为什么在函数外的结果被修改了。

要避免这样的结果,必须创建列表的副本。对序列执行切片操作时,返回的切片都是副本。因此,如果你创建覆盖整个列表的切片,得到的将是列表的副本。

此时就可以发现,n和names虽然内容相同,但是已经不是同一个列表了。 注意到参数n包含的是副本。

(1)为何要修改参数

在提高程序的抽象程度方面,使用函数来修改数据结构(如列表或字典)是一种不错的方式。

假设你要编写一个程序,让它存储姓名,并让用户能够根据名字、中间名或 姓找人。为此,你可能使用一个类似于下面的数据结构:

每个键下都存储了一个人员列表。在这个例子里,这些列表只包含作者。

现在,要获取中间名为Lie的人员名单,可像下面这样做:

但是,如你所见,将人员添加到这个数据结构中有点繁琐,在多个人的名字、中间名或姓相同时尤其如此,因为在这种情况下需要对存储在名字、中间名或姓下的列表进行扩展。

下面来添加我的妹妹,并假设我们不知道数据库中存储了什么内容。

storage['first']['Anne'] 在第一个代码的第二行给first键对应的‘Anne’键对应的值用my_sister添加,由于之前我们并没有对Anne的键对应相应的值,现在直接添加,形成的结果就是刚刚添加的。对于三行的Lie之前我们有设置过值,现在append一个,最后得到的结果就是第二个代码出现的结果。

可以想见,编写充斥着这种更新的大型程序时,代码将很快变得混乱不堪。

抽象的关键在于隐藏所有的更新细节,为此可使用函数。下面首先来创建一个初始化数据结构的函数。

你所见,这个函数承担了初始化职责,让代码的可读性高了很多。

接下来设计获取人员姓名的函数。

第一个代码就是获取设计人员姓名的函数。第二个代码最后就是对该函数的使用。

下面来编写将人员存储到数据结构中的函数。

运行一下:

如你所见,如果多个人的名字、中间名或姓相同,可同时获取这些人员。

(2)如果参数是不可变的

在很多语言中,经常需要给参数赋值并让这种修改影响函数外部的变量。在Python中,没法直接这样做,只能修改参数对象本身。

但是,如果参数不可变呢?没办法。在这种情况下,应从函数返回所有需要的值(如果需要返回多个值,就以元组的方式返回它们)。

这样没有进过修改参数

如果一定要修改参数,改变外部的值,可以把值放在列表中。

6.4.3关键字参数和默认值

有时候,参数的排列顺序可能难以记住,尤其是参数很多时。

但是当我们改成这样的时候参数的顺序就无关紧要了,但是名称变的很重要。

像这样使用名称指定的参数称为关键字参数,主要优点是有助于澄清各个参数的作用。

虽然这样做的输入量多些,但每个参数的作用清晰明了。另外,参数的顺序错了也没关系。

然而,关键字参数最大的优点在于,可以指定默认值。

像这样,设定完默认值后,调用时不提供它,也可以运行出来。

当然也可以提供默认值。提供1个或者2个都可以。

如你所见,这两个提供的值,其实还是按照位置进行分配的。那如何使用提供的name或者greeting。

还不止这些。你可结合使用位置参数和关键字参数,但必须先指定所有的位置参数,否则解释器将不知道它们是哪个参数(即不知道参数对应的位置)。通常不会结合位置参数和关键字参数。

大家可以自己看一下代码,思考一下与预期是否相同。

直接运行报错,因为name没有设定默认值。

6.4.4收集参数

有时候,允许用户提供任意数量的参数很有用。

每次只能存储一个数据太少了,如果可以同时存储多个数据就比较好:

为此,应允许用户提供任意数量的姓名。请尝试使用下面这样的函数定义:

这里好像只指定了一个参数,但它前面有一个星号。

看,我们引用这个定义,发现最终打印出的是一个元组,因为里面有一个逗号。那继续尝试是否可以打印出更多的项。

看出来,打印多个项目也是可以的。参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。这样的行我们在5.2.1节见过:赋值时带星号的变量收集多余的值。它收集的是列表而不是元组中多余的值,但除此之外,这两种用法很像。

和我们预期相同,第一个参数收集一个值(params),第二个参数由于有*号,所以收集剩余的值(1,2,3)。

这段代码,在第一个参数收集完第一个值,没有值了,所以第二个参数返回了一个空的元组。

那此时,我们可能会好奇,那如果说星号的参数在中间,它应该怎么判断剩余的元组呢?我们尝试一下:

星号不会收集管自己参数,如果不给z=6呢?

报错了。

星号不会收集关键字参数。如下。

正常来说,在参数title收集到Hmm...后,剩余内容被星号参数收集,但是事实上没有,因为提供了关键字了,星号不会收集关键字参数。

要收集关键字参数,可使用两个星号。

如你所见,这样得到的是一个字典而不是元组。

将以上的内容全部结合一下,位置,关键字,*,**

现在我们来解决最初的问题,如何在姓名存储示例中使用这种技术?解决方案如下:

6.4.5分配参数

前面介绍了如何将参数收集到元组和字典中,但用同样的两个运算符(*和**)也可执行相反的操作。与收集参数相反的操作是什么呢?假设有如下函数:

现在定义了一个相加的函数,但是给出的两个数据在一个元组里。现在就希望将这两个数据进行相加,但是定义中给的是两个参数。与收集参数相反的操作(不是收集参数,而是分配参数):

当然使用一个*可以,也可以使用两个**。可将字典中的值分配给关键字参数。如下:

大家看下面这一段代码:

对于函数with_stars,我在定义和调用它时都使用了星号,而对于函数without_stars,我在定义和调用它时都没有使用,但这两种做法的效果相同。

因此,只有在定义函数(允许可变数量的参数)或调用函数时(拆分字典或序列)使用, 星号才能发挥作用。

使用这些拆分运算符来传递参数很有用,因为这样无需操心参数个数之类的问题,如下所示:

6.5作用域

变量到底是什么呢?可将其视为指向值的名称。因此,执行赋值语句x = 1后,名称x指向值1。这几乎与使用字典时一样(字典中的键指向值),只是你使用的是“看不见”的字典。

有一个名为vars的内置函数,它返回这个不可见的字典:

警告 一般而言,不应修改vars返回的字典,因为根据Python官方文档的说法,这 样做的结果是不确定的。换而言之,可能得不到你想要的结果。

这种“看不见的字典”称为命名空间或作用域。那么有多少个命名空间呢?除全局作用域外,每个函数调用都将创建一个。

这个地方就有些疑问了,我调用foo了,foo函数内赋值语句x=42,为什么最终x没有变化,依然是1呢?

这是因为调用foo时创建了一个新的命名空间,供foo中的代码块使用。赋值语句x = 42是在这个内部作用域(局部命名空间)中执行的,不影响外部(全局)作用域内的x。在函数内使用的变量称为局部变量(与之相对的是全局变量)。参数类似于局部变量,因此参数与全局变量同名不会有任何问题。

简而言之,就是创建函数foo时,创建了新的命名空间,这个空间里(局部)的x值不会影响到全局作用域中的x值。因此局部变量与全局变量同名也没有问题。

读取全局变量的值通常不会有问题,但还是存在出现问题的可能性。

(1)“遮盖”的问题

如果有一个局部 变量或参数与你要访问的全局变量同名,就无法直接访问全局变量,因为它被局部变量遮住了。(其实就是在局部变量里面使用全局变量时,如果局部变量中有与全局同名的,系统不知道识别哪一个,而因为在定义里面,会先访问局部变量)

那我到底如何让函数里知道我要访问全局变量呢?使用global

看,此时函数里就访问到了全局变量的parameter。

还记得我们在6.5开始的时候,函数里面的值的赋值操作,并没有改变函数外的值。那如何改变呢?

重新关联全局变量(使其指向新值)是另一码事。在函数内部给变量赋值时,该变量默认为局部变量,除非你明确地告诉Python它是全局变量。当然还是使用global。

ok,大家知道了可以这样进行关联全局变量。大家可以思考一下为什么下面这个x还是1呢?

(2)作用域嵌套

Python函数可以嵌套,即可将一个函数放在另一个函数内。

嵌套通常用处不大,但有一个很突出的用途:使用一个函数来创建另一个函数。这意味着可像下面这样编写函数:

在这里,一个函数位于另一个函数中,且外面的函数返回里面的函数。也就是返回一个函数,而不是调用它。重要的是,返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!

每当外部函数被调用时,都将重新定义内部的函数,而变量factor的值也可能不同。由于Python的嵌套作用域,可在内部函数中访问这个来自外部局部作用域(multiplier)的变量,如下所示:

第一句中的2其实就是multiplier的factor,double中的5,其实就是number。下面两个例子也是类似的。

像multiplyByFactor这样存储其所在作用域的函数称为闭包。

通常,不能给外部作用域内的变量赋值,但如果一定要这样做,可使用关键字nonlocal。这个关键字的用法与global很像,让你能够给外部作用域(非全局作用域)内的变量赋值。

6.6递归

你知道,函数可调用其他函数,但可能让你感到惊 讶的是,函数还可调用自己。

如果你以前没有遇到这种情况,可能想知道递归是什么意思。简单地说,递归意味着引用(这里是调用)自身。(其实完全没有必要明白递归的准确定义)

这就是一个递归式函数的定义,其实什么都没做,与“递归”定义一样傻。

从理论上说,这个程序将 不断运行下去,但每次调用函数时,都将消耗一些内存。因此函数调用次数达到一定的程 度(且之前的函数调用未返回)后,将耗尽所有的内存空间,导致程序终止并显示错误消 息“超过最大递归深度”。

这个函数中的递归称为无穷递归(就像以while True打头且不包含break和return语句的循环被称为无限循环一样),因为它从理论上说永远不会结束。

我们需要的是对我们有帮助的递归,通常包含两个部分:

基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。

递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分。

6.6.1 阶乘与幂(经典案例)

首先,假设你要计算数字n的阶乘。n的阶乘为n × (n - 1) × (n - 2) × … × 1,在数学领域的用途非常广泛。

首先将result设置为n,再将其依次乘以1到n - 1的每个数字,最后返回result。但如果你愿意,可采取不同的做法。

ok,上面这个方法就一步步的进行计算,但我们也可以采用不同的方法。

①1的阶乘为1。

②对于大于1的数字n,其阶乘为n - 1的阶乘再乘以n。这与阶乘的定义相同。

再来看一个示例。假设你要计算幂,就像内置函数pow和运算符**所做的那样。要定义一个数字的整数次幂,有多种方式,但先来看一个简单的定义:power(x, n)(x的n次幂)是将数字x自乘n - 1次的结果,即将n个x相乘的结果。

同样,也可以将他改成递归式。

①对于任何数字x,power(x, 0)都为1。

②n>0时,power(x, n)为power(x, n-1)与x的乘积。

提示 如果函数或算法复杂难懂,在实现前用自己的话进行明确的定义将大有裨益。以这种“准编程语言”编写的程序通常称为伪代码。

那么使用递归有何意义呢?难道不能转而使用循环吗?答案是肯定的,而且在大多数情况下,使用循环的效率可能更高。然而,在很多情况下,使用递归的可读性更高,且有时要高得多,在你理解了函数的递归式定义时尤其如此。

6.6.2二分查找

例如,对方心里想着一个1~100的数字,你必须猜出是哪个。当然,猜100次肯定猜对,但最少需要猜多少次呢?实际上只需猜7次。首先问:“这个数字大于50吗?”如果答案是肯定的,再问:“这个数字大于75吗?”不断将可能的区间减半,直到猜对为止。你无需过多地思考就能成功。

这样的想法适用于众多其他不同的情形。

一个常见的问题是:指定的数字是否包含在已排序的序列中?如果包含,在什么位置?为解决这个问题,可采取同样的策略:“这个数字是否在序列中央的右边?”如果答案是否定的,再问:“它是否在序列的第二个四分之一区间内(左半部分的右边)?”依此类推。明确数字所处区间的上限和下限,并且每一个问题都将区间分成两半。

这里的关键是,这种算法自然而然地引出了递归式定义和实现。

①如果上限和下限相同,就说明它们都指向数字所在的位置,因此将这个数字返回。

②否则,找出区间的中间位置(上限和下限的平均值),再确定数字在左半部分还是右 半部分。然后在继续在数字所在的那部分中查找。

在这个递归案例中,关键在于元素是经过排序的。找出中间的元素后,只需将其与要查找的数字进行比较即可

当然,上面的代码有一个缺陷,在一我们通常不知道lower和upper(这两个值代表的是列表的下标)所有可以进行修改。

现在进行调用,看是否正确。

结果是正确的,但是你可能会好奇,明明对于列表,我们可以直接index查找,为什么要这样呢?

的确,index是可以的,但是效率太低了,前面说过,要在100个数字中找到指定的数字,只需问7次;但使用循环时,在最糟的情况下需要问100次。(大家看100好像没什么,事实上,在可观察到的宇宙中,包含的粒子数大约为10 87个。要找出其中的一个粒子,只需问大约290次!)

实际上,模块bisect提供了标准的二分查找实现。

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

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

相关文章

Freeswitch-soundtouch-变声开发

文章目录 一、介绍二、安装soundtouch2.1 源码安装方式(推荐)2.1.1下载源码2.1.2解压2.1.3 编译2.1.4 迁移(可选) 2.2 apt-get 安装 三、使用3.1 终端使用3.2 Freeswitch使用3.2.1编译Freeswitch的mod_soundtouch3.2.2启用 mod_so…

Qt图像处理技术九:得到QImage图像的灰度直方图

效果 原理 得到灰度化值&#xff0c;将灰度化的值带入0-255内&#xff0c;增加&#xff0c;得到可视化图形 源码 // 绘制直方图 QImage drawHistogram(const QImage &image) {QVector<int> histogram(256, 0);// 计算图像的灰度直方图for (int y 0; y < image…

static的用法

static一般用于修饰局部变量&#xff0c;全局变量&#xff0c;函数 1 static修饰局部变量 是因为改为static int a1;后&#xff0c;出了作用域&#xff0c;不会销毁a的值&#xff0c;想要理解其本质&#xff0c;首先先看一下这个图&#xff1a; static修饰局部变量时&#xf…

【代码随想录】【算法训练营】【第30天】 [322]重新安排行程 [51]N皇后 [37]解数独

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 30&#xff0c;周四&#xff0c;好难&#xff0c;会不了一点~ 题目详情 [322] 重新安排行程 题目描述 322 重新安排行程 解题思路 前提&#xff1a;…… 思路&#xff1a;回溯。 重点&…

yolo水果品质:新鲜腐烂橙子检测/分类数据集(3k+图像全标注)

yolo水果品质检测之新鲜腐烂橙子数据集&#xff0c;整个数据集共包含3852张图像&#xff0c;yolo标注完整&#xff08;txt格式&#xff09;,标注类别分为新鲜橙子&#xff08;0&#xff09;和腐烂橙子&#xff08;1&#xff09;两类 图像统一格式&#xff1a;jpg 图像统一分辨…

windows10子系统wsl ubuntu22.04下GN/ninja环境搭建

打开windows10子系统 ubuntu22.04 ubuntu22.04: 首先需要 安装ninja $sudo apt install ninja-build $ ninja --version 1.10.0 安装clang $sudo apt install clang $clang --version Ubuntu clang version 14.0.0-1ubuntu1.1安装gn Github: https://github.com/timniederh…

ar地产沙盘互动体验提供更加丰富多彩的楼盘信息

AR增强现实技术作为其重要分支&#xff0c;正逐步在全球市场中崭露头角。国内的AR增强现实技术公司正致力于链接物理世界和虚拟世界&#xff0c;为用户带来沉浸式的AR体验。它们打造线上线下联动的一站式文旅景区数字化运营平台&#xff0c;让您在享受旅游的同时&#xff0c;也…

什么是Vector Database(向量数据库)?

什么是Vector Database(向量数据库)&#xff1f; 向量数据库是向量嵌入的有组织的集合&#xff0c;可以随时创建、读取、更新和删除。向量嵌入将文本或图像等数据块表示为数值。 文章目录 什么是Vector Database(向量数据库)&#xff1f;什么是嵌入模型(Embedding Model)&…

用蒙特卡罗积分法近似求解定积分的值及举例

一、背景知识 1、连续随机变量的概率密度函数 对于连续型随机变量的概率密度函数&#xff08;PDF&#xff09;&#xff0c;其在整个定义域上的积分必须等于1。这是概率密度函数的一个基本属性&#xff0c;它确保了随机变量取任何值的概率之和等于1&#xff0c;符合概率论的公…

家用洗地机哪个牌子好?专家推荐榜单助你挑选最合适的洗地机

随着科技不断发展&#xff0c;智能家居产品逐渐融入我们日常生活中&#xff0c;洗地机作为家庭清洁必备工具&#xff0c;越来越受到消费者青睐&#xff0c;但是面对市面上种类繁多的洗地机&#xff0c;我们如何挑选到适合自己的产品呢&#xff1f;专家推荐榜单助你挑选最合适的…

在vue项目中使用markdown-it回显markdown文本

前言 其实有很多插件都是可以用来回显markdown文本的,这个插件也是其中之一。 文档地址:markdown-it | markdown-it 中文文档 这个文档在vue2和vue3里面都可以使用,所以还是比较推荐的 使用 安装 npm install markdown-it --save 应用 <template><div><…

正邦科技(第10天)

这里写目录标题 任务一任务二任务三 任务一 下位机报上来的十进制数据进行解析&#xff1a; 360170 固定报文&#xff0c;一个F对应一个字节&#xff0c;温度值&#xff0c;湿度值&#xff0c;烟雾浓度值是十进制转16进制&#xff0c;告警状态需要高低位移位&#xff0c;然后再…

【Pycharm】功能介绍

1.Code Reformat Code 格式化代码&#xff0c;可以帮助我们去自动调整空格等&#xff0c;根据python语法规范自动调整 2.Settings 1.创建py文件默认填充模版 3.读写py文件编码格式一致性 顶部代码指定的编码方式作用&#xff1a; 可以保证python2/3解释器在读取文件的时候按…

个人项目———密码锁的实现

布局组件 布局效果 组件绑定 密码锁的实现代码 using TMPro; using UnityEngine; using UnityEngine.UI;public class PasswordPanel : MonoBehaviour {// public Button button;// 所有按键的父物体public Transform buttonPanel;// 输入字符串的文本框public TMP_Text input…

英国树莓派五大天王和你相约上海国际嵌入式展!

6月12日-14日 上海世博展览馆3号馆 H3馆 237展位 树莓派(Raspberry Pi),这个曾经让全球掀起"创客热潮"的小型单板电脑,如今已经成为嵌入式行业不可或缺的一员。作为行业先驱,树莓派基金会正携手团队,亮相2024年6月12日至6月14日在上海举办的 Embedded World上海国…

【Elasticsearch】es基础入门-03.RestClient操作文档

RestClient操作文档 示例&#xff1a; 一.初始化JavaRestClient &#xff08;一&#xff09;引入es的RestHighLevelClient依赖 <!--elasticsearch--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest…

基于springboot+vue的家乡特色推荐系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

SpringBoot高手之路03-事务传播行为

那么就是 a事务调用了b事务 日志技术 当解散部门的时候,那么就直接进行 操作日志 就是什么时间点吧部门解散 成功失败都需要记录日志 首先一个日志表 那么日志技术,在电商平台,不论是否支付订单,那么都需要保存订单信息 这个时候我们就使用传播事务 传播事务首先是出现在两…

云南区块链商户平台发票助手成品

目录 1 概述2 功能对比3 项目演示图4 核心逻辑4.1智能赋码4.2 解密方法4.3 登录与检测4.4 发票金额大写转换4.5 检查登录是否失效4.6 验证码识别5 演示效果6 项目部署6.1 Web站点部署6.1.1 环境6.1.2 前端6.1.3 后端6.2 Docker部署6.2.1 构建镜像6.2.2 创建容器6.3.3 访问项目域…

混剪素材哪里找?分享几个热门混剪素材下载网站

在短视频和新媒体的世界里&#xff0c;高质量的混剪素材是吸引观众的关键。今天&#xff0c;我将为大家详细介绍几个优秀的素材网站&#xff0c;它们不仅资源丰富&#xff0c;而且完全满足新媒体创作者的需求。这篇文章将帮助你理解如何有效利用这些平台提升你的视频创作。 蛙…