str.center(25,‘-‘)和“{:-^25}“.format(“开始执行“)的区别
"{:-^25}".format("开始执行")
首先,让我们理解这两种方法的工作原理:
-
center
方法:这个方法会将字符串居中,并在两边填充指定的字符,直到总长度达到指定的宽度。如果字符串本身的长度超过了指定的宽度,它将不会被截断,而是保持原样。 -
format
方法:这个方法使用格式化字符串来生成字符串。{:-^25}
中的-^
表示使用-
字符填充,并且字符串居中对齐。
现在,让我们看看为什么这两个输出会有差异:
print("开始执行".center(25,'-')) print("{:-^25}".format("开始执行"))
- 第一个输出使用了
center
方法,生成的字符串总长度是25,其中"开始执行"被居中对齐,两边填充了-
字符。 - 第二个输出使用了
format
方法,生成的字符串总长度也是25,但这里的^
符号表示字符串居中对齐,并且两边填充了-
字符。
问题在于,center
方法和format
方法在处理宽度时的行为略有不同。具体来说:
center
方法在填充字符时,会将字符串居中,但不会改变字符串本身的长度。因此,如果字符串长度小于指定宽度,它会在两边填充字符,直到达到指定宽度。format
方法在生成字符串时,会确保生成的字符串总长度恰好等于指定宽度。如果字符串本身的长度超过了指定宽度,它会被截断。
因此,当你的字符串长度小于指定宽度时,这两种方法会产生不同的输出。在你的示例中,"开始执行"的长度为5个字符,加上两边的填充字符,总长度为25。两种方法都能正确地生成居中对齐的字符串。
如果你希望这两种方法生成完全相同的输出,你可以确保字符串本身的长度加上填充字符的总长度等于指定的宽度。例如:
print("开始执行".center(30,'-')) print("{:-^30}".format("开始执行"))
这样,两种方法都会生成一个宽度为30的字符串,其中"开始执行"被居中对齐,两边填充了-
字符。
注意end=""
mport time
scale=50
print("执行开始".center(50//2,'-'))
start=time.perf_counter()
for i in range(scale+1):
a="*"*i
b="."*(scale-i)
c=(i/scale)*100
dur=time.perf_counter()-start
print("\r{:3.0f}%[{}->{}]{:.2f}".format(c,a,b,dur),end="")
time.sleep(0.1)
print("\n"+"执行结束".center(50//2,'-'))
这段代码是使用 Python 编写的,它模拟了一个进度条的显示过程。以下是代码的逐行解释:
import time
:导入 Python 的time
模块,用于获取时间相关的功能。scale=50
:定义一个变量scale
,其值为 50,表示进度条的总长度。print("执行开始".center(50//2,'-'))
:打印一个以“执行开始”为中心的字符串,并用“-”字符填充剩余空间,使其宽度为 50 个字符。start=time.perf_counter()
:获取当前时间的高性能计数器的值,并将其存储在变量start
中,用于后续计算经过的时间。for i in range(scale+1):
:开始一个循环,从 0 到scale
(这里是 50),每次循环增加 1。a="*"*i
:生成一个由i
个星号组成的字符串,表示进度条的当前完成部分。b="."*(scale-i)
:生成一个由scale-i
个点号组成的字符串,表示进度条的未完成部分。c=(i/scale)*100
:计算当前进度的百分比。dur=time.perf_counter()-start
:计算从开始到现在经过的时间,并将其存储在变量dur
中。print("\r{:3.0f}%[{}->{}]{:.2f}".format(c,a,b,dur),end="")
:打印当前进度的百分比和进度条,使用\r
(回车符)使打印位置回到行首,以便在同一行上更新进度条。格式化字符串中的{:3.0f}%
表示整数百分比,[{}->{}]
表示进度条的当前状态,{:.2f}
表示经过的时间(保留两位小数)。time.sleep(0.1)
:暂停 0.1 秒,以便在下一次循环之前显示当前的进度。print("\n"+"执行结束".center(50//2,'-'))
:在进度条完成后,打印一个换行符和一个以“执行结束”为中心的字符串,并用“-”字符填充剩余空间。
整体上,这段代码模拟了一个进度条的显示过程,从 0% 到 100%,每 0.1 秒更新一次进度条,并显示经过的时间。
为何要打印换行符?
在这段代码中若去掉换行符程序结果为
-----------执行开始----------
100%[**************************************************->]5.02-----------执行结束----------
这是因为在循环退出的输出语句带有一个end=“”
这会使得之后的一条print输出语句打印在其之后(两语句之间的填充内容取决于end=“”中引号引起来的东西。使用单引号也可)
为何要使用sleep函数?
在这段代码中,time.sleep(0.1)
的使用有几个重要的原因:
-
显示效果:
- 这是为了让进度条的更新变得可见。由于进度条每 0.1 秒更新一次,这样可以让用户看到进度条逐渐增加的效果,使得进度条的动画效果更明显,从而在视觉上提供了直观的进展反馈。
-
控制执行速度:
- 如果没有
sleep
函数,程序可能会立即运行完,这样进度条的变化就会非常快,几乎瞬间完成,用户无法看到进度的逐步变化。
- 如果没有
-
提高用户体验:
- 用户在执行一些需要时间等待的任务时,一个动态的进度条可以让用户了解到程序正在运行,而不是卡住了或者没有任何响应。
-
模拟行为:
- 在开发过程中,有时候需要模拟某些操作的执行时间,通过
sleep
可以模拟出这种延时效果。
- 在开发过程中,有时候需要模拟某些操作的执行时间,通过
-
避免过载:
- 如果是在一个多任务或多线程的环境中,避免一个任务过快完成并消耗过多的 CPU 资源,可以通过
sleep
来降低 CPU 的使用率,给予其他任务或线程更多处理时间。
- 如果是在一个多任务或多线程的环境中,避免一个任务过快完成并消耗过多的 CPU 资源,可以通过
-
调试方便:
- 调试程序时,
sleep
函数可以让开发者更容易观察程序的运行状态,因为它使得程序的执行过程变得更慢,更容易跟踪。
- 调试程序时,
简而言之,sleep
函数在这类进度显示代码中扮演着重要的角色,它控制着显示更新的频率,使得显示效果和用户体验都更好。此外,它还可以用来模拟或控制程序执行的速度,方便开发和调试。
sleep函数为何置于该位置?
在这段代码中,time.sleep(0.1)
被放置在循环体内部,具体位置是在打印进度条信息之后。这样做有几个主要原因:
-
控制进度更新频率:
- 通过在每次打印进度信息后立即调用
sleep
函数,可以确保每次更新进度条之间的时间间隔是固定的。这样可以使得进度条的更新看起来是连续且均匀的。
- 通过在每次打印进度信息后立即调用
-
避免过快完成:
- 如果
sleep
函数被放置在循环之前或循环之外,那么整个循环可能会在瞬间完成,用户几乎看不到进度条的变化。通过在循环体内部调用sleep
,每次循环都会暂停 0.1 秒,给用户足够的时间看到进度条的变化。
- 如果
-
保持同步:
- 将
sleep
函数放在循环体内部可以确保每次循环都执行一次sleep
,从而保持进度条的更新与时间的同步。这样可以避免因程序运行速度过快而导致进度条显示不准确。
- 将
-
减少资源消耗:
- 将
sleep
函数放在循环体内部可以避免在循环开始前就占用大量 CPU 资源。如果sleep
被放在循环开始前,程序可能会在循环开始前就占用大量资源,而实际上这些资源在循环执行过程中是不需要的。
- 将
-
易于调试:
- 当程序需要调试时,将
sleep
函数放在循环体内部可以使得调试过程更加直观。开发者可以更容易地观察到每次循环的执行情况和进度条的变化。
- 当程序需要调试时,将
-
防止程序过快执行导致的意外:
- 在某些情况下,程序的执行速度过快可能会引发一些意外的行为,例如在某些系统中可能会触发过载保护机制。通过在循环体内部添加
sleep
,可以避免这种情况的发生。
- 在某些情况下,程序的执行速度过快可能会引发一些意外的行为,例如在某些系统中可能会触发过载保护机制。通过在循环体内部添加
简而言之,是为了使输出内容更好的为用户所感知。
环境变量配置查找顺序
当你在命令行中输入 python
并按下回车时,操作系统会尝试找到并执行名为 python
的可执行文件。这个过程并不是因为 python
这个名字与某个特定地址绑定,而是因为操作系统有一个环境变量叫做 PATH
,它定义了操作系统在哪些目录中搜索可执行文件。
这里是详细步骤:
-
环境变量PATH:当你在命令行中输入一个命令,比如
python
,操作系统会查看PATH
环境变量中列出的目录。 -
搜索顺序:
PATH
环境变量包含一系列以分号分隔的目录路径。操作系统会按照这个列表的顺序,从左到右搜索每个目录。 -
可执行文件:每个目录中可能包含多个可执行文件。当操作系统在
PATH
指定的目录中找到名为python
的可执行文件时,它就会执行这个文件。 -
Python解释器:如果
PATH
环境变量中包含了Python安装的路径,比如D:\Python32
,那么操作系统会在该路径下查找名为python.exe
的文件(在Windows系统中)。如果找到了,就会执行这个Python解释器。 -
版本问题:有时候,系统中可能安装了多个版本的Python,或者同时安装了Python 2和Python 3。在这种情况下,
PATH
环境变量中Python路径的顺序会影响哪个版本的Python被调用。通常,我们希望调用最新版本的Python,所以可能需要调整PATH
环境变量中的路径顺序。 -
别名和绑定:在某些情况下,用户可能会在他们的shell配置文件中设置别名,将
python
命令映射到特定版本的Python解释器。但这并不是操作系统级别的绑定,而是用户级别的配置。
总之,python
这个名字本身并不与任何地址绑定,而是 PATH
环境变量告诉操作系统在哪里寻找名为 python
的可执行文件。
如果我在该目录中加入一个名字为python但其实是C++的可执行文件,且其顺序在真正的python之前
如果你在 PATH
环境变量中的某个目录下创建了一个名为 python
的可执行文件,并且这个目录的顺序在真正的 Python 解释器路径之前,当你在命令行中输入 python
时,操作系统将会首先在这个目录中查找名为 python
的可执行文件。如果找到了,它将执行这个文件,而不是 Python 解释器。
这可能会导致以下情况:
-
执行错误的程序:如果该
python
可执行文件实际上是用 C++ 编写的程序,那么当你输入python
时,C++ 程序将被执行,而不是 Python 解释器。 -
功能冲突:如果 C++ 程序的输出或行为与 Python 解释器相似,用户可能会混淆,不知道为什么会得到预期之外的结果。
-
安全风险:如果这个 C++ 程序是恶意的,它可能会执行不安全的操作,比如访问或修改敏感数据。
-
环境混乱:这可能会导致开发环境混乱,因为其他依赖于 Python 解释器的工具和脚本可能无法正常工作。
为了避免这种情况,你应该确保:
PATH
环境变量中的目录顺序是有意义的,通常将 Python 解释器的路径放在前面。- 不要在
PATH
中包含可能与常用命令冲突的可执行文件。 - 保持你的开发环境的清洁和有序,避免不必要的混乱。
如果你需要运行特定的 C++ 程序,你可以给它一个独特的名称,或者在需要时使用完整路径来调用它,而不是使用可能与系统命令冲突的名称。
语句很长该怎么办?
Python 通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠 \ 来实现多行语句,例如:
total = item_one + \ item_two + \ item_three
在 [], {}, 或 () 中的多行语句,不需要使用反斜杠 \,例如:
total = ['item_one', 'item_two', 'item_three', 'item_four', 'item_five']
反斜杠(\)可以作为续行符,表示下一行是上一行的延续。
命令行参数
很多程序可以执行一些操作来查看一些基本信息,Python可以使用-h参数查看各参数帮助信息:
$ python -h usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ... Options and arguments (and corresponding environment variables): -c cmd : program passed in as string (terminates option list) -d : debug output from parser (also PYTHONDEBUG=x) -E : ignore environment variables (such as PYTHONPATH) -h : print this help message and exit [ etc. ]
注:输入python -h(中间有空格)
为什么True==1是True而True is 1是False?
在 Python 中,True
和 1
相等是 True
的原因是因为 Python 允许布尔值和整数之间的隐式转换。在 Python 中,布尔类型 True
和 False
可以被视为整数 1
和 0
。因此,当比较 True
和 1
时,Python 将它们视为相等的,因为它们在数值上是相同的。
然而,True is 1
和 True == 1
之间的区别在于它们使用的运算符:
请注意,使用 del
语句删除对象后,该对象将不再存在,任何尝试访问它的操作都会引发错误(例如 NameError
)。此外,del
只能删除对象,不能删除对象的引用。如果一个对象有多个引用,使用 del
删除其中一个引用不会影响其他引用。
-
==
是等号运算符,它用于比较两个值是否相等。在这个上下文中,它比较的是布尔值True
和整数1
的值,它们在数值上是相等的,所以结果是True
。 -
is
是身份运算符,它用于比较两个对象是否是同一个对象。在这个上下文中,True
和1
虽然在数值上是相同的,但它们是两个不同的对象:True
是布尔类型,而1
是整数类型。因此,True is 1
的结果是False
,因为它们不是同一个对象。 -
del函数
-
del
语句是 Python 语言中用来删除对象的关键字。它可以直接删除列表、字典、集合、元组等数据结构中的元素,或者删除变量本身。下面是一些del
语句的基本用法: -
删除单个变量:
python
del var
-
删除列表中的元素:
- 删除特定索引的元素:
python
del list_name[index]
- 删除列表中的切片:
python
del list_name[start:end:step]
- 删除特定索引的元素:
-
删除字典中的键值对:
python
del dict_name[key]
-
删除集合中的元素:
- 由于集合是无序的,通常你不能指定删除哪个元素,但可以删除整个集合或清空集合:
python
del set_name # 删除整个集合 set_name.clear() # 清空集合,但不删除集合本身
- 由于集合是无序的,通常你不能指定删除哪个元素,但可以删除整个集合或清空集合:
-
删除元组中的元素(元组是不可变数据结构,不能直接删除其中的元素,但可以删除整个元组或使用切片删除部分元素,然后重新赋值):
python
del tuple_name # 删除整个元组
-
删除多个变量:
python
del var1, var2, var3
-
删除对象的属性(如果对象支持
__delattr__
方法):python
del object.name
-
使用
del
语句删除对象后,该对象将不再存在,任何尝试访问它的操作都会引发错误(例如NameError
)。此外,del
只能删除对象,不能删除对象的引用。如果一个对象有多个引用,使用del
删除其中一个引用不会影响其他引用。 -
a = 1;b = 2 del a,b print(a) print(b)
运行结果报错,a和b存在本身被删除了。
NameError Traceback (most recent call last)
Cell In[39], line 3
1 a = 1;b = 2
2 del a,b
----> 3 print(a)
4 print(b)
NameError: name 'a' is not defined
虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。
是的,你说得对。在Python中,tuple
(元组)是一个不可变的序列类型,这意味着一旦元组被创建,你不能修改它的内容,比如添加、删除或更改其中的元素。然而,元组可以包含可变类型的对象,比如列表(list
)、字典(dict
)、集合(set
)等。
例如,你可以创建一个包含列表的元组:
python
my_tuple = (1, [2, 3, 4], 'hello')
尽管你不能改变元组my_tuple
中的元素(比如不能添加或删除元素),但你可以修改列表中的元素,因为列表是可变的。例如:
python
my_tuple[1].append(5) # 向列表中添加一个元素 print(my_tuple) # 输出: (1, [2, 3, 4, 5], 'hello')
在这个例子中,虽然my_tuple
的元素没有改变,但列表[2, 3, 4]
的内容被修改了。这种特性使得元组在需要确保数据不被更改时非常有用,同时还能包含和操作可变的数据结构。
创建只有一个元素的元组
需要注意在元素后面添加一个逗号,以区分它是一个元组而不是一个普通的值,这是因为在没有逗号的情况下,Python会将括号解释为数学运算中的括号,而不是元组的表示。
tup1 = () # 空元组
tup2 = (20,) # 一个元素,需要在元素后添加逗号
创建一个集合(set)
注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
创建格式:
在 Python 中,创建一个集合(set)可以通过几种不同的方法。以下是一些常见的方法:
-
使用花括号
{}
创建集合:python
parame = {value01, value02, ...}
这里
value01, value02, ...
需要被替换为实际的值。花括号中的元素会被自动转换为集合,并且集合中的元素是唯一的。 -
使用
set()
函数创建集合:python
parame = set(value)
这里
value
可以是一个列表、元组或其他可迭代对象。使用set()
函数可以将这些可迭代对象转换为集合。
例如:
python
parame = {1, 2, 3, 4} print(parame) # 输出: {1, 2, 3, 4} parame = set([1, 2, 3, 4]) print(parame) # 输出: {1, 2, 3, 4}
集合是无序的,并且其中的元素是唯一的。这意味着集合中不会有重复的元素,并且元素的顺序可能会与输入时的顺序不同。
如果你需要将一个字典的键或值转换为集合,可以使用以下方法:
-
将字典的键转换为集合:
python
sites = {1: "Google", 2: "Runoob", 3: "Wiki"} parame = set(sites.keys()) print(parame) # 输出: {1, 2, 3}
-
将字典的值转换为集合:
python
sites = {1: "Google", 2: "Runoob", 3: "Wiki"} parame = set(sites.values()) print(parame) # 输出: {'Google', 'Runoob', 'Wiki'}
这些方法可以帮助你根据需要创建和管理集合。
set函数的参数要求
在 Python 中,set
函数用于创建一个集合(set)。集合是一个无序的、不包含重复元素的容器。以下是 set
函数的参数要求:
-
参数类型:
set
函数可以接受一个可迭代对象(如列表、元组、字典、另一个集合等)作为参数。如果参数是一个可迭代对象,set
函数会将其转换为一个集合,其中包含该可迭代对象中的唯一元素。 -
参数个数:
set
函数可以接受零个或一个参数。如果没有提供参数,set
函数将创建一个空集合。如果提供了一个参数,该参数必须是可迭代的。 -
参数值:如果提供了参数值,这个值必须是可迭代的。如果提供了不可迭代的值(如整数、浮点数或字符串),将会引发
TypeError
。
以下是一些 set
函数的用法示例:
-
创建一个空集合:
python
my_set = set()
-
从列表创建集合:
python
my_list = [1, 2, 2, 3, 4, 4, 5] my_set = set(my_list) # 结果: {1, 2, 3, 4, 5}
-
从元组创建集合:
python
my_tuple = (1, 2, 2, 3, 4) my_set = set(my_tuple) # 结果: {1, 2, 3, 4}
-
从字典的键或值创建集合:
python
my_dict = {'a': 1, 'b': 2, 'c': 2} keys_set = set(my_dict.keys()) # 结果: {'a', 'b', 'c'} values_set = set(my_dict.values()) # 结果: {1, 2}
-
从另一个集合创建集合(这通常不会改变集合的内容,除非原集合中有重复元素):
python
another_set = {3, 4, 5, 5} my_set = set(another_set) # 结果: {3, 4, 5}
如果尝试将不可迭代的对象作为参数传递给 set
函数,例如:
python
my_set = set(123) # 这将引发 TypeError
将会引发 TypeError
,因为整数 123
不是可迭代的。
'abracadabra' 为什么是可迭代对象,可迭代对象的特征是什么
a = set('abracadabra')
b = set('alacazam')
在 Python 中,几乎所有的序列类型都是可迭代的,包括字符串、列表、元组、字典等。一个对象被认为是可迭代的,如果它实现了 __iter__()
方法或者 __getitem__()
方法。这意味着 Python 可以使用内置的 iter()
函数来获取一个迭代器,进而遍历该对象。
以下是可迭代对象的一些特征:
-
实现了迭代器协议:可迭代对象必须实现
__iter__()
方法,该方法返回一个迭代器。迭代器是一个具有__next__()
方法的对象,用于返回下一个元素,直到所有元素都被返回完毕。 -
支持索引访问:如果可迭代对象还实现了
__getitem__()
方法,那么它可以通过索引来访问元素,这通常适用于序列类型。 -
能够使用 for 循环遍历:可迭代对象可以在
for
循环中使用,因为for
循环内部调用了iter()
和next()
函数。 -
能够使用迭代相关的内置函数:例如
iter()
,next()
,all()
,any()
,sum()
,min()
,max()
等可以与可迭代对象一起使用。 -
能够用于创建其他可迭代对象:例如,可迭代对象可以作为
set
,list
,tuple
,dict
等构造函数的参数,从而创建新的集合类型。
字符串 'abracadabra'
是一个可迭代对象,因为它是一个序列,可以通过索引访问每个字符,并且可以被 for
循环遍历。此外,字符串类型实现了 __iter__()
方法,使得它能够返回一个迭代器,该迭代器按顺序返回字符串中的每个字符。
这里是一个简单的例子,展示如何使用 iter()
函数和 next()
函数来迭代字符串:
python
s = 'abracadabra' iterator = iter(s) # 获取字符串的迭代器 for _ in range(len(s)): # 迭代字符串的长度次 print(next(iterator))
这段代码将按顺序打印出字符串 'abracadabra'
中的每个字符。
序列类型是什么?
在编程中,序列类型(Sequence Type)指的是一种数据结构,它存储了一系列有序的元素,并且可以通过索引来访问这些元素。Python 中的序列类型具有以下共同特征:
-
有序:序列中的元素按照特定的顺序排列,每个元素都有一个位置或索引。
-
可索引:可以通过整数索引来访问序列中的元素。索引通常是从 0 开始的。
-
可迭代:序列类型是可迭代的,意味着你可以使用循环结构(如
for
循环)来遍历序列中的每个元素。 -
元素唯一性:虽然大多数序列类型(如列表和元组)可以包含重复的元素,但有些序列类型(如集合)不允许元素重复。
-
可变与不可变:序列类型可以是可变的或不可变的。不可变序列类型(如元组)一旦创建就不能更改其元素,而可变序列类型(如列表)允许修改其元素。
Python 中的常见序列类型包括:
- 字符串(str):字符的序列,是不可变的。
- 列表(list):可以包含不同类型的元素,是可变的。
- 元组(tuple):类似于列表,但一旦创建就不能更改其元素,是不可变的。
- 字典的键(dict keys):字典的键本身是一个序列,但字典作为整体不是标准的序列类型,因为其元素是键值对。
序列类型在 Python 中非常重要,因为它们提供了一种灵活的方式来处理数据集合,并且支持许多通用的操作,如索引、切片、迭代等。
字典输出
print (tinydict.keys())
: 输出字典tinydict
的所有键,结果是一个键的列表。print (tinydict.values())
: 输出字典tinydict
的所有值,结果是一个值的列表。
哪些数据类型能作为字典的键?
dict={}
dict["one"]="Hello"
dict[[1,2,3]]="World"
print(dict)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[34], line 3
1 dict={}
2 dict["one"]="Hello"
----> 3 dict[[1,2,3]]="World"
4 print(dict)
TypeError: unhashable type: 'list'
这个错误是因为你尝试将一个列表 [1, 2, 3]
作为字典的键。在Python中,字典的键必须是不可变类型,比如整数、浮点数、字符串或元组,而列表是可变类型,因此不能作为字典的键。
如果你想将多个值存储在同一个键下,可以考虑以下几种方法:
-
使用列表作为值: 你可以将一个列表作为字典的值,而不是作为键。
python
dict = {} dict["one"] = [1, 2, 3] print(dict) # 输出:{'one': [1, 2, 3]}
-
使用元组作为键: 如果需要将多个值组合成一个键,可以使用元组,因为元组是不可变类型。
python
dict = {} dict[(1, 2, 3)] = "World" print(dict) # 输出:{(1, 2, 3): 'World'}
-
使用集合存储键: 如果你需要存储多个键,可以使用集合(set),但集合中的元素是无序的。
python
keys = {1, 2, 3} dict = {key: "World" for key in keys} print(dict) # 输出可能是:{1: 'World', 2: 'World', 3: 'World'}
-
使用嵌套字典: 如果每个键需要存储多个值,可以使用嵌套字典。
python
dict = {} dict[1] = {"two": 2, "three": 3} print(dict) # 输出:{1: {'two': 2, 'three': 3}}
选择哪种方法取决于你的具体需求和数据结构。
生成字典方式
-
在Python中,创建字典有几种常见的方式:
-
使用花括号
{}
: 这是创建字典最直接的方式。键和值之间用冒号:
分隔,不同的键值对之间用逗号,
分隔。python
my_dict = {'name': 'Alice', 'age': 25}
-
使用
dict()
构造函数:dict()
函数可以接受一个可迭代对象作为参数,其中每个元素都是一个键值对(通常是元组),或者使用关键字参数来创建字典。python
# 使用可迭代对象 my_dict = dict([('name', 'Alice'), ('age', 25)]) # 使用关键字参数 my_dict = dict(name='Alice', age=25)
每种方式都有其使用场景和优势,你可以根据需要选择最适合的一种。
-
使用字典推导式: 字典推导式是一种简洁的方式,用于根据现有数据创建字典。
python
keys = ['a', 'b', 'c'] values = [1, 2, 3] my_dict = {k: v for k, v in zip(keys, values)}
-
使用
collections.defaultdict
: 如果你需要一个字典,其键在访问时如果不存在就会返回一个默认值,可以使用collections
模块中的defaultdict
类。python
from collections import defaultdict my_dict = defaultdict(lambda: 'default_value') my_dict['key1'] = 'value1'
-
使用
types.MappingProxyType
: 如果你需要一个只读的字典视图,可以使用types.MappingProxyType
。python
my_dict = {'name': 'Alice', 'age': 25} my_readonly_dict = types.MappingProxyType(my_dict)
-
使用
json.loads()
: 如果你有一个JSON格式的字符串,可以使用json.loads()
函数将其转换为字典。python
import json json_str = '{"name": "Alice", "age": 25}' my_dict = json.loads(json_str)
-
使用
ast.literal_eval()
: 如果你有一个可以安全地评估为Python字典的字符串,可以使用ast.literal_eval()
来创建字典。python
import ast dict_str = "{'name': 'Alice', 'age': 25}" my_dict = ast.literal_eval(dict_st)
字典中的位置参数和关键字参数
# 设置关键字参数
numbers2 = dict([('x', 5), ('y', -5)], z=8)
print('numbers2 =',numbers2)
在编程语言中,特别是在Python中,设置关键字参数(也称为关键字参数)是一种向函数传递参数的方式,这种方式允许你明确指定每个参数的名称。这在函数参数较多或者参数顺序不明确的情况下特别有用。
基本语法
在Python中,关键字参数的基本语法如下:
python
函数名(参数名1=值1, 参数名2=值2, ...)
示例
假设有一个函数greet
,它接受两个参数:name
和age
:
python
def greet(name, age): print(f"Hello, {name}! You are {age} years old.")
使用位置参数
你可以通过位置参数调用这个函数:
python
greet("Alice", 30)
使用关键字参数
你也可以通过关键字参数调用这个函数,这样可以更清楚地看到每个参数的名称:
python
greet(name="Alice", age=30)
混合使用位置参数和关键字参数
你甚至可以混合使用位置参数和关键字参数:
python
greet("Alice", age=30)
或者
python
greet(age=30, name="Alice")
字典中的关键字参数
在创建字典时,也可以使用关键字参数:
python
my_dict = dict(name="Alice", age=30) print(my_dict) # 输出: {'name': 'Alice', 'age': 30}
映射关系(map)
numbers2 = {'x': 4, 'y': 5}
print('numbers2 =',numbers2)
映射类型(Mapping Types)是一种关联式的容器类型,它存储了对象与对象之间的映射关系。
repr() 函数使用
repr()
函数在 Python 中用于获取对象的字符串表示,它通常用于调试。repr()
函数会返回一个字符串,这个字符串可以被 eval()
函数用来重新构造对象。在大多数情况下,如果对象是一个字符串,repr()
会返回一个带有额外引号的字符串,以区分字符串的开始和结束。例如:
python
s = 'hello' print(repr(s)) # 输出:'hello'
然而,对于非字符串类型的对象,repr()
会返回一个能够表达该对象的字符串,但不一定包含引号。例如:
python
l = [1, 2, 3] print(repr(l)) # 输出:[1, 2, 3]
repr()
函数的输出通常用于生成一个可以被 eval()
执行的字符串,而不仅仅是简单地在对象外添加一对引号。
python中的可变类型和不可变类型
不可变类型
不可变类型指的是一旦创建,其内容不能被修改的数据类型。常见的不可变类型包括:
- 整数 (
int
) - 浮点数 (
float
) - 字符串 (
str
) - 元组 (
tuple
)
可变类型
可变类型指的是内容可以被修改的数据类型。常见的可变类型包括:
- 列表 (
list
) - 字典 (
dict
) - 集合 (
set
)
特性说明
-
不可变类型:
- 整数和浮点数:一旦赋值,其数值不能改变。
- 字符串:字符串一旦创建,其内容不能被修改,但可以重新赋值或通过字符串方法生成新字符串。
- 元组:元组一旦创建,其元素不能被修改,但可以重新赋值或通过元组解包和重新组合生成新元组。
-
可变类型:
- 列表:可以增加、删除或修改元素。
- 字典:可以添加、删除或修改键值对。
- 集合:可以添加或删除元素,但不能修改元素。
示例
-
不可变类型示例:
python
a = 10 a += 1 # 这实际上是创建了一个新的整数对象,而不是修改原来的a b = "hello" b += " world" # 这会创建一个新的字符串对象,而不是修改原来的b c = (1, 2, 3) c[1] = 20 # 这会引发TypeError,因为元组是不可变的
-
可变类型示例:
python
d = [1, 2, 3] d[1] = 20 # 这会修改列表中的元素 e = {"name": "Alice", "age": 25} e["age"] = 26 # 这会修改字典中的值 f = {1, 2, 3} f.add(4) # 这会向集合中添加一个新元素
海象运算符
# 传统写法
n = 10
if n > 5:
print(n)
# 使用海象运算符
if (n := 10) > 5:
print(n)
在 Python 3.8 及更高版本中,引入了一种新的语法特性,称为"海象运算符"(Walrus Operator),它使用 := 符号。这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。
is运算符和id()
a = [1,2,3,4]
b = a
c = [1,2,3,4]
print(b is c)
print(id(b))
print(id(c))
这边输出结果表明b和c不为同一对象
a = 1
b = a
c = 1
print(b is c)
print(id(b))
print(id(c))
这边输出表明b和c为同一对象
在Python中,整数是不可变的(immutable),这意味着它们不能被修改。当您创建一个整数并将其赋值给多个变量时,Python的整数对象缓存机制会起作用。这个机制会缓存一系列小整数(通常是-5到256之间),如果创建的整数在这个范围内,Python会重用这些已经存在的整数对象。
其他类型可以自己去试试
数学函数
不需要import math的只有:abs();max();min();round( x [, n] )
有内置方法的: pow(x, y[, z])
python格式化输出%g和%G
在Python中,%g
是一种格式化字符串的格式说明符,用于生成浮点数的字符串表示。它在格式化时会根据数值的大小自动选择使用科学记数法还是固定小数点记数法。
具体来说:
- 当数值的绝对值小于
0.0001
或大于等于1e+4
时,使用科学记数法(如1.23e+04
)。 - 当数值的绝对值在
0.0001
到1e+4
之间时,使用固定小数点记数法(如1234.56
)。
例如:
python
print("%.2g", 123.456) # 输出: 123.5 print("%.2g", 0.00012345) # 输出: 1.23e-4
这里的%.2g
表示:
%
表示开始一个格式化指令。.2
表示小数点后保留两位数字。g
表示使用%g
格式化说明符。
f-string函数
name = 'World'
f'Hello {name}'
结果'Hello World'
name = 'World'
f'Hello name'
结果'Hello name'
a = 1
b = 2
f'1 + 3'
结果'1+3'
a = 1
b = 2
f'{1 + 3}'
结果'4'
a = 1
b = 2
f'{1 + 3 = }'
结果'1 + 3 = 4'
当没有{ }时,就按照' '中的内容打印且会带上单引号,有{ }时会对{ }中内容进行运算再输出结果。
注:可以使用 = 符号来拼接运算表达式与结果,详见最后一段代码与倒数第二段代码比较。
直接赋值与copy的区别
#!/usr/bin/python
# -*- coding: UTF-8 -*-
dict1 = {'user':'runoob','num':[1,2,3]}
dict2 = dict1 # 浅拷贝: 引用对象
dict3 = dict1.copy() # 浅拷贝:深拷贝父对象(一级目录),子对象(二级目录)不拷贝,子对象是引用
# 修改 data 数据
dict1['user']='root'
dict1['num'].remove(1)
# 输出结果
print(dict1)
print(dict2)
print(dict3)
实例中 dict2 其实是 dict1 的引用(别名),所以输出结果都是一致的,dict3 父对象进行了深拷贝,不会随dict1 修改而修改,子对象是浅拷贝所以随 dict1 的修改而修改。
list1 = [1,2,3,4]
list2 = list1
list1 is list2
#True
list1 = [1,2,3,4]
list2 = list1.copy
list1 is list2
#False
dict2与dict1是同一对象,dict3与dict1不为同一对象
生成推导式
比如列表推导式,列表推导式的基本语法:
[expression for item in iterable if condition]
eg:
squares = [x**2 for x in range(10)]
print(squares) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Python中的列表推导式虽然以“列表”命名,但它实际上可以生成多种类型的数据结构,而不仅仅是列表。以下是一些常见的数据类型,列表推导式可以用于生成它们:
-
列表(List):
- 这是最常见的使用场景,生成一个元素列表。
python
[x**2 for x in range(10)]
-
元组(Tuple):
- 通过使用圆括号,可以生成一个元组列表。
python
((x, x**2) for x in range(5))
-
集合(Set):
- 使用花括号可以生成一个不包含重复元素的集合。
python
{x**2 for x in range(10)}
-
字典(Dictionary):
- 通过指定键和值,可以生成一个字典。
python
{x: x**2 for x in range(5)}
-
字符串(String):
- 虽然不能直接生成字符串,但可以通过连接生成字符串。
python
''.join([str(x) for x in range(10)])
-
其他可迭代对象:
- 任何可迭代对象都可以作为列表推导式的输入,生成新的可迭代对象。
-
生成元组列表:
python
tuples = [(x, x**2) for x in range(5)] print(tuples) # 输出: [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16)]
-
生成集合:
python
unique_squares = {x**2 for x in range(10)} print(unique_squares) # 输出: {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
-
生成字典:
python
squares_dict = {x: x**2 for x in range(5)} print(squares_dict) # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
-
生成字符串:
python
numbers_str = ''.join([str(x) for x in range(5)]) print(numbers_str) # 输出: '01234'
列表推导式提供了一种非常灵活和强大的方式来生成各种类型的数据结构,使得代码更加简洁和易于理解。不过,当生成的数据结构复杂或逻辑较为复杂时,可能需要考虑使用传统的循环语句来提高代码的可读性。
python中的pass语句有什么作用
在Python中,pass
是一个关键字,它表示一个空的代码块。它通常用在以下几种情况:
-
占位符:当你正在编写代码,但还没有时间或想法来实现某个部分时,你可以使用
pass
作为占位符。这样,代码仍然可以运行,但不会执行任何操作。 -
结构要求:在Python中,某些结构需要至少有一个语句,即使该语句实际上不执行任何操作。例如,在
if
、for
、while
等语句中,如果没有else
或else:
子句,就必须有一个pass
来满足语法要求。 -
避免错误:在某些情况下,你可能需要避免语法错误,但又不想立即实现代码逻辑,
pass
可以作为临时解决方案。 -
创建框架:在开发大型项目时,
pass
可以用来快速创建代码框架,之后再填充具体的实现细节。
下面是一个简单的 pass
使用示例:
python
if some_condition: pass # 这里暂时不执行任何操作 else: do_something()
在这个例子中,如果 some_condition
为真,程序将不会执行任何操作,因为 pass
表示空操作。如果 some_condition
为假,程序将执行 else
子句中的 do_something()
函数。
元组赋值语法
a, b = b, a+b
在 Python 中,a, b = b, a+b
是一种称为元组赋值(tuple unpacking)的语法。这种语法允许你同时交换两个或多个变量的值。具体来说,这行代码的工作原理如下:
b, a+b
形成了一个元组,其中包含两个元素:b
和a+b
。a, b
是两个变量,它们将被赋予元组中的相应值。- 首先,计算
a+b
的值。 - 然后,将元组的第一个元素(即原来的
b
值)赋值给变量a
。 - 接着,将元组的第二个元素(即计算出的
a+b
)赋值给变量b
。
这种赋值方式在交换两个变量的值时非常有用,因为它不需要使用临时变量,代码更加简洁。
实例变量与局部变量
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
这之中self.a是实例变量,是类实例的一部分以在类的任何方法中访问和修改。
实例变量和局部变量是编程中两个非常重要的概念,它们在作用域、生命周期、访问权限和使用场景上有着明显的不同。以下是它们之间的主要区别:
-
定义的位置:
- 实例变量: 定义在类中,但在类的任何方法之外。它们是类的属性,与类的实例相关联。
- 局部变量: 定义在函数、方法或代码块内部。它们只在该函数、方法或代码块的作用域内可见。
-
生命周期:
- 实例变量: 与对象的生命周期相同。一旦创建了类的实例,实例变量就会被初始化,并一直存在直到对象被销毁。
- 局部变量: 仅在函数或方法的执行期间存在。当函数或方法执行完毕后,局部变量的生命周期结束。
-
作用域:
- 实例变量: 可以在类的所有方法中访问,它们是共享的。
- 局部变量: 只能在定义它们的函数或方法内部访问。
-
数据共享:
- 实例变量: 每个实例都有自己的实例变量副本,不同的实例之间不共享这些变量。
- 局部变量: 在函数的不同调用之间不共享,每个调用都有自己的局部变量副本。
-
封装性:
- 实例变量: 有助于封装数据,因为它们可以被类的方法所控制,通常通过 getter 和 setter 方法来访问和修改。
- 局部变量: 不涉及封装,因为它们仅在局部作用域内可见。
-
使用场景:
- 实例变量: 用于存储对象的状态信息,比如用户的姓名、年龄等。
- 局部变量: 用于存储函数或方法执行过程中需要的临时数据。
-
内存使用:
- 实例变量: 存储在堆内存中,每个实例都有自己的副本。
- 局部变量: 通常存储在栈内存中,调用结束后自动释放。
-
可见性:
- 实例变量: 可以通过公共方法(如 getter 和 setter)来控制其可见性。
- 局部变量: 对外部是不可见的,它们隐藏了实现细节。
理解这些区别对于编写清晰、可维护的代码非常重要。实例变量支持对象的状态管理,而局部变量则有助于实现函数或方法的逻辑,同时保持变量的作用域限制在最小必要范围内。
条件语句和条件表达式的区别
条件语句主要用于控制程序的执行流程,根据条件的真假来决定是否执行某个代码块。
条件表达式则是一种更简洁的方式来选择两个值中的一个。它通常用于在单个表达式中进行选择。Python中常用的条件表达式是三元运算符(也称为条件运算符)。
主要区别
-
用途:
- 条件语句用于控制代码块的执行,不返回值。
- 条件表达式用于在表达式中选择一个值,返回值。
-
语法:
- 条件语句使用
if
、elif
、else
关键字。 - 条件表达式使用三元运算符
value_if_true if condition else value_if_false
。
- 条件语句使用
-
简洁性:
- 条件表达式更简洁,适合在需要返回值的场合。
- 条件语句更灵活,适合控制复杂的逻辑流程。
-
可读性:
- 条件表达式在简单情况下更易于阅读和理解。
- 条件语句在处理复杂逻辑时更清晰,易于维护。
-
适用场景:
- 条件表达式通常用于简单的值选择。
- 条件语句用于控制复杂的逻辑流程和代码块的执行。
lambda函数
-
使用逻辑运算符:
python
f = lambda x: x if x > 0 else -x
-
使用多个条件表达式
python
f = lambda x: 'high' if x > 100 else 'low' if x < 50 else 'mid'
-
使用逻辑运算符和条件表达式结合:
python
f = lambda x: 'high' if x > 100 else ('low' if x < 50 else 'mid')
-
使用逻辑运算符实现多条件判断:
python
f = lambda x: 'high' if x > 100 else ('mid' if 50 <= x <= 100 else 'low')
-
使用布尔表达式:
python
f = lambda x: True if x > 0 else False
-
使用条件表达式结合布尔值:
python
f = lambda x: ('high' if x > 100 else 'low') if x > 50 else 'mid'
-
使用函数调用: 如果需要更复杂的逻辑,可以在lambda函数中调用其他函数,但这些函数本身需要是简单的。
python
def check_value(x): if x > 100: return 'high' elif x < 50: return 'low' else: return 'mid' f = lambda x: check_value(x)
-
使用异常处理: 虽然不推荐在lambda表达式中使用异常处理,但技术上是可行的。
python
f = lambda x: 'high' if x > 100 else ('low' if x < 50 else 'mid') # 假设 x 是一个数字
需要注意的是,lambda 函数的表达式必须是一个单一的表达式,不能包含多个语句。因此,复杂的逻辑判断通常不适合在 lambda 函数中实现,而更适合定义为一个完整的函数。
Lambda 函数中的条件表达式(也称为三元运算符)的一般格式是:
结果在前,判定条件在后。
python
lambda 参数: 表达式1 if 条件1 else 表达式2
这里的结构是:
- 表达式1:如果条件1为真时返回的值。
- 条件1:一个布尔表达式。
- 表达式2:如果条件1为假时返回的值。
这种结构使得结果(表达式1或表达式2)在前,判定条件(条件1)在后。这与一些其他编程语言的三元运算符的顺序不同,例如在C语言或Java中,条件在前,结果在后。
例如:
python
result = (lambda x: 'high' if x > 100 else 'low')(50) print(result) # 输出 'low'
在这个例子中:
'high'
是当x > 100
为真时的结果。'low'
是当x > 100
为假时的结果。
lambda函数实际上是创建了一个函数
a=11
b = lambda:'Hello World' if a==11 else 'Bye'
print(b)
#<function <lambda> at 0x0000022362773380>
a=11
b = lambda:'Hello World' if a==11 else 'Bye'
print(b())
#Hello World
当你在Python中使用print
函数打印一个函数对象时,Python不会执行该函数,而是打印出该函数的内存地址表示。在该代码示例中:
python
a = 11 b = lambda: 'Hello World' if a == 11 else 'Bye' print(b)
当运行print(b)
时,实际上是在打印b
这个lambda函数对象本身,而不是调用它。因此,输出显示的是函数对象的内存地址,格式类似于<function <lambda> at 0x0000022362773C40>
,这个地址是函数对象在内存中的位置,每次运行代码时这个地址都可能不同。
如果想要打印b
函数的返回值,你需要调用这个函数,如下所示:
python
print(b())
这样,Python会执行b
函数,并打印出它的返回值,即'Hello World'
。
特别注意lambda函数实际上也是创建了一个函数对象
设置参数的lambda函数:x = lambda a, b : a * b
print(x(5, 6))
lambda后面,冒号之前的就是创建的匿名函数的参数。
popleft()函数
popleft()
是 Python 中 collections.deque
类的一个方法,用于从双端队列(deque)的左侧移除并返回第一个元素。这个方法的名称来源于 "pop" 和 "left" 的组合,意味着从队列的左侧弹出元素。
这里是 popleft()
方法的一些关键点:
-
原子性:
popleft()
是一个原子操作,意味着它不会被线程调度中断,适合用于多线程环境中。 -
时间复杂度:
popleft()
操作的时间复杂度是 O(1),因为它直接访问和修改了队列的头部。 -
异常处理:如果尝试在一个空的
deque
上调用popleft()
,将会抛出IndexError
。 -
使用场景:
popleft()
常用于实现队列或栈的数据结构,特别是当你需要快速从队列的一端添加和移除元素时。
下面是一个使用 popleft()
方法的简单示例:
python
from collections import deque # 创建一个 deque 对象 d = deque() # 向 deque 中添加元素 d.append(1) d.append(2) d.append(3) # 使用 popleft() 方法从左侧移除元素 first_element = d.popleft() # 移除并返回 1 print(first_element) # 输出: 1 # 再次使用 popleft() 方法 second_element = d.popleft() # 移除并返回 2 print(second_element) # 输出: 2 # 查看 deque 的当前状态 print(d) # 输出: deque([3], maxlen=4)
在这个示例中,我们首先创建了一个 deque
对象,然后添加了三个元素。使用 popleft()
方法,我们从左侧移除了前两个元素,并打印了它们。最后,我们打印了 deque
的当前状态,显示只剩下一个元素。
矩阵转置[[row[i] for row in matrix] for i in range(4)]
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],]
[[row[i] for row in matrix] for i in range(4)]
在 Python 中,这段代码定义了一个名为 matrix
的列表,它包含了一个 3x4 的矩阵(一个列表的列表),然后通过列表推导式创建了一个新列表。这个列表推导式使用了两层嵌套。
第一层列表推导式是 [row[i] for row in matrix]
,它遍历 matrix
中的每一行(row
),然后根据索引 i
从每行中取出相应的元素。
第二层列表推导式是 [[row[i] for row in matrix] for i in range(4)]
,它首先遍历索引 i
,从 0 到 3。对于每个索引 i
,它执行第一层列表推导式,得到一个包含 matrix
中第 i
列所有元素的列表。
执行这段代码后,将会进行原始矩阵的转置,即将矩阵的行和列互换。
在 Python 中,列表推导式 [[row[i] for row in matrix] for i in range(4)]
包含两层嵌套的循环。这种结构的执行顺序是从外层到内层。(嵌套循环:和C语言等都相同。eg:for循环)
-
外层循环:首先执行的是外层循环,它遍历
range(4)
。这里的range(4)
生成一个序列[0, 1, 2, 3]
,表示列索引。 -
内层循环:对于外层循环的每个索引
i
,执行内层循环。内层循环遍历matrix
中的每一行(row
),并取出每行中索引为i
的元素。
因此,这个列表推导式的执行顺序是:
- 首先,外层循环选择一个列索引
i
。 - 然后,内层循环遍历
matrix
中的每一行,并取出每行的第i
个元素。
最终,这个列表推导式会生成一个新列表,其中包含了原始矩阵 matrix
的每一列作为一个子列表。
这里是具体的执行过程:
- 当
i = 0
时,内层循环取出matrix
中每一行的第一个元素,形成一个子列表[1, 5, 9]
。 - 当
i = 1
时,内层循环取出matrix
中每一行的第二个元素,形成一个子列表[2, 6, 10]
。 - 当
i = 2
时,内层循环取出matrix
中每一行的第三个元素,形成一个子列表[3, 7, 11]
。 - 当
i = 3
时,内层循环取出matrix
中每一行的第四个元素,形成一个子列表[4, 8, 12]
。
最终生成的列表是:
python
[ [1, 5, 9], # 第一列 [2, 6, 10], # 第二列 [3, 7, 11], # 第三列 [4, 8, 12] # 第四列 ]
这实际上是原始矩阵的转置。
解包操作
>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
>>> for k, v in knights.items():
... print(k, v)
...
gallahad the pure
robin the brave
问题:这边的k,v输入方式是位置参数方式吗?
是的。在Python中,for k, v in knights.items():
这种语法使用了所谓的"解包"(unpacking)操作,它是一种位置参数方式。这意味着在迭代字典的items()
方法返回的元组时,每个元组的第一个元素被赋值给变量k
(代表键),第二个元素被赋值给变量v
(代表值)。
这里的k
和v
是按位置赋值的,它们必须与.items()
方法返回的元组中的元素数量相匹配。如果.items()
返回的元组中有多于或少于两个元素,这将导致一个ValueError
。
例如,如果字典有多个值与同一个键相关联(使用其他数据结构如列表或集合),则需要使用不同的方法来解包这些值。但在这个例子中,每个键都只映射到一个值,所以使用两个变量进行解包是合适的。
解包操作是什么?
解包操作(Unpacking)是Python中的一项特性,它允许你将一个序列(如列表、元组)或者可迭代对象中的元素分配到多个变量中。这种操作通常用于简化代码,使代码更加易读和简洁。
以下是一些解包操作的例子:
-
解包元组:
python
point = (10, 20) x, y = point print(x) # 输出 10 print(y) # 输出 20
-
解包列表:
python
numbers = [1, 2, 3] a, b, c = numbers print(a) # 输出 1 print(b) # 输出 2 print(c) # 输出 3
-
解包字典:
python
person = {'name': 'Alice', 'age': 25} name, age = person.values() print(name) # 输出 Alice print(age) # 输出 25
-
解包任意可迭代对象:
python
colors = ['red', 'green', 'blue'] first, second, third = colors print(first) # 输出 red print(second) # 输出 green print(third) # 输出 blue
-
解包时使用下划线(_)忽略某些值:
python
values = [1, 2, 3, 4, 5] first, *_, last = values print(first) # 输出 1 print(last) # 输出 5
-
解包并赋值给字典:
python
data = {'id': 1, 'name': 'Bob', 'email': 'bob@example.com'} id, name = data.items() # 这里实际上是获取字典的键和值 print(id) # 输出 ('id', 1) print(name) # 输出 ('name', 'Bob')
解包操作在Python中非常有用,特别是在处理函数返回多个值、迭代序列或处理复杂的数据结构时。
enumerate()函数的用法
在序列中遍历时,索引位置和对应值可以使用 enumerate() 函数同时得到
>>> for i, v in enumerate(['tic', 'tac', 'toe']):
... print(i, v)
...
0 tic
1 tac
2 toe
Python 中的 enumerate()
函数是一个非常有用的内置函数,它能够将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列,同时返回元素和它的索引。这在遍历列表时,如果需要知道元素的索引,非常有用。
以下是 enumerate()
函数的基本用法:
python
# 假设我们有一个列表 my_list = ['apple', 'banana', 'cherry'] # 使用enumerate()函数遍历列表 for index, item in enumerate(my_list): print(index, item)
这段代码将输出:
0 apple 1 banana 2 cherry
enumerate()
函数还接受一个可选的起始索引参数,如果你想从非零索引开始计数,可以这样做:
python
for index, item in enumerate(my_list, start=1): print(index, item)
这将输出:
1 apple 2 banana 3 cherry
使用 enumerate()
可以避免使用像下面这样的代码,它使用 range()
来获取索引,这不仅代码更长,而且也更容易出错:
python
for i in range(len(my_list)): print(i, my_list[i])
enumerate()
函数是处理索引和元素的优雅方式,它使代码更加简洁和易于阅读。
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的
x = 'global'
def func():
x = 'local'
print(x) # 打印 'local'
if True:
x = 'if block'
print(x) # 打印 'if block'
func()
print(x) # 打印 'global',因为if块不引入新的作用域
在这个例子中,func
函数引入了局部作用域,而if
块内的x
并没有创建新的作用域,它实际上覆盖了全局变量x
。所以,在if
块外打印x
时,它仍然是全局作用域中的'global'
值
reduce函数
from functools import reduce
list1 = [11, 5, 17, 18, 23]
sum = reduce(lambda x,y:x+y,list1)
print(sum)
reduce
函数在迭代过程中不会将累计值作为第二次迭代的第一项。reduce
函数的工作原理是将序列的第一个元素作为初始的累积值,然后依次将累积值与序列中的下一个元素进行操作。
具体来说,reduce
函数的迭代过程是这样的:
-
第一次迭代:使用序列的第一个元素作为累积值,然后将其与序列中的第二个元素结合,使用提供的函数(在这个例子中是
lambda x, y: x + y
)。 -
第二次迭代:将第一次迭代的结果作为新的累积值,然后将其与序列中的第三个元素结合。
-
后续迭代:这个过程继续进行,每次迭代都将上一次迭代的结果作为累积值,然后与序列中的下一个元素结合,直到遍历完序列中的所有元素。
以列表list1 = [11, 5, 17, 18, 23]
为例,reduce
函数的迭代过程如下:
- 第一次迭代:累积值是
11
(序列的第一个元素),与5
结合,计算11 + 5
得到16
。 - 第二次迭代:新的累积值是
16
,与17
结合,计算16 + 17
得到33
。 - 第三次迭代:新的累积值是
33
,与18
结合,计算33 + 18
得到51
。 - 第四次迭代:新的累积值是
51
,与23
结合,计算51 + 23
得到74
。
所以,reduce
函数的累计值是作为每次迭代中的x
参数,而不是序列中的元素。最终,reduce
函数返回的是所有元素累积操作后的最终结果。
sort方法
dict1 = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
# 根据字典的值进行排序
dict1.sort(key=lambda x: x[1], reverse=False) # reverse=False 表示升序,True 表示降序
print(dict1)
输出 :
[('pear', 1), ('banana', 3), ('orange', 2), ('apple', 4)]
这里,dict1.sort()
方法接受两个参数:
key
:一个函数,用于从每个元素中提取一个用于比较的值。在这个例子中,lambda x: x[1]
表示使用字典项的值(即元组的第二项)作为排序的依据。reverse
:一个布尔值,用于指定排序的顺序。如果设置为False
(默认值),则进行升序排序;如果设置为True
,则进行降序排序。
请注意,sort()
方法会改变原字典的顺序,如果你不希望改变原字典,可以先将字典转换为列表,然后对列表进行排序。
插入排序算法实现
def insertionSort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while j >=0 and key < arr[j] :
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
arr = [12, 11, 13, 5, 6]
insertionSort(arr)
print ("排序后的数组:")
for i in range(len(arr)):
print ("%d" %arr[i])
为什么arr[j+1] = key,j+1是key应该在的位置?
在插入排序算法中,arr[j+1] = key
这行代码的执行是基于之前的循环逻辑来确定 key
应该插入的位置的。
-
初始化 j:当
i
从 1 开始遍历时,j
被初始化为i-1
,即当前key
的前一个位置。 -
循环条件:
while j >= 0 and key < arr[j]
这个循环会持续进行,只要j
没有超出数组的起始位置(即j >= 0
),并且key
小于当前遍历到的元素arr[j]
。 -
元素后移:在循环体内部,
arr[j+1] = arr[j]
将arr[j]
的值复制到arr[j+1]
的位置,这样做是为了在已排序的数组部分为key
腾出空间。 -
更新 j:
j -= 1
将j
向前移动一个位置,继续检查key
是否小于新的arr[j]
。 -
找到插入点:当循环结束时,有两种情况:
j < 0
:这意味着key
应该插入到数组的最开始,因为key
小于数组中所有已检查的元素。key >= arr[j]
:这意味着key
找到了它应该插入的位置,即arr[j]
的后面。
-
插入 key:
arr[j+1] = key
这行代码将key
插入到正确的位置。由于在循环中arr[j]
已经被移动到了arr[j+1]
的位置,所以j+1
就是key
应该插入的空位。
因此,j+1
是 key
应该在的位置,因为在循环中已经确保了所有小于 key
的元素都被移动到了 key
的右边,而 key
需要插入到等于或大于它的元素的前面。这样,每次循环结束时,key
都会被插入到已排序序列的正确位置,保持了序列的有序性。
当j=0时且key仍然小于arr[j]时,继续while循环,j变成-1,退出while循环。再将key的值赋给arr[j+1]即是arr[0],为数列首元素。
当j>=0但key>arr[j]时,退出while循环。将arr[j+1]=key。本来在循环中arr[j+1] = arr[j](使得arr[j]和arr[j+1]为同一值)。退出循环后又将arr[j+1]赋为key。