Python基础语法(三)

Python基础语法(三)

函数

函数是什么

数学当中的函数:三角函数:sin,cos,y=ax+b,一个x对应一个y,具有某种映射关系

而编程当中的函数是一段可以被重复使用的代码

# 1.求1-100的和
theSum = 0
for i in range(1, 101):
	theSum += i
print(theSum)

# 2.求300-400 的和
theSum = 0
for i in range(300,401):
	theSum += i
print(theSum)

# 3.求1-1000的和
theSum = 0
for i in range(1, 1001):
	theSum += i
print(theSum)

上面代码我们求了1-100的和,300-400的和,1-1000的和,我们发现功能都是类似的,我们可以使用函数来更加简洁的解决:

# 定义一个求和函数
def calcSum(begin,end):
    theSum = 0
    for i in range(begin,end):
        theSum += i
    print(theSum)

# 调用函数
# 1.求1-100的和
calcSum(1,101)
# 1.求300-400的和
calcSum(300,401)
# 1.求1-1000的和
calcSum(1,1001)

def为定义函数关键字。

语法格式

创建函数/定义函数:

def 函数名(形参列表):
    函数体
    return 返回值

形参列表中,可以有多个形参,多个形参之间使用逗号分隔,return语句并不是必须的。

调用函数/使用函数:

函数名(实参列表)	//不考虑返回值
返回值 = 函数名(实参列表)	//考虑返回值
  • 函数定义并不会执行函数体内容,必须要调用才会执行,调用几次就会执行几次

  • 定义在前,调用在后

函数参数

# 定义一个求和函数
def calcSum(begin,end):
    theSum = 0
    for i in range(begin,end):
        theSum += i
    print(theSum)

# 调用函数
# 1.求1-100的和
calcSum(1,101)
# 1.求300-400的和
calcSum(300,401)
# 1.求1-1000的和
calcSum(1,1001)

上面代码中:1,101,300,401,1,1001都是函数的实参,begin和end是函数的形参。

注意:

  • 一个函数可以有一个形参,也可以有多个形参,也可以没有形参。
  • 一个函数的形参有几个,那么传递实参的时候也得传几个,保证个数要匹配函数返回值

函数返回值

函数的参数可以视为是函数的“输入",则函数的返回值就可以视为是函数的“输出”。
此处的“输入",“输出”是更广义的输入输出,不是单纯指通过控制台输入输出.
我们可以把函数想象成一个"厂",工厂需要买入原材料,进行加工,并生产出产品.
函数的参数就是原材料,函数的返回值就是生产出的产品
下列代码:

def calcsum(beg, end):
    sum=0
    for i in range(beg, end + 1):
    	sum += i
    print(sum)
calc(1,100)

可以转换成:

def calcsum(beg, end):
    sum=0
    for i in range(beg, end + 1):
    	sum += i
    return sum

result = calcSum(1, 100)
print(result)

这两个代码的区别就在于,前者直接在函数内部进行了打印,后者则使用return语句把结果返回给函数调用者,再由调用者负责打印.

我们一般倾向于第二种写法。
实际开发中我们的一个通常的编程原则,是“逻辑和用户交互分离",而第一种写法的函数中, 既包含了计算逻辑,又包含了和用户交互(打印到控制台上),这种写法是不太好的,如果后续我们需要的是把计算结果保存到文件中,或者通过网络发送或者展示到图形化界面里,那么第一种写法的函数, 就难以胜任了。

而第二种写法则专注于做计算逻辑,不负责和用户交互.那么就很容易把这个逻辑搭配不同的用户交互代码,来实现不同的效果。

Python中的一个函数可以返回多个值,C++要想返回多个值,可以通过输出型参数(指针/引用)

写一个函数,返回平面上的一个点:

def getPoint():
    x = 10
    y = 20
    return x, y


a, b = getPoint()
print(f"a = {a},b = {b}")
image-20230130170713741

虽然现在返回了多个值,但是只想用其中的一部分,不关注其他的,可以使用_来进行占位!

_, b = getPoint()

不要x,只要y,把y赋值给b即可!

变量作用域

观察以下代码

def getPoint():
    x = 10
    y = 20
    return x,y


x,y = getPoint()

在这个代码中,函数内部存在x, y,函数外部也有x,y。但是这两组x, y不是相同的变量,而只是恰好有一样的名字,变量只能在所在的函数内部生效。在函数getPoint()内部定义的x, y只是在函数内部生效,一旦出了函数的范围,这两个变量就不再生效了。

def getPoint():
    x=10
    y=20
    return x,y


getPoint()
print(x, y)
image-20230130171413558

在不同的作用域中,允许存在同名的变量,虽然名字相同,实际上是不同的变量。

x=20
def test():
    x = 10
    print(f'函数内部x = {x}')
    

test()
print(f'函数外部x = {x}')
image-20230130171535756

值为20的为全局变量,是在整个程序中都有效的,值为10的为局部变量,只是在函数内部有效

在函数里尝试读取全局变量,是可以的!当函数中尝试访问某个变量的时候,会先尝试在局部变量中查找,如果找到,就直接访问,如果没找到,就会往上一级作用域中进行查找。

如果想在函数里面修改全局变量:

x = 10
def test():
    # 声明x为全局变量,没有glabal,则会将x当成局部变量进行定义
    global x
    x = 20
    

test()
print(f"x = {x}")

像if,while,for这些语句的代码块当中定义的变量,在python当中是可以在外面进行访问的,而C++是不允许的。C++当中是有作用域的限制的,而Python当中的作用域的限制是函数以及类当中。

函数执行过程

  • 调用函数才会执行函数体代码,不调用则不会执行
  • 函数体执行结束(或者遇到return语句),则回到函数调用位置继续往下执行。

链式调用

前面的代码很多都是写作

#判定是否是奇数
def isOdd(num) ;
	if num % 2 == 0:
		return False
	else:
		return True

result = isOdd(10)
print(result)

实际上也可以简化写作:

print(isOdd(10))

把一个函数的返回值,作为另一个函数的参数, 这种操作称为链式调用,这是一 种比较常见的写法。

嵌套调用

函数内部还可以调用其他的函数,这个动作称为“嵌套调用" .

def test():
    print ("执行函数内部代码")
    print ("执行函数内部代码")
    print ("执行团数内部代码")

test函数内部调用了print 函数这里就属于嵌套调用。
一个函数里面可以嵌套调用任意多个函数,函数嵌套的过程是非常灵活的。

函数递归

在Python中,我们知道一个函数可以调用其他函数。函数甚至可能会调用自身。这些类型的构造称为递归函数。

递归函数的示例,求一个数字的阶乘:

def calc_factorial(x):
    """这是一个
    求整数阶乘的递归函数"""
    if x == 1:
        return 1
    else:
        return (x * calc_factorial(x-1))
    

calc_factorial(4)

calc_factorial()是一个递归函数,它调用了自己。当我们用正整数调用此函数时,它将通过减少数量来递归调用自身。

每个函数将数字乘以该数字下面的数字的阶乘,直到它等于1。即4! = 4 * 3!,3! = 3 * 2!

递归调用的步骤:

calc_factorial(4)              # 1st call with 4
4 * calc_factorial(3)          # 2nd call with 3
4 * 3 * calc_factorial(2)      # 3rd call with 2
4 * 3 * 2 * calc_factorial(1)  # 4th call with 1
4 * 3 * 2 * 1                  # return from 4th call as number=1
4 * 3 * 2                      # return from 3rd call
4 * 6                          # return from 2nd call
24                             # return from 1st call

当数字减少到1时,递归结束。这称为基本条件。

每个递归函数必须具有停止递归的基本条件,否则该函数将无限调用自身。

Python解释器限制了递归的深度,以帮助避免无限递归,从而导致堆栈溢出。

默认情况下,最大递归深度为 1000。如果超出限制,则结果为RecursionError。

参数默认值

Python中的函数,可以给形参指定默认值.
带有默认值的参数可以在调用的时候不传参.
代码示例:计算两个数字的和

def add(x, y, debug=False):
	if debug:
		print(f"调试信息: x={x}, y={y}')
	return x+ y
              
print(add(10,20))
print(add(10, 20True))

此处debug=False即为参数默认值,当我们不指定第三个参数的时候默认debug的取值即为False.

带有默认值的参数需要放到没有默认值的参数的后面

def add(x, debug=False, y):
	if debug: 
		print(f'调试信息: x={x}, y={y}')
	return x + y

print(add(10, 20))
image-20230130203535095

关键字参数

在调用函数的时候,需要给函数指定实参,一般默认情况下是按照形参的顺序,来依次传递实参的。
但是我们也可以通过关键字参数,来调整这里的传参顺序,显式指定当前实参传递给哪个形参:

def test(x, y):
    print(f'x = {x}')
    print(f'y = {y}')
    
test(x=10, y=20)
test(y=100, x=200)
image-20230130203924923

形如上述test(x=10, y=20)这样的操作,即为关键字参数。按照形参的名字进行传参,非常明显的告诉程序员,你的参数要传给谁!,可以无视形参和实参的顺序。

列表和元组

什么是列表,什么是元组

编程中,经常需要使用变量,来保存/表示数据。

如果代码中需要表示的数据个数比较少,我们直接创建多个变呈即可。

num1 = 10
num2 = 20
num3 = 30

但是有的时候,代码中需要表示的数据特别多,甚至也不知道要表示多少个数据,这个时候,就需要用到列表。列表是一种让程序猿在代码中批量表示/保存数据的方式
就像我们去超市买辣条,如果就只是买—两根辣条,那咱们直接拿着辣条就走了,但是如果一次买个十根八根的,这个时候用手拿就不好拿,超市老板就会给我们个袋子。这个袋子,就相当于列表。
元组和列表相比,是非常相似的,只是列表中放哪些元索可以修改调整,元组中放的元素是创建元组的时候就设定好的,不能修改调整。

列表和元组类似于C++当中的数组。列表可变,元组不可变。

创建列表

创建列表有两种方式:

  1. 直接使用字面值来创建
a = []
# []表示一个空的列表
  1. 使用list()来创建
b = list()
  1. 可以在创建列表的时候,在[]中指定列表的初始值,元素之间使用,分割
a = [1, 2, 3, 4]
print(a)
image-20230131110534644

C++当中要求一个数组里只能存相同类型的变量

  1. 可以在同一个列表里放不同类型的变量
a = [1,'hello',True,1.0]
print(a)
image-20230131110612607

访问下标

列表里面可以管理很多元素,通过下标访问的方式来访问列表中的元素,下标访问运算符:[]

a = [1,'hello',True,1.0]
print(a[0],a[1],a[2],a[3])
image-20230131111024513

注意下标从0开始计数。

使用下标修改列表元素:

a = [1,'hello',True,1.0]
a[0] = 100
print(a)
image-20230131111206949

下标的有效范围:[0,长度-1],超出下标有效范围就是越界访问

可以使用内建函数len来获取到列表的长度,和字符串类似,len可以传参字符串,列表,元组,字典,自定义的类等,python中的下标,还可以写成负数,比如a[-1]表示列表a的倒数第一个元素,a[-2]表示列表a的倒数第二个元素

切片操作

通过下标操作是一次取出里面第一个元素,通过切片,则是—次取出—组连续的元素,相当于得到一个子列表

  • 使用[ : ]的方式进行切片操作。
alist = [1, 2, 3, 4]
print(alist[1:3])

alist[1:3]中的1:3表示的是[1,3)这样的由下标构成的前闭后开区间。
也就是从下标为1的元素开始(2),到下标为3的元素结束(4),但是不包含下标为3的元素,所以最终结果只有2,3

  • 切片操作中可以省略前后边界
alist = [1, 2, 3, 4]
print(alist[1:])
#省略后边界,表示获取到列表末尾
print(alist[:-1])
#省略前边界,表示从列表开头获取
print(alist[:])
#省略两个边界,表示获取到整个列表。
image-20230131112401641
  • 切片操作还可以指定“步长”,也就是""每访问—个元素后,下标自增几步”
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(alist[::1])
print(alist[::2])
print(alist[::3])
print(alist[::5])

这里再多加一个:,再多加一个数字,这个数字就是步长。

image-20230131112910096

步长的数值还可以是负数,当步长为负数的时候,意思是从后往前来取元素

当切片中的范围超出有效下标之后,不会出现异常!而是尽可能的把符合要求的元素获取到:

alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(alist[1:100])
image-20230131113317481

切片操作是一个比较高效的操作,进行切片的时候,只是取出了原有列表中的一个部分,并不涉及到"数据的拷贝假设有一个很大的列表,进行切片,切片的范围也很大,即使如此,切片操作仍然非常高效.

遍历列表元素

  1. 使用for循环进行遍历
a = {1, 2, 3, 4, 5}
for elem in a:
    print(elem)

对elem修改,不会影响a列表。

  1. 使用for循环遍历,通过下标的方式
a = {1, 2, 3, 4, 5}
for i in range(0,len(a)):
    print(a[i])
  1. 使用while循环,通过下标遍历
a = {1, 2, 3, 4, 5}
i = 0
while i < len(a):
    print(a[i])

新增元素

  • 使用append方法,向列表末尾插入一个元素(尾插)。
alist = [1, 2, 3, 4]
alist.append('he11o')
print(alist)
image-20230131142717355

此处的append是搭配列表对象a,来一起使用的,而不是作为一个独立的函数

type,print,input,len这些自定义函数都是独立的函数,这种要搭配对象来使用的函数,也叫做方法

  • 使用insert方法,向任意位置插入—个元素

    insert第一个参数表示要插入元素的下标。

alist = [1, 2, 3, 4]
alist.insert(1, "hello")
alist.insert(100, "hello")
print(alist)
image-20230131142849761

什么是"方法”?(method)

方法其实就是函数.只不过函数是独立存在的,而方法往往要依附于某个"对象".
像上述代码 alist.append , append就是依附于alist,相当于是““针对alist这个列表,进行尾插操作”

查找元素

  • 使用in操作符,判断元素是否在列表中存在,返回值是布尔类型。
alist = [1, 2, 3, 4]
print(2 in alist)
print(5 in alist)
image-20230131143048318
print(1 not in alist)
#若1不在alist当中,则返回True,否则返回false
print(5 not in alist)
  • 使用index方法,查找元素在列表中的下标,返回值是一个整数(下标),如果元素不存在,则会抛出异常
alist = [1, 2, 3, 4]
print(alist.index(2))
print(alist,index(5))
image-20230131143319184

删除元素

  1. 使用pop删除列表中最末尾的元素
alist = [1, 2, 3, 4]
alist.pop()
print(alist)
image-20230131145219648
  1. 使用pop还能删除任意位置的元素,pop的参数可以传一个下标过去
alist = [1, 2, 3, 4]
alist.pop(1)
print(alist)
image-20230131145240939
  1. 使用remove方法,可以按照值来进行删除
a = ['aa', 'bb', 'cc', 'dd']
a.remove('cc')
print(a)
image-20230131145300153

连接列表

  • 使用+能够把两个列表拼接在—起。

此处的+结果会生成一个新的列表,而不会影响到旧列表的内容.

alist = [1, 2, 3, 4]
blist = [5, 6, 7]
print(alist + blist)
image-20230131145627018
  • 使用extend方法,相当于把一个列表拼接到另一个列表的后面。

a.extend(b),是把b中的内容拼接到a的末尾,不会修改b,但是会修改a。

alist = [1, 2, 3, 4]
b1ist = [5, 6, 7]
alist.extend(blist)
print(alist)
print(blist)
image-20230131151342696

None这是一个特殊的变量的值,表示"啥都没有"。

  • 使用+=进行拼接
alist = [1, 2, 3, 4]
b1ist = [5, 6, 7]
alist += blist
print(alist)
print(blist)
image-20230131152159849

看似和extend执行结果一样,但是执行的过程是有差别的,a += b,等价于a = a + b,a += b会首先创建更大的空间来保存a + b,然后再将a + b赋值给a,a的旧值会释放。而extend操作只是将b的值附加到a的末尾了。extend的开销更小一些。

关于元组

元组的功能和列表相比,基本是一致的。

元组使用()来表示。

atuple = ()
atuple = tuple()

元组不能修改里面的元素,列表则可以修改里面的元素

因此,像读操作,比如访问下标切片,遍历, in, index,+等,元组也是一样支持的。

但是,像写操作,比如修改元素,新增元素,删除元素, extend等,元组则不能支持。

另外,元组在 Python中很多时候是默认的集合类型,例如,当一个函数返回多个值的时候。

def getPoint():
	return 10, 20

result = getPoint()
print(type(result))

此处的result的类型,其实是元组。

image-20230131153446232

问题来了,既然已经有了列表,为啥还需要有元组?

元组相比于列表来说,优势有两方面:

  • 你有一个列表,现在需要调用一个函数进行一些处理,但是你又不是特别确认这个函数是否会把你的列表数据弄乱.那么这时候传一个元组就安全很多。

  • 我们马上要讲的字典,是一个键值对结构,要求字典的键必须是"可hash对象"(字典本质上也是一个hash表),而一个可hash对象的前提就是不可变,因此元组可以作为字典的键,但是列表不行。

字典

字典是什么

字典是一种存储键值对的结构。
啥是键值对?这是计算机/生活中一个非常广泛使用的概念。

把键(key)和值(value)进行一个一对一的映射,然后就可以根据键,快速找到值。举个要子,学校的每个同学,都会有一个唯一的学号,知道了学号,就能确定这个同学。此处"学号”就是“键",这个"同学"就是"值"。可以根据key能够快速的找到value。在Python的字典中,可以同时包含很多个键值对,同时要求这些键,不能重复。

创建字典

a = {}
print(type(a))
b = dict()
print(type(b))
image-20230202150921929

创建字典的同时设定初始值:

a= {"id" : 1, 
    "name" : "zhangsan"
}
print(a)
image-20230202150841080

一个字典中的key的类型不一定都一样,一个字典中的value的类型不一定都一样

查找key

  • 使用in可以判定key是否在字典中存在,返回布尔值
student = {
    "id": 1,
    "name": "zhangsan"
}
print("id" in student)
print("score" in student)
image-20230202160032934

in不能判断value在不在字典中。

  • 使用[]通过类似于取下标的方式,获取到元素的值,只不过此处的下标是key,可能是整数,也可能是字符串等其他类型
student = {
    "id": 1,
    "name": "zhangsan"
}
print(student["id"])
print(student["name"])
image-20230202160136695
  • 如果key在字典中不存在,则会抛出异常
student = {
    "id": 1,
    "name": "zhangsan"
}
print(student["score"])
image-20230202160201460

该error表示这个key在该字典中不存在

新增/修改元素

使用[]来进行新增元素

a = {
    "id": 1,
    "name": "zhangsan"
}
# 该操作就是往字典中新增元素
a["score"] = 90
print(a)
image-20230202160920372

修改操作,根据key修改value:

a = {
    "id": 1,
    "name": "zhangsan"
}
# 该操作就是往字典中新增元素
a["score"] = 100
print(a)
image-20230202161109362

如果key 不存在,往里写入,相当于新增键值对。
如果key存在,往里写入,则相当于根据key修改value。

删除元素

使用pop方法,根据key来删除键值对

a = {
    "id": 1,
    "name": "zhangsan"
}
a.pop("name")
print(a)

image-20230202161459538

遍历字典元素

遍历指的就是能够把一个可迭代对象,里面包含的元素依次的取出来,并进行一些操作.整个过程要求不重不漏。
字典被设计出来的初衷,不是为了实现遍历,而是为了增删改查。字典是哈希表,进行增删改查操作,效率都是非常高的,而字典的遍历则效率就要差一些,哈希表这个结构被设计的非常巧妙,能够以"常数级"时间复杂度来完成增删改查。

直接使用for循环来遍历字典:

# 直接使用for循环来遍历字典
a = {
    "id": 1,
    "name": "zhangsan"
    "socre": 90 
}
for key in a:
    print(key,a[key])

for循环中对于字典拿到的是key而不是整个key和value。

image-20230202163048491

在C++当中,哈希表里面的键值对存储的顺序是无序的,但是在Python 中还不一样,Python中做了特殊处理能够保证遍历出来的顺序,就是和插入的顺序一致的,Python中的字典,不是一个单纯的哈希表

取出所有key和value

keys 获取到字典中的所有key

values获取到字典中的所有value

items获取到字典中的所有键值对~

# 直接使用for循环来遍历字典
a = {
    "id": 1,
    "name": "zhangsan"
    "socre": 90 
}
print(a.)print(a.keys())
print(a.values())
print(a.items())
image-20230202164102754

items返回的元素是一个列表,列表里面又是元组,所以可以这样遍历:

for key,value in a.items():
    print(key,value)
image-20230202164530620

合法的key类型

使用hash函数能够计算出一个变量的哈希值

print(hash(0))
print(hash(3.14))
print(hash('hello'))
print(hash(True))
print(hash((1, 2, 3)))

有的类型是不能计算哈希值的:

print(hash([1, 2, 3]))

list是不可哈希类型

print(hash(dict()))

字典也是不可哈希类型。

可以认为一个不可变的对象,一般就是可哈希的,可变的对象,一般就是不可哈希的。

文件

文件是什么

变量是把数据保存到内存中。如果重启程序或者主机重启,内存中的数据就会丢失

要想能让数据被持久化存储,就可以把数据存储到硬盘中,也就是在文件中保存。

电影->mp4文件

歌曲->mp3文件

图片->jpg

文本->txt

表格->xlsx

存储器分为内存和外村,所谓变量就是在内存中,硬盘是外存,文件就是在硬盘中

  1. 内存的空间更小,硬盘空间更大
  2. 内存访问更快,硬盘访问更慢
  3. 内存成本更贵,硬盘成本更便宜
  4. 内存的数据已丢失,硬盘的数据持久化存储
  5. 硬盘上存储的数据就是以文件的形式来组织的

文件操作

要使用文件,主要是通过文件来保存数据,并且在后续把保存的数据读取出来,但是要想读写文件,需要先"“打开文件”,读写完毕之后还要"关闭文件""。

1. 打开文件

使用内建函数open打开—个文件。

f = open( "d:/test.txt ", 'r')

第一个参数是—个字符串,表示要打开的文件路径,第二个参数是一个字符串,表示打开方式。其中r表示按照读方式打开。w表示按照写方式打开。a表示追加写方式打开。如果打开文件成功,返回一个文件对象,后续的读写文件操作都是围绕这个文件对象展开。如果打开文件失败(比如路径指定的文件不存在),就会抛出异常。

2. 关闭文件

使用close方法关闭已经打开的文件

f = open( "d:/test.txt ", 'r')
f.close()

文件在打开完之后,使用完了之后,也就一定要关闭!打开文件,其实是在申请一定的系统资源,不使用文件的时候,就应该及时释放,否则会造成文件资源泄漏。

python有一个重要的机制,垃圾回收机制,自动的把不使用的变量给进行释放。

虽然 Python给了我们一个后手,让我们一定程度的避免上述问题,但是也不能完全依赖,自动释放机制~~因为自动释放不一定及时,因此还是要尽量手动释放,万无一失。

3. 写文件
  1. 直接写方式打开
f = open( "d:/test.txt ", 'w')
#使用write来实现写文件操作,打开文件时需要以写方式打开
f.write("hello")
f.close()
image-20230203225121171
  1. 追加写方式打开
f = open( "d:/test.txt ", 'w')
#使用write来实现写文件操作,打开文件时需要以写方式打开
f.close()
image-20230203225206024

如果是使用w方式打开,会清空掉文件原有的内容!!!如果是使用a方式打开,则不会清空,写的内容会加在原有内容的末尾。

f = open( "d:/test.txt ", 'a')
#使用write来实现写文件操作,打开文件时需要以写方式打开
f.write("hello")
f.close()
image-20230203225445773
4. 读文件
  • 读文件内容需要使用’r’的方式打开文件
  • 使用read方法完成读操作,参数表示"读取几个字符"
f = open("d:/test.txt", 'r')
result = f.read(2)
print(result)
f.close()
image-20230204094130450

如果文件内容是中文,读取时可能会报错,要保证文件的编码方式和代码中的打开文件的编码方式相同,所以我们可以这样:

f = open("d:/test.txt", 'r',encoding='utf8')
result = f.read(2)
print(result)
f.close()

在实际开发中,最常见的需求是按行来读取

f = open("d:/test.txt", 'r',encoding='utf8')
for line in f:
	print(f'line = {line}')
f.close()
image-20230204095415338

我们发现多了空行,这是因为本来读到的文件内容(这一行末尾就带有\n),此处使用print来打印,又会自动加一个换行符

可以给print多设定个参数,不自动加换行:

print(f'line = {line}', end='')

end参数表示每次打印之后要在末尾加个啥,默认是\n。

image-20230204095836731

还可以使用readlines方法直接把整个文件所有内容都读出来,按照行组织到一个列表里。

f = open("d:/test.txt", 'r',encoding='utf8')
content = f.readlines()
print(content)
f.close()
image-20230204100255737

上下文管理器

打开文件之后,是容易忘记关闭的,Python提供了上下文管理器,来帮助程序猿自动关闭文件:

  • 使用with语句打开文件。

  • 当with 内部的代码块执行完毕后,就会自动调用关闭方法。

有些情况还是非常容易遗漏close的,防不胜防

def func():
    f = open('d:/test.txt', 'r', encoding=utf8)
    f.close()

有人说,我直接在写open时,就写close,就不会忘记close了,但是万一中间有条件判断,函数返回,可能就执行不到close了。使用上下文管理器,就能解决这个问题:

def func():
    with open('d:/test.txt', 'r', encoding='utf8') as f:
        #进行文件处理逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
		if cond:
            return
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        #代码逻辑
        if cond:
            return
        
    

不管有多少个条件,多少个return都没关系了,都不用写close了,当with对应的代码块执行结束,就会自动的执行f的close。

Python通过模块来体现"库",库就是别人已经写好了的代码,可以让我们直接拿来用。
一个编程语言能不能流行起来,—方面取决于语法是否简单方便容易学习,一方面取决于生态是否完备。所谓的"生态”指的就是语言是否有足够丰富的库,来应对各种各样的场景。实际开发中,也并非所有的代码都自己手写,而是要充分利用现成的库,简化开发过程。
按照库的来源,可以大致分成两大类:

  • 标准库: Python自带的库,只要安装了Python就可以直接使用。

  • 第三方库:其他人实现的库.要想使用,需要额外安装

    咱们自己也可以实现"第三方库"发布出去,交给别人来使用。

标准库

认识标准库

Python自带的库,Python自身内置了非常丰富的库。
在Python官方文档上可以看到这些库的内容:https://docs.python.org/3.10/library/index.html

简单来说,主要是这些部分:

  • 内置函数(如print, input 等)
  • 内置类型(针对 int, str, bool, list, dict等类型内置的操作)
  • 文本处理
  • 时间日期
  • 数学计算
  • 文件目录
  • 数据存储(操作数据库,数据序列化等)

第三方库

认识第三方库

第三方库就是别人已经实现好了的库,我们可以拿过来直接使用。虽然标准库已经很强大了,但是终究是有限的。而第三方库可以视为是集合了全世界Python程序猿的智慧,可以说是几乎无穷无尽。问题来了,当我们遇到一个需求场景的时候,如何知道,该使用哪个第三方库呢?
就需要用到百度,谷歌等浏览器了。

当我们确定了该使用哪个第三方库之后,就可以使用pip来安装第三方库了.

使用pip

pip 是 Python 内置的包管理器。

所谓包管理器就类似于我们平时使用的手机 app 应用商店一样。
第三方库有很多,是不同的人不同的组织实现的,为了方便大家整理, Python官方提供了一个网站PyPl PyPI · The Python Package Index,来收集第三方库,其他大佬写好的第三方库也会申请上传到 PyPl上。
这个时候就可以方便的使用pip工具来下载 PyPI上的库了。

pip在我们安装Python 的时候就已经内置了,无需额外安装,pip是一个可执行程序,就在 Python的安装目录中。

生成二维码

二维码本质上就是一段字符串,我们可以把任意的字符串,制作成一个二维码图片,生活中使用的二维码,更多的是一个URL

使用第三方库qrcode进行生成二维码

安装qrcode:

pip install qrcode[pil]
import qrcode
img = qrcode.make('https://blog.csdn.net/attemptendeavor?spm=1000.2115.3001.5343')
img.save("some_file.png")

实现文件查找工具

测试理解:

inputPath = input("请输入要搜索的路径: ")
pattern = input("请输入要搜索的关键词: ")
for dirpath, dirname, filenames in os.walk(inputPath)
	print("----------------------------")
	print(f'dirpath = {dirpath}')
	print('dirnames:')
    for name in dirnames:
        print(name)
	print('filenames:')
    for name in filenames:
        print(name)

dirpath表示遍历到当前位置对应的路径是啥

dirname表示当前目录下,都有哪些目录,是一个列表,可以包含多个目录名

filenames表示当前目录下,都有哪些文件名,是一个列表,可以包含多个文件名

os.walk每次调用都能自动的去针对子目录进行递归的操作,只需要使用上述循环就可以把所有的路径都获取出来。

实现文件以及目录查找工具

import os

inputPath = input("请输入要搜索的路径: ")
pattern = input("请输入要搜索的关键词: ")
for dirpath, dirnames, filenames in os.walk(inputPath):
	# 目录名 
    for name in dirnames:
        if pattern in name:
            print(f"{dirpath}/{name}")
	# 文件名
    for name in filenames:
        if pattern in name:
            print(f"{dirpath}/{name}")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小赵小赵福星高照~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值