python入门9-函数基础
函数介绍
<1>什么是函数
请看如下代码:
print(" _ooOoo_ ")
print(" o8888888o ")
print(" 88 . 88 ")
print(" (| -_- |) ")
print(" O\\ = /O ")
print(" ____/`---'\\____ ")
print(" . ' \\| |// `. ")
print(" / \\||| : |||// \\ ")
print(" / _||||| -:- |||||- \\ ")
print(" | | \\\\\\ - /// | | ")
print(" | \\_| ''\\---/'' | | ")
print(" \\ .-\\__ `-` ___/-. / ")
print(" ___`. .' /--.--\\ `. . __ ")
print(" ."" '< `.___\\_<|>_/___.' >'"". ")
print(" | | : `- \\`.;`\\ _ /`;.`/ - ` : | | ")
print(" \\ \\ `-. \\_ __\\ /__ _/ .-` / / ")
print(" ======`-.____`-.___\\_____/___.-`____.-'====== ")
print(" `=---=' ")
print(" ")
print(" ............................................. ")
print(" 佛祖镇楼 BUG辟易 ")
print(" 佛曰: ")
print(" 写字楼里写字间,写字间里程序员; ")
print(" 程序人员写程序,又拿程序换酒钱。 ")
print(" 酒醒只在网上坐,酒醉还来网下眠; ")
print(" 酒醉酒醒日复日,网上网下年复年。 ")
print(" 但愿老死电脑间,不愿鞠躬老板前; ")
print(" 奔驰宝马贵者趣,公交自行程序员。 ")
print(" 别人笑我忒疯癫,我笑自己命太贱; ")
print(" 不见满街漂亮妹,哪个归得程序员?")
Copy
想一想:
如果一个程序在不同的地方需要输出“佛祖镇楼”,程序应该怎样设计?
if 条件1:输出‘佛祖镇楼’...(省略)...if 条件2:输出‘佛祖镇楼’...(省略)...
Copy
如果需要输出多次,是否意味着要编写这块代码多次呢?
小总结:
- 如果在开发程序时,需要某块代码多次执行。为了提高编写的效率以及更好的维护代码,需要把具有独立功能的代码块组织为一个小模块,这就是函数。
函数定义和调用
一、定义函数
定义函数的格式如下:
def 函数名():代码
Copy
示例:
# 定义一个函数,能够完成打印信息的功能
def printInfo():print('------------------------------------')print(' 人生苦短,我用Python')print('------------------------------------')
Copy
二、调用函数
定义了函数之后,就相当于有了一个具有某些功能的代码,想要让这些代码能够执行,需要调用它
调用函数很简单的,通过 函数名() 即可完成调用
# 定义完函数后,函数是不会自动执行的,需要调用它才可以
printInfo()
Copy
三、注意:
- 函数定义好以后,函数体里的代码并不会执行,如果想要执行函数体里的内容,需要手动的调用函数。
- 每次调用函数时,函数都会从头开始执行,当这个函数中的代码执行完毕后,意味着调用结束了。
- 当然了如果函数中执行到了return也会结束函数。
四、练一练
要求:定义一个函数,能够计算两个数字之和,并且调用这个函数让它执行
- 使用def定义函数
- 编写完函数之后,通过 函数名() 进行调用
函数参数(一)
思考一个问题,如下:
现在需要定义一个函数,这个函数能够完成2个数的加法运算,并且把结果打印出来,该怎样设计?下面的代码可以吗?有什么缺陷吗?
def add2num():a = 11b = 22c = a+bprint(c)
Copy
为了让一个函数更通用,即想让它计算哪两个数的和,就让它计算哪两个数的和,在定义函数的时候可以让函数接收数据,就解决了这个问题,这就是 函数的参数
一、定义、调用带有参数的函数
定义一个add2num(a, b)函数,来计算任意两个数字之和:
def add2num(a, b):c = a+bprint cadd2num(11, 22) # 调用带有参数的函数时,需要在小括号中,传递数据
Copy
注意点:
- 在定义函数的时候,小括号里写等待赋值的变量名
- 在调用函数的时候,小括号里写真正要进行运算的数据
调用带有参数函数的运行过程:
二、练一练
要求:定义一个函数,完成前2个数完成加法运算,然后对第3个数,进行减法;然后调用这个函数
- 使用def定义函数,要注意有3个参数
- 调用的时候,这个函数定义时有几个参数,那么就需要传递几个参数
三、调用函数时参数的顺序
>>> def test(a,b):
... print(a,b)
...
>>> test(1,2) # 位置参数
1 2
>>> test(b=1,a=2) # 关键字参数
2 1
>>>
>>> test(b=1,2) # 关键字参数写在位置参数之前会导致出错File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
Copy
四、小总结
- 定义时小括号中的参数,用来接收参数用的,称为 “形参”
- 调用时小括号中的参数,用来传递给函数用的,称为 “实参”
函数返回值(一)
一、“返回值”介绍
现实生活中的场景:
我给儿子10块钱,让他给我买个冰淇淋。这个例子中,10块钱是我给儿子的,就相当于调用函数时传递到参数,让儿子买冰淇淋这个事情最终的目标,我需要让他把冰淇淋带回来,此时冰淇淋就是返回值
开发中的场景:
定义了一个函数,完成了获取室内温度,想一想是不是应该把这个结果给调用者,只有调用者拥有了这个返回值,才能够根据当前的温度做适当的调整
综上所述:
- 所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果
- 使用返回值的前提需求就是函数调用者想要在函数外使用计算结果
二、带有返回值的函数
想要在函数中把结果返回给调用者,需要在函数中使用return
如下示例:
def add2num(a, b):c = a+breturn c # return 后可以写变量名
Copy
或者
def add2num(a, b):return a+b # return 后可以写计算表达式
Copy
三、保存函数的返回值
在本小节刚开始的时候,说过的“买冰淇淋”的例子中,最后儿子给你冰淇淋时,你一定是从儿子手中接过来 对么,程序也是如此,如果一个函数返回了一个数据,那么想要用这个数据,那么就需要保存
保存函数的返回值示例如下:
#定义函数
def add2num(a, b):return a+b#调用函数,顺便保存函数的返回值
result = add2num(100,98)#因为result已经保存了add2num的返回值,所以接下来就可以使用了
print(result)
Copy
结果:
198
函数的文档说明
1.基本使用
>>> def test(a,b):
... "用来完成对2个数求和" # 函数第一行写一个字符串作为函数文档
... print("%d"%(a+b))
...
>>>
>>> test(11,22) # 函数可以正常调用
33
>>>
>>> help(test) # 使用 help 查看test函数的文档说明
Help on function test in module __main__:test(a, b)用来完成对2个数求和
Copy
使用效果
2.高级使用
def get_info(name: str, age: int):"""接收用户的名字和年龄,拼接一个字符串并返回:param name: 接收一个名字:param age: 接收用户的年龄,必须是 0-200 间的一个整数:return: 返回拼接好的字符串"""return "我的名字叫 %s,今年是 %d 岁" % (name, age)get_info("吴彦祖", 19)
get_info(520, 19) # 注意,形参上标注的类型只是提高代码的可读性,并不会限制实参的类型
help(get_info)
Copy
使用效果
函数应用:打印图形和数学计算
目标
- 感受函数的嵌套调用
- 感受程序设计的思路,复杂问题分解为简单问题
思考&实现1
- 写一个函数打印一条横线
- 打印自定义行数的横线
参考代码1
# 打印一条横线
def printOneLine():print("-"*30)# 打印多条横线
def printNumLine(num):i=0# 因为printOneLine函数已经完成了打印横线的功能,# 只需要多次调用此函数即可while i<num:printOneLine()i+=1printNumLine(3)
Copy
思考&实现2
- 写一个函数求三个数的和
- 写一个函数求三个数的平均值
参考代码2
# 求3个数的和
def sum3Number(a,b,c):return a+b+c # return 的后面可以是数值,也可是一个表达式# 完成对3个数求平均值
def average3Number(a,b,c):# 因为sum3Number函数已经完成了3个数的就和,所以只需调用即可# 即把接收到的3个数,当做实参传递即可sumResult = sum3Number(a,b,c)aveResult = sumResult/3.0return aveResult# 调用函数,完成对3个数求平均值
result = average3Number(11,2,55)
print("average is %d"%result)
函数的嵌套调用
def testB():print('---- testB start----')print('这里是testB函数执行的代码...(省略)...')print('---- testB end----')def testA():print('---- testA start----')testB()print('---- testA end----')testA()
Copy
结果:
---- testA start----
---- testB start----
这里是testB函数执行的代码...(省略)...
---- testB end----
---- testA end----
Copy
小总结:
如下图所示:
- 一个函数里面又调用了另外一个函数,这就是所谓的函数嵌套调用
- 如果函数A中,调用了另外一个函数B,那么先把函数B中的任务都执行完毕之后才会回到上次 函数A执行的位置
-
本章节主要介绍以下内容:
- 局部变量和全局变量
- 不定长参数的使用
- 多个返回值
- 缺省参数
- 可变类型和不可变类型的使用
-
局部变量
- 局部变量,就是在函数内部定义的变量
- 其作用范围是这个函数内部,即只能在这个函数中使用,在函数的外部是不能使用的
- 因为其作用范围只是在自己的函数内部,所以不同的函数可以定义相同名字的局部变量(打个比方,把你、我是当做成函数,把局部变量理解为每个人手里的手机,你可有个iPhone8,我当然也可以有个iPhone8了, 互不相关)
- 局部变量的作用,为了临时保存数据需要在函数中定义变量来进行存储
- 当函数调用时,局部变量被创建,当函数调用完成后这个变量就不能够使用了
全局变量
如果一个变量,既能在一个函数中使用,也能在其他的函数中使用,这样的变量就是全局变量
打个比方:有2个兄弟 各自都有手机,各自有自己的小秘密在手机里,不让另外一方使用(可以理解为局部变量);但是家里的电话是2个兄弟都可以随便使用的(可以理解为全局变量)
# 定义全局变量
a = 100def test1():print(a) # 虽然没有定义变量a但是依然可以获取其数据def test2():print(a) # 虽然没有定义变量a但是依然可以获取其数据# 调用函数
test1()
test2()
Copy
运行结果:
总结1:
- 在函数外边定义的变量叫做
全局变量
- 全局变量能够在所有的函数中进行访问
全局变量和局部变量名字相同问题
看如下代码:
总结2:
- 当函数内出现局部变量和全局变量相同名字时,函数内部中的
变量名 = 数据
此时理解为定义了一个局部变量,而不是修改全局变量的值
修改全局变量
函数中进行使用时可否进行修改呢?
代码如下:
总结3:
- 如果在函数中出现
global 全局变量的名字
那么这个函数中即使出现和全局变量名相同的变量名 = 数据
也理解为对全局变量进行修改,而不是定义局部变量 - 如果在一个函数中需要对多个全局变量进行修改,那么可以一次性全部声明,也可以分开声明
# 可以使用一次global对多个全局变量进行声明
global a, b
# 还可以用多次global声明都是可以的
# global a
# global b
Copy
查看所有的全局变量和局部变量
Python提供了两个内置函数globals()和locals()可以用来查看所有的全局变量和局部变量。
def test():a = 100b = 40print(locals()) # {'a': 100, 'b': 40}test()x = 'good'
y = True
print(globals()) # {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x101710630>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/jiangwei/Desktop/Test/test.py', '__cached__': None, 'test': <function test at 0x101695268>, 'x': 'good', 'y': True}
函数返回值
在python中我们怎样返回多个值?
一、多个return?
def create_nums():print("---1---")return 1 # 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数print("---2---")return 2print("---3---")
Copy
总结1:
-
一个函数中可以有多个return语句,但是只要有一个return语句被执行到,那么这个函数就会结束了,因此后面的return没有什么用处
-
如果程序设计为如下,是可以的因为不同的场景下执行不同的return
def create_nums(num):print("---1---")if num == 100:print("---2---")return num+1 # 函数中下面的代码不会被执行,因为return除了能够将数据返回之外,还有一个隐藏的功能:结束函数else:print("---3---")return num+2print("---4---")result1 = create_nums(100)print(result1) # 打印101result2 = create_nums(200)print(result2) # 打印202
Copy
二、一个函数返回多个数据的方式
def divid(a, b):shang = a//byushu = a%b return shang, yushu #默认是元组result = divid(5, 2)
print(result) # 输出(2, 1)
Copy
总结2:
-
return后面可以是元组,列表、字典等,只要是能够存储多个数据的类型,就可以一次性返回多个数据。
def function():# return [1, 2, 3]# return (1, 2, 3)return {"num1": 1, "num2": 2, "num3": 3}
Copy -
如果return后面有多个数据,那么默认是元组。
对返回的数据直接拆包
def get_my_info():high = 178weight = 100age = 18return high, weight, age # 函数返回三个数据,会自动打包为元组# result = get_my_info() # result 接收到一个元组
# print(result)my_high, my_weight, my_age = get_my_info() # 直接把元组拆分为三个变量来使用,更加方便
print(my_high)
print(my_weight)
print(my_age)
Copy
总结:
- 拆包时要注意,需要拆的数据的个数要与变量的个数相同,否则程序会异常
- 除了对元组拆包之外,还可以对列表、字典等拆包
In [17]: a, b = (11, 22)
In [18]: a
Out[18]: 11
In [19]: b
Out[19]: 22In [20]: a, b = [11, 22]
In [21]: a
Out[21]: 11
In [22]: b
Out[22]: 22In [23]: a, b = {"m":11, "n":22} # 取出来的是key,而不是键值对
In [24]: a
Out[24]: 'm'
In [25]: b
Out[25]: 'n'
函数参数详解
一、缺省参数
调用函数时,缺省参数的值如果没有传入,则取默认值。
下例会打印默认的age,如果age没有被传入:
def printinfo(name, age=35):# 打印任何传入的字符串print("name: %s" % name)print("age %d" % age)# 调用printinfo函数
printinfo(name="miki") # 在函数执行过程中 age取默认值35
printinfo(age=9 ,name="miki")
Copy
以上实例输出结果:
name: miki
age: 35
name: miki
age: 9
Copy
总结:
-
在形参中默认有值的参数,称之为缺省参数
-
注意:带有默认值的参数一定要位于参数列表的最后面
>>> def printinfo(name, age=35, sex):... print name...File "<stdin>", line 1SyntaxError: non-default argument follows default argument
Copy
二、不定长参数
有时可能需要一个函数能处理比当初声明时更多的参数, 这些参数叫做不定长参数,声明时不会命名。
基本语法如下:
def functionname([formal_args,] *args, **kwargs):"""函数_文档字符串"""function_suitereturn [expression]
Copy
注意:
- 加了星号(*)的变量args会存放所有未命名的变量参数,args为元组
- 而加**的变量kwargs会存放命名参数,即形如key=value的参数, kwargs为字典.
def test(a, b, *args, **kwargs):"函数在声明时,需要两个参数"print('a={},b={},args={},kwargs={}'.format(a,b,args,kwargs))test(2, 3, '你好', 'hi', 'how do you do', name="zhangsan", age=18)
# a=2,b=3,args=('你好', 'hi', 'how do you do'),kwargs={'name': 'zhangsan', 'age': 18}b = ('hi', '大家好', '今天天气真好')
d = {'name': "zhangsan", "age": 19}# 注意,在传入参数时的星号问题。
test(10, 20, *b, **d)
# a=10,b=20,args=('hi', '大家好', '今天天气真好'),kwargs={'name': 'zhangsan', 'age': 19}# 如果在传值时,不使用星号,会把后面的参数当做 args
test(10,20,b,d)
# a=10,b=20,args=(('hi', '大家好', '今天天气真好'), {'name': 'zhangsan', 'age': 19}),kwargs={}
Copy
三、缺省参数在*args后面
def sum_nums_3(a, *args, b=22, c=33, **kwargs):print(a)print(b)print(c)print(args)print(kwargs)sum_nums_3(100, 200, 300, 400, 500, 600, 700, b=1, c=2, mm=800, nn=900)
Copy
说明:
- 如果很多个值都是不定长参数,那么这种情况下,可以将缺省参数放到 args的后面, 但如果有*kwargs的话,kwargs必须是最后的
-
可变、不可变类型
-
总结
- 所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变,否则是不可变
- 可变类型(修改数据,内存地址不会发生变化)有: 列表、字典、集合
- 不可变类型(修改数据,内存地址必定发生变化)有: 数字、字符串、元组
- 先写可变参数再写缺省参数
# *args 表示可变位置参数
# **kwargs 表示可变的关键字参数def add(a, b, *args, mul=1, **kwargs):# print('a = {},b={}'.format(a, b))# print('args = {}'.format(args)) # 多出来的可变参数会以元组的形式保存到args里print('kwargs = {}'.format(kwargs)) # 多出来的关键字参数会以字典的形式保存c = a + bfor arg in args:c += argreturn c * mul# def add(*args):
# passprint(add(1, 3, 5, 7, mul=2, x=0, y=4))
# add(9, 5, 4, 2, 0, p=9, q=10)
# add(8, 9, 7, 5, 7, 9, 8, 7, 5, 3, t=0, m=5)
递归函数
<1>什么是递归函数
通过前面的学习知道一个函数可以调用其他函数。
如果一个函数在内部不调用其它的函数,而是自己本身的话,这个函数就是递归函数。
<2>递归函数的作用
举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n
解决办法1:使用循环来完成
def cal(num):result,i = 1,1while i <= num:result *= ii+= 1return resultprint(cal(3))
Copy
看阶乘的规律
1! = 1
2! = 2 × 1 = 2 × 1!
3! = 3 × 2 × 1 = 3 × 2!
4! = 4 × 3 × 2 × 1 = 4 × 3!
...
n! = n × (n-1)!
Copy
解决办法2:使用递归来实现
def factorial(num):result = 1if num == 1:return 1result = num * factorial(num -1)return result
print(cal(3))
Copy
原理
匿名函数
用lambda关键词能创建小型匿名函数。这种函数得名于省略了用def声明函数的标准步骤。
lambda函数的语法只包含一个语句,如下:
lambda 参数列表: 运算表达式
Copy
如下实例:
sum = lambda arg1, arg2:/;
[KL''O' arg1 + arg2# 调用sum函数
print("Value of total : %d" % sum( 10, 20 ))
print("Value of total : %d" % sum( 20, 20 ))
Copy
以上实例输出结果:
Value of total : 30
Value of total : 40
Copy
Lambda函数能接收任何数量的参数但只能返回一个表达式的值
匿名函数可以执行任意表达式(甚至print函数),但是一般认为表达式应该有一个计算结果供返回使用。
python在编写一些执行脚本的时候可以使用lambda,这样可以接受定义函数的过程,比如写一个简单的脚本管理服务器。
应用场合
函数作为参数传递
>>> def fun(a, b, opt):
... print("a = " % a)
... print("b = " % b)
... print("result =" % opt(a, b))
...
>>> add = lambda x,y:x+y
>>> fun(1, 2, add) # 把 add 作为实参传递
a = 1
b = 2
result = 3
Copy
练习:
有一个列表
students = [{'name': 'zhangsan', 'age': 18, 'score': 92},{'name': 'lisi', 'age': 20, 'score': 90},{'name': 'wangwu', 'age': 19, 'score': 95},{'name': 'jerry', 'age': 21, 'score': 98},{'name': 'chris', 'age': 17, 'score': 100},
]
Copy
要求,对上述列表里的数据按照score进行升序排序。
Python中使用函数作为参数的内置函数和类:
函数名或类名 | 功能 | 参数描述 |
---|---|---|
sorted函数 | 用来将一个无序列表进行排序 | 函数参数的返回值规定按照元素的哪个属性进行排序 |
filter类 | 用来过滤一个列表里符合规定的所有元素,得到的结果是一个迭代器 | 函数参数的返回值指定元素满足的过滤条件 |
map类 | 将列表里的每一项数据都执行相同的操作,得到的结果是一个迭代器 | 函数参数用来指定列表里元素所执行的操作 |
reduce函数 | 对一个序列进行压缩运算,得到一个值。python3以后,这个方法被移到了functools模块 | 函数参数用来指定元素按照哪种方式合并 |
高阶函数
在Python中,函数其实也是一种数据类型。
def test():return 'hello world'
print(type(test)) # <class 'function'>
Copy
函数对应的数据类型是 function
,可以把它当做是一种复杂的数据类型。
既然同样都是一种数据类型,我们就可以把它当做数字或者字符串来处理。
定义一个变量指向函数
在Python中,我们还可以定义一个变量,让它来指向一个函数,相当于给函数起了一个别名。
def test():return 'hello wrold'fun = test # 定义了一个变量fun,让它指向了 test 这个函数
print(fun()) # 使用fun()可以直接调用test这个函数print(id(fun)) # 1819677672040
print(id(test)) # 1819677672040
Copy
注意:在定义一个变量表示一个函数时,函数后面不能加括号!加括号表示的是调用这个函数。
def test():return 'hello world'result = test() # 这种写法是调用test函数,并把函数的返回值赋值给result变量
print(result()) # 这里会报错 TypeError: 'str' object is not callablefun = test # 这种写法是给test函数起了一个别名,注意,这里的test后面不能加()
fun() # 可以使用别名调用这个函数
Copy
高阶函数
既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,同样,我们还可以把一个函数当做另一个函数的返回值。这种函数的使用方式我们称之为高阶函数。
函数做为另一个函数的参数
def test(age,action):if age < 18:print('您还没满十八岁,请退出')action() # 把参数action直接当做一个函数来调用def smoke():print('我已经年满十八岁了,我想抽烟')my_action = smoke # 定义一个变量my_action,让它指向smoke函数
test(21, my_action) # 将my_action传给 test 函数作为它的参数test(21,smoke) # 还可以不再定义一个新的变量,直接传入函数名
Copy
函数作为另一个函数的返回值
def test():print('我是test函数里输入的内容')def demo():print('我是demo里输入的内容')return test # test 函数作为demo函数的返回值result = demo() # 我是demo里输入的内容 调用 demo 函数,把demo函数的返回值赋值给 result
print(type(result)) # <class 'function'> result 的类型是一个函数result() # 我是demo里输入的内容 我是test函数里输入的内容 既然result是一个函数,那么就可以直接使用() 调用这个函数demo()() # 我是demo里输入的内容 我是test函数里输入的内容
闭包
函数只是一段可执行代码,编译后就“固化”了,每个函数在内存中只有一份实例,得到函数的入口点便可以执行函数了。函数还可以嵌套定义,即在一个函数内部可以定义另一个函数,有了嵌套函数这种结构,便会产生闭包问题。
函数嵌套
在函数里面还可以定义函数,可以嵌套多层,执行需要被调用。
def outer():print('outer----hello')def inner(): # inner这个函数是在outer函数内部定义的print('inner----hello')inner() # inner函数只在outer函数内部可见outer()
# inner() 这里会报错,在outer函数外部无法访问到inner函数
Copy
什么是闭包
闭包是由函数及其相关的引用环境组合而成的实体(即:闭包=函数块+引用环境)。
def outer(n):num = ndef inner():return num+1return innerprint(outer(3)()) # 4
print(outer(5)()) # 5
Copy
在这段程序中,函数 inner 是函数 outer 的内嵌函数,并且 inner 函数是outer函数的返回值。我们注意到一个问题:内嵌函数 inner 中引用到外层函数中的局部变量num,Python解释器会这么处理这个问题呢? 先让我们来看看这段代码的运行结果,当我们调用分别由不同的参数调用 outer 函数得到的函数时,得到的结果是隔离的(相互不影响),也就是说每次调用outer函数后都将生成并保存一个新的局部变量num,这里outer函数返回的就是闭包。 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
修改外部变量的值
闭包里默认不能修改外部变量。
def outer(n):num = ndef inner():num = num + 1return numreturn innerprint(outer(1)())
Copy
上述代码运行时会报错!
UnboundLocalError: local variable 'num' referenced before assignment
原因分析
在python里,只要看到了赋值语句,就会认为赋值语句的左边是一个局部变量。num = num + 1
这段代码里,num
在=
的左边,python解析器会认为我们要修改inner
函数里num
这个局部变量,而这个变量使用之前是未声明的,所以会报错。
解决方案
我们分析过,报错的原因在于当我们在闭包内修改外部变量时,会被python解析器误会为内部函数的局部变量。所以,解决方案就在于,我们需要想办法,让解析器知道我们不是要修改局部变量,而是要修改外部变量。
- 解决方法:使用 nonlocal 关键字
def outer(n):num = ndef inner():nonlocal num # 修改前使用nonlocal关键字对 num 变量进行说明num = num + 1return numreturn innerprint(outer(2)())
装饰器
装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率如虎添翼,所以这也是Python面试中必问的问题。但对于好多初次接触这个知识的人来讲,这个功能有点绕,自学时直接绕过去了,然后面试问到了就挂了,因为装饰器是程序开发的基础知识,这个都不会,别跟人家说你会Python, 看了下面的文章,保证你学会装饰器。
1、先明白这段代码
#### 第一波 ####
def foo():print('foo')foo # 表示是函数
foo() # 表示执行foo函数#### 第二波 ####
def foo():print('foo')foo = lambda x: x + 1foo() # 执行lambda表达式,而不再是原来的foo函数,因为foo这个名字被重新指向了另外一个匿名函数
Copy
函数名仅仅是个变量,只不过指向了定义的函数而已,所以才能通过 函数名()调用,如果 函数名=xxx被修改了,那么当在执行 函数名()时,调用的就不知之前的那个函数了
2、需求来了
初创公司有N个业务部门,基础平台部门负责提供底层的功能,如:数据库操作、redis调用、监控API等功能。业务部门使用基础功能时,只需调用基础平台提供的功能即可。如下:
############### 基础平台提供的功能如下 ###############def f1():print('f1')def f2():print('f2')def f3():print('f3')def f4():print('f4')############### 业务部门A 调用基础平台提供的功能 ###############f1()
f2()
f3()
f4()############### 业务部门B 调用基础平台提供的功能 ###############f1()
f2()
f3()
f4()
Copy
目前公司有条不紊的进行着,但是,以前基础平台的开发人员在写代码时候没有关注验证相关的问题,即:基础平台的提供的功能可以被任何人使用。现在需要对基础平台的所有功能进行重构,为平台提供的所有功能添加验证机制,即:执行功能前,先进行验证。
老大把工作交给 Low B,他是这么做的:
跟每个业务部门交涉,每个业务部门自己写代码,调用基础平台的功能之前先验证。诶,这样一来基础平台就不需要做任何修改了。太棒了,有充足的时间泡妹子...
当天Low B 被开除了…
老大把工作交给 Low BB,他是这么做的:
############### 基础平台提供的功能如下 ############### def f1():# 验证1# 验证2# 验证3print('f1')def f2():# 验证1# 验证2# 验证3print('f2')def f3():# 验证1# 验证2# 验证3print('f3')def f4():# 验证1# 验证2# 验证3print('f4')############### 业务部门不变 ###############
### 业务部门A 调用基础平台提供的功能### f1()
f2()
f3()
f4()### 业务部门B 调用基础平台提供的功能 ### f1()
f2()
f3()
f4()
Copy
过了一周 Low BB 被开除了…
老大把工作交给 Low BBB,他是这么做的:
只对基础平台的代码进行重构,其他业务部门无需做任何修改
############### 基础平台提供的功能如下 ############### def check_login():# 验证1# 验证2# 验证3passdef f1():check_login()print('f1')def f2():check_login()print('f2')def f3():check_login()print('f3')def f4():check_login()print('f4')
Copy
老大看了下Low BBB 的实现,嘴角漏出了一丝的欣慰的笑,语重心长的跟Low BBB聊了个天:
老大说:
写代码要遵循开放封闭
原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即:
- 封闭:已实现的功能代码块
- 开放:对扩展开发
如果将开放封闭原则应用在上述需求中,那么就不允许在函数 f1 、f2、f3、f4的内部进行修改代码,老板就给了Low BBB一个实现方案:
def w1(func):def inner():# 验证1# 验证2# 验证3func()return inner@w1
def f1():print('f1')
@w1
def f2():print('f2')
@w1
def f3():print('f3')
@w1
def f4():print('f4')
Copy
对于上述代码,也是仅仅对基础平台的代码进行修改,就可以实现在其他人调用函数 f1 f2 f3 f4 之前都进行【验证】操作,并且其他业务部门无需做任何操作。
Low BBB心惊胆战的问了下,这段代码的内部执行原理是什么呢?
老大正要生气,突然Low BBB的手机掉到地上,恰巧屏保就是Low BBB的女友照片,老大一看一紧一抖,喜笑颜开,决定和Low BBB交个好朋友。
详细的开始讲解了:
单独以f1为例:
def w1(func):def inner():# 验证1# 验证2# 验证3func()return inner@w1
def f1():print('f1')
Copy
python解释器就会从上到下解释代码,步骤如下:
- def w1(func): ==>将w1函数加载到内存
- @w1
没错, 从表面上看解释器仅仅会解释这两句代码,因为函数在 没有被调用之前其内部代码不会被执行。
从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章, @函数名 是python的一种语法糖。
上例@w1内部会执行一下操作:
执行w1函数
执行w1函数 ,并将 @w1 下面的函数作为w1函数的参数,即:@w1 等价于 w1(f1) 所以,内部就会去执行:
def inner(): #验证 1#验证 2#验证 3f1() # func是参数,此时 func 等于 f1 return inner# 返回的 inner,inner代表的是函数,非执行函数 ,其实就是将原来的 f1 函数塞进另外一个函数中
Copy
w1的返回值
将执行完的w1函数返回值 赋值 给@w1下面的函数的函数名f1 即将w1的返回值再重新赋值给 f1,即:
新f1 = def inner(): #验证 1#验证 2#验证 3原来f1()return inner
Copy
所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在新f1 函数内部先执行验证,再执行原来的f1函数,然后将原来f1 函数的返回值返回给了业务调用者。
如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用者。Low BBB 你明白了吗?要是没明白的话,我晚上去你家帮你解决吧!!!
3. 再议装饰器
# 定义函数:完成包裹数据
def makeBold(fn):def wrapped():return "<b>" + fn() + "</b>"return wrapped# 定义函数:完成包裹数据
def makeItalic(fn):def wrapped():return "<i>" + fn() + "</i>"return wrapped@makeBold
def test1():return "hello world-1"@makeItalic
def test2():return "hello world-2"@makeBold
@makeItalic
def test3():return "hello world-3"print(test1())
print(test2())
print(test3())
Copy
运行结果:
<b>hello world-1</b>
<i>hello world-2</i>
<b><i>hello world-3</i></b>
4. 装饰器(decorator)功能
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
5. 装饰器示例
例1:无参数的函数
def check_time(action):def do_action():action()return do_action@check_time
def go_to_bed():print('去睡觉')go_to_bed()
Copy
上面代码理解装饰器执行行为可理解成
result = check_time(go_to_bed) # 把go_to_bed 当做参数传入给 check_time函数,再定义一个变量用来保存check_time的运行结果
result() # check_time 函数的返回值result是一个函数, result()再调用这个函数,让它再调用go_to_bed函数
Copy
例2:被装饰的函数有参数
def check_time(action):def do_action(a,b):action(a,b)return do_action@check_time
def go_to_bed(a,b):print('{}去{}睡觉'.format(a,b))go_to_bed("zhangsan","床上")
Copy
例3:被装饰的函数有不定长参数
def test(cal):def do_cal(*args,**kwargs):cal(*args,**kwargs)return do_cal@test
def demo(*args):sum = 0for x in args:sum +=xprint(sum)demo(1, 2, 3, 4)
Copy
例4:装饰器中的return
def test(cal):def do_cal(*args,**kwargs):return cal(*args,**kwargs) # 需要再这里写return语句,表示调用函数,获取函数的返回值并返回return do_cal@test
def demo(a,b):return a + bprint(demo(1, 2)) #3
Copy
总结:
- 一般情况下为了让装饰器更通用,可以有return
例5:装饰器带参数
def outer_check(time):def check_time(action):def do_action():if time < 22:return action()else:return '对不起,您不具有该权限'return do_actionreturn check_time@outer_check(23)
def play_game():return '玩儿游戏'print(play_game())
Copy
提高:使用装饰器实现权限验证
以下代码不要求掌握,如果能看懂最好,如果能自己手动写出来,那就太棒了!
def outer_check(base_permission):def check_permission(action):def do_action(my_permission):if my_permission & base_permission:return action(my_permission)else:return '对不起,您不具有该权限'return do_actionreturn check_permissionREAD_PERMISSION = 1
WRITE_PERMISSION = 2
EXECUTE_PERMISSION = 4@outer_check(base_permission=READ_PERMISSION)
def read(my_permission):return '读取数据'@outer_check(base_permission=WRITE_PERMISSION)
def write(my_permission):return '写入数据'@outer_check(base_permission=EXECUTE_PERMISSION)
def execute(my_permission):return '执行程序'print(read(5))
装饰器的结构
dec onter(fn):
def inner():
pass
return inner
*args关键字参数
**kwargs可变的关键字参数
相关文章:
python入门9-函数基础
函数介绍 <1>什么是函数 请看如下代码: print(" _ooOoo_ ") print(" o8888888o ") print(" 88 . 88 ") print(" …...
AMD(Xilinx) FPGA配置Flash大小选择
目录 1 FPGA配置Flash大小的决定因素2 为什么选择的Flash容量大小为最小保证能够完成整个FPGA的配置呢? 1 FPGA配置Flash大小的决定因素 在进行FPGA硬件设计时,选择合适的配置Flash是我们进行硬件设计必须考虑的,那么配置Flash大小的选择由什…...
TypeScript学习笔记(二)
接一 四、类型声明 使用 : 来对变量或函数形参,进行类型声明: let a: string //变量a只能存储字符串 let b: number //变量b只能存储数值 let c: boolean //变量c只能存储布尔值 a hello a 100 //警告:不能将类型“number”分配给类型“…...
Centos Stream 9安装Jenkins-2.485 构建自动化项目步骤
官网:https://www.jenkins.io/ 1 下载 环境准备: 版本支持查询:https://pkg.jenkins.io/redhat-stable/ 安装JDK17:https://blog.csdn.net/qq_44870331/article/details/140784297 yum -y install epel-release wget upgradew…...
多目标粒子群优化(Multi-Objective Particle Swarm Optimization, MOPSO)算法
概述 多目标粒子群优化(MOPSO) 是粒子群优化(PSO)的一种扩展,用于解决具有多个目标函数的优化问题。MOPSO的目标是找到一组非支配解(Pareto最优解),这些解在不同目标之间达到平衡。…...
【网络系统管理】2023年全国职业院校技能大赛:组策略--10套题组合--1
1、限制访问C盘; (1)搜索《我的电脑》 (2)用户配置\策略\管理模板\Windows组件\文件资源管理器 2、禁止运行run.exe; (1)搜索《应用程序》 (2)用户配置\策略\管理模板\系统...
【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定
在现代 Web 开发中,API(特别是 RESTful API)是前后端分离架构的核心。Gin 框架提供了丰富的功能来处理 API 请求和 JSON 数据,使得开发者可以快速构建高效的接口服务。本篇博客将从基础到深入,全面讲解如何使用 Gin 框…...
在Linux下配置gitee与Github的远程仓库
目录 前言 云服务器下载git 检测是否下载成功git Linux下配置gitee远程仓库 代码提交演示 git三板斧 Linux下配置Github远程仓库 最后的提醒 前言 那么本篇文章将是在,你已经创建了本地仓库的基础上,在Linux下配置gitee的远程仓库的步骤ÿ…...
自动化测试过程操作细节
一、软件与框架介绍 1. Postman 读音:[pəʊstmən](剖斯特曼) 介绍:API开发与测试的得力助手,通过直观界面发送HTTP请求,查看响应数据。支持环境变量、集合、脚本等功能。 主要特点:易于使用…...
iic协议
IIC(Inter-Integrated Circuit)协议,也被称为I2C协议,是一种由荷兰的PHILIPS公司(现为NXP半导体公司)开发的简单、高效的通信协议。以下是关于IIC协议的详细介绍: 一、IIC协议概述 定义&#…...
uniapp、js判断输入的内容是整数
清奇的思路 通过取余运算符 % 来检查 输入的内容是否为整数 for (var i 0; i < this.list.length; i) {if (this.list[i].times % 1 ! 0) { // 使用取余运算符检查是否为整数uni.showToast({icon: none,title: 请输入整数的套餐次数,})return;}}...
《Qt Creator:人工智能时代的跨平台开发利器》
《Qt Creator:人工智能时代的跨平台开发利器》 一、Qt Creator 简介(一)功能和优势(二)快捷键与效率提升(三)跨平台支持(四)工具介绍与使用主要特性:使用步骤…...
The Yarn application application_xxx_xxx doesn‘t exist in RM
本文主要解决flink在standalone模式下,flink run却一直使用yarn-session模式的问题。 问题 有个客户找到笔者,问题是报错如下: 分析 笔者先从环境入手,首先要确定的是flink是使用了什么模式。确认过后是使用standalone模式。 那就很奇怪&a…...
爬虫实战:采集知乎XXX话题数据
目录 反爬虫的本意和其带来的挑战目标实战开发准备代码开发发现问题1. 发现问题[01]2. 发现问题[02] 解决问题1. 解决问题[01]2. 解决问题[02] 最终结果 结语 反爬虫的本意和其带来的挑战 在这个数字化时代社交媒体已经成为人们表达观点的重要渠道,对企业来说&…...
【C++篇】像解谜一样转换字符串:stoi 带你走向整数的世界
文章目录 前言 在现代 C 编程中,字符串与数字之间的转换是非常常见的需求。随着编程语言的发展,C 提供了多种方式来处理这种转换。stoi(string to integer)函数正是为了简化这一任务而被引入的。 在 C 的早期版本中,字…...
小U数数问题
问题描述 小U正在数偶数,从 0,2,4,6,8,10,12,…0,2,4,6,8,10,12,… 开始,依次将这些数连在一起,形成一个无穷长的字符串,例如:"0246810121416..."。小U想知道这个字符串中的第 nn 个字符是什么。 测试样例 …...
Rocky Linux 系统安装/部署 Docker
1、下载docker-ce的repo文件 [rootlocalhost ~]# curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker.repo % Total % Received % Xferd Average Speed Time Time Time Current Dloa…...
程序语言语法上手题目合集
程序语言语法上手题目合集 1跑步2猜年龄3Vigenre 密码 1跑步 2.跑步 - 蓝桥云课 枚举日期,判断是否符合条件即可。 参考程序: #include<stdio.h> int y2022,m1,d1; int week6; int month[13]{0,31,28,31,30,31,30,31,31,30,31,30,31};int judg…...
MCU通过APB总线与FPGA 数据交互(实现JATG 模块的控制)
问题出发点: 通过MCU 的APB 将数据发送到fpga 端;fpga 端实现 jtag 模块功能,支持状态机TAP的移动主要是:从IDLE 移动到 shirft-IR 发送指令数据然后再回到 IDLE ,从 IDLE 移动到shirft-DR 发送用户数据再回到IDLE;从而可以 通过 mcu端实现jtag 协议控制。 为了实现 MC…...
Mysql的UPDATE(更新数据)详解
MySQL的UPDATE语句是用于修改数据库表中已存在的记录,本文将详细介绍UPDATE语句的基本语法、高级用法、性能优化策略以及注意事项,帮助您更好地理解和应用这一重要的SQL命令。 1. 基本语法 单表更新 单表更新的基本语法如下: UPDATE [LOW…...
【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
Dual Pixel 简介 双像素是成像系统的感光元器件中单帧同时生成的图像:通过双像素可以实现:深度估计、图像去模糊去雨去雾恢复、图像重建 成像原理来源如上,也有遮罩等方式的pd生成,如图双像素视图可以看到光圈的不同一半&#x…...
如何使用AWS Lambda构建一个云端工具(超详细)
首发地址(欢迎大家访问):如何使用AWS Lambda构建一个云端工具(超详细) 1 前言 1.1 无服务器架构 无服务器架构(Serverless Computing)是一种云计算服务模型,它允许开发者构建和运行…...
Scala—数组(数组定义、数组常用方法等)— 用法详解
Scala Scala-数组-用法详解 Scala一、数组的定义1. new 关键字2. Array 对象的 apply 方法3. 创建多维数组 二、数组常用方法1. length:获取数组的长度。2. apply:通过索引获取数组中的元素。3. update:通过索引更新数组中的元素。4. foreach…...
使用 Elastic 收集 Windows 遥测数据:ETW Filebeat 输入简介
作者:来自 Elastic Chema Martinez 在安全领域,能够使用 Windows 主机的系统遥测数据为监控、故障排除和保护 IT 环境开辟了新的可能性。意识到这一点,Elastic 推出了专注于 Windows 事件跟踪 (ETW) 的新功能 - 这是一种强大的 Windows 原生机…...
二分排序
二分问题之前遇到很多次了,不过一直是手写完整二分,现在转变一下想法,直接使用函数lower_bound和upper_bound更方便 lower_bound 有序数组中 查找第一个不小于指定值的位置。 本质二分代码: int lower_bound_custom(int* arr, i…...
数据库---HSQLDB使用教程详解
本学校期末的课程设计要求使用HSQLDB数据库,作为一个小众且轻量的数据库,很少人接触过,再加上同学们都问这个方面,所以就出教程,展示怎么使用HSQLDB。 第一步:启动HSQLDB 下载HSQLDB的jar包,因…...
Makefile基础应用
1 使用场景 在Linux环境下,我们通常需要通过命令行来编译代码。例如,在使用gcc编译C语言代码时,需要使用以下命令。 gcc -o main main.c 使用这种方式编译代码非常吃力,每次调试代码都需要重新在命令行下重新编译,重复…...
一个点绕任意点旋转后的点的坐标
在平面坐标上,任意点P(x1,y1),绕一个坐标点Q(x2,y2)逆时针旋转θ角度后,新的坐标设为(x, y)的计算公式: x (x1 - x2)*cos(θ) - (y1 - y2)*sin(θ) x2 ; y (x1 - x2)*sin(θ) (y1 - y2)*cos(θ) y2 ; 另一个场景应用,坐标轴绕…...
嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)
引言:对于嵌入式硬件这个庞大的知识体系而言,太多离散的知识点很容易疏漏,因此对于这些容易忘记甚至不明白的知识点做成一个梳理,供大家参考以及学习,本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…...
算力100问☞第16问:什么是TPU?
TPU全称是Tensor Processing Unit芯片,中文全称是张量处理单元芯片,是谷歌开发的一种特殊类型的芯片,用于加速人工智能(AI)和机器学习(ML)工作负载。TPU主要针对张量(tensor…...
Level DB --- SkipList
class SkipList class SkipList 是Level DB中的重要数据结构,存储在memtable中的数据通过SkipList来存储和检索数据,它有优秀的读写性能,且和红黑树相比,更适合多线程的操作。 SkipList SkipList还是一个比较简单的数据结构&a…...
全面解析 JMeter 后置处理器:概念、工作原理与应用场景
在性能测试中,Apache JMeter是一个非常流行的工具,它不仅能够模拟大量用户进行并发访问,还提供了丰富的扩展机制来满足各种复杂的测试需求。后置处理器(Post-Processor)是JMeter中非常重要的组件之一,用于在…...
【视频】二维码识别:libzbar-dev、zbar-tools(zbarimg )
1、简介 ZBar可以使用多个方式识别各种条形码和二维码。 支持的格式有:EAN-13/UPC-A、UPC-E、EAN-8、Code 128、Code 93、Code 39、Codabar、Interleaved 2 of 5、QR Code和SQ Code 支持的来源有:视频流、图像文件等 libzbar-dev:二维码识别开发库 zbar-tools(zbarimg …...
EasyExcel: 结合springboot实现表格导出入(单/多sheet), 全字段校验,批次等操作(全)
全文目录,一步到位 1.前言简介1.1 链接传送门1.1.1 easyExcel传送门 2. Excel表格导入过程2.1 easyExcel的使用准备工作2.1.1 导入maven依赖2.1.2 建立一个util包2.1.3 ExcelUtils统一功能封装(单/多sheet导入)2.1.4 ExcelDataListener数据监听器2.1.5 ResponseHelper响应值处理…...
志愿者小程序源码社区网格志愿者服务小程序php
志愿者服务小程序源码开发方案:开发语言后端php,tp框架,前端是uniapp。 一 志愿者端-小程序: 申请成为志愿者,志愿者组织端进行审核。成为志愿者后,可以报名参加志愿者活动。 志愿者地图:可以…...
HTML实现 扫雷游戏
前言: 游戏起源与发展 扫雷游戏的雏形可追溯到 1973 年的 “方块(cube)” 游戏,后经改编出现了 “rlogic” 游戏,玩家需为指挥中心探出安全路线避开地雷。在此基础上,开发者汤姆・安德森编写出了扫雷游戏的…...
小白学多线程(持续更新中)
1.JDK中的线程池 JDK中创建线程池有一个最全的构造方法,里面七个参数如上所示。 执行流程分析: 模拟条件:10个核心线程数,200个最大线程数,阻塞队列大小为100。 当有小于十个任务要处理时,因为小于核心线…...
【uni-app多端】修复stmopjs下plus-websocket无心跳的问题
从这篇文章接着向下看: uniapp plus-websocket 和stompjs连接教程 安卓ios手机端有效 - 简书 按照文章的方式,能够实现APP下stmopjs长连接。但是有一个问题,就是会频繁输出 res-创建连接-1- 跟踪连接,会发现连接都会在大约40s后…...
【SLAM文献阅读】基于概率模型的视觉SLAM动态检测与数据关联方法
A dynamic detection and data association method based on probabilistic models for visual SLAM 《基于概率模型的视觉SLAM动态检测与数据关联方法》 2024 摘要: 通常,静态特征采用多视图几何来估计相机姿态和重建环境地图。因此,动态特…...
Linux系统使用valgrind分析C++程序内存资源使用情况
内存占用是我们开发的时候需要重点关注的一个问题,我们可以人工根据代码推理出一个消耗内存较大的函数,也可以推理出大概会消耗多少内存,但是这种方法不仅麻烦,而且得到的只是推理的数据,而不是实际的数据。 我们可以…...
Selenium+Java(19):使用IDEA的Selenium插件辅助超快速编写Pages
前言 或是惊叹于Selenium对于IDEA的支持已经达到了这样的地步,又或是由于这个好用的小工具的入口就在那里,它已经陪伴了我这么久,而我这么久的时间却都没有发现它。在突然发现这个功能的一瞬间,真的是喜悦感爆棚,于是赶快写下了这篇文章。希望可以帮助到其他同样在做UI自动…...
Unity 设计模式-单例模式(Singleton)详解
设计模式 设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构…...
OAuth协议详解
一、基本概念 OAuth(Open Authorization)是一种授权协议,用于允许第三方应用程序以受信任的方式访问用户的资源,而无需共享用户的身份验证凭据。OAuth协议的核心目标是在保持用户数据安全的前提下,简化用户在不同应用…...
2024收官之战:车展向下,智驾向上
作者 | 德新 编辑 | 王博 广州车展在上周拉开帷幕,在激烈的车市竞争中,可以说没有一届车展比本届更加「 冰火两重天」。 在本届车展前夕,已经传出不少车企集团面临业务整合的消息,一部分品牌缺席了本届车展,而势头强…...
开源项目-如何更好的参与开源项目开发
开源之谜-提升自我核心竞争力 一、寻找适合自己的开源项目二、像坐牢一样闭关修炼三、最后的实践 开源代码对所有人开放,开发者可以基于现有代码进行扩展和创新,而不是从零开始,参与开源项目可以提升自我的技术能力,丰富个人的经历…...
如何重命名 Conda 环境 - 详细教程
如何重命名 Conda 环境 - 详细教程 前言重命名步骤1. 克隆现有环境2. 验证新环境3. 删除旧环境 实例演示注意事项常见问题解答Q1: 为什么 Conda 没有直接的重命名命令?Q2: 重命名过程会影响环境中的包吗?Q3: 如果克隆过程中断,会怎么样&#…...
自动驾驶之激光雷达
这里写目录标题 1 什么是激光雷达2 激光雷达的关键参数3 激光雷达种类4 自动驾驶感知传感器5 激光雷达感知框架5.1 pointcloud_preprocess5.2 pointcloud_map_based_roi5.3 pointcloud_ground_detection5.4 lidar_detection5.5 lidar_detection_filter5.6 lidar_tracking 1 什么…...
Python毕业设计选题:基于python的豆瓣电影数据分析可视化系统-flask+spider
开发语言:Python框架:flaskPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 系统首页 个人中心 管理员登录界面 管理员功能界面 电影管理 用户管理 系统管理 摘要…...
从 Mac 远程控制 Windows:一站式配置与实践指南20241123
引言:跨平台操作的需求与挑战 随着办公场景的多样化,跨平台操作成为现代开发者和 IT 人员的刚需。从 Mac 系统远程控制 Windows,尤其是在同一局域网下,是一种高效解决方案。不仅能够灵活管理资源,还可以通过命令行简化…...
k8s部署Nginx详细教程
Kubernetes(简称k8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。本文将详细介绍如何使用k8s部署Nginx,包括创建部署配置、创建服务以及如何通过一个命令完成部署和删除。 环境准备 在开始之前&#x…...