学习笔记

全民一起玩Python【1】

1.模块导入需先行,巧用name规范主宾

import不仅能导入模块,还能导入同文件夹下的文件,不需要加入文件后缀

比如,导入b.py只需要写上import b

Python中,每一个import语句就相当于执行了一个run命令,去运行指定的python程序

导入的另一个Python程序将会被运行

import语句经常被写在程序的开头,但在其他位置,也能使用import,程序会在运行到对应位置时,执行import语句

模块只能被导入一次,也就是说一个模块被导入多次,Python只将第一次导入视作有效

Python程序可以import自己

A调用B,两个Python程序都有相同名字的变量,但却不会发生冲突,因为调用B的变量,需要B.变量名,因为被调用的B就相当于一个模块,调用模块里的变量X,就需要写模块名.x,而不是直接写x,因此即使A和B存在重名的变量,也不会发生冲突。

有时候A调用B,只希望将B当做一个函数库,而不希望B里面的代码被执行,可以将B里面函数之外这些可执行的代码放到一个判断结构中(注意有左右各两个下划线)

可以将函数之外的代码,放入:

if __name__==’__main__’:

可以将下划线内想象成Python系统定义的一个特殊系统变量,代表它所在程序的名字,当Python导入一个程序模块准备运行它的时候会自动判断一下这个程序是自己独立运行的,还是被放在import语句中运行的,

如果是独立运行,那么Python在运行这个程序之前,会先把__name__变量设置为【__main__】

如果被放在import语句中运行,__name__会被设置为这个程序模块的名字

因此,如果希望import后不被执行代码,可以放入if __name__==’__main__’:内

📎02 模块导入需先运行,巧用name规范主宾-迅捷文字转语音-1679985190146zh.docx

此处为语雀视频卡片,点击链接查看:02 模块导入需先运行,巧用name规范主宾.mp4

2.包结构整合发布多模块,MatPlotLib轻松绘制统计图

可以在python程序文件中创建一个文件夹,再将自己另一个当做模块调用的py文件放入文件夹中

如果文件夹的名字是a,文件夹中的模块文件名是b.py

在主程序中调用,可以写: import a.b

该功能在Python3.3之前的版本中会有区别,在旧版本的Python中,a文件夹内必须有个__init__.py文件(文件内容可以为空)才能被识别。

为了更加规范,每次创建模块文件夹时,都建立__init__.py文件

可以在__init__.py文件中加入代码,这些代码在模块被调用的时候直接自动运行

模块文件夹内还有一个文件是__main__.py,如果将多个Python文件做成一个压缩包,其中主程序的文件名是__main__.py,在CMD中执行一下命令python zip文件路径,回车后就能在CMD中运行该程序。

用pip命令安装的模块,都在Python安装目录下的\Lib\site-packages内

C:\Users\llj\AppData\Local\Programs\Python\Python310\Lib\site-packages

使用import命令时,如果看见import 模块名.功能名,就相当于import模块文件夹内的某个文件

import matplotlib.pyplot as plot

import random
plot.rcParams['font.sans-serif']=['Microsoft Yahei'] #将默认字体设置成中文,以支持中文显示
plot.rcParams['axes.unicode_minus']=False   #使【-】号显示正常

#可以通过修改文件的方法让其默认支持中文

#生成1到100之间的随机数作为散点图的参数
r1 = [random.randint(1, 100) for _ in range(10)]
r2 = [random.randint(1, 100) for _ in range(10)]

plot.grid() #给图表添加网格线

plot.title('这里是标题 / this is title') #给图标增加标题
plot.xlabel('x方向的名称(横)')
plot.ylabel('y方向的名称(竖)')

#绘制散点图,marker参数用于修改散点图中散点的样式,s用于修改散点的大小
#s可以是一个列表,图表中有几个点,列表中就设置多少个数字,这样散点图中的散点大小就不一样
#参数c可以设置散点的颜色
plot.scatter(r1,r2,marker='*',s=200)

#除了scatter散点图,还有plot,bar等图形

plot.show() #绘制散点图后,必须使用show才能让它显示

3.按名字传参数对号入座,用星号代列表长短自由

调用函数时,可以直接输入函数的参数的数值,但必须按照函数的参数顺序输入

如果不按顺序输入,可以输入函数的参数名加上等于号再输入数值

创建函数时,可以设置函数的默认值,这样在调用函数的时候,有默认值的参数可以被省略

有默认值的参数被称为可选参数,没有默认值的参数称为必选参数

如果在申明一个函数时,既有可选参数,又有必选参数,那么可选参数,也就是由默认值的参数,必选放在必选参数之后,否则程序运行会报错。

如果申明函数时,不确定将来会被传入多少个参数,可以使用参数列表,也就是参数等于列表,比如a=[],

但Python更推荐的做法是在参数前加上星号*

被称作不定长参数(可边长参数)

只要Python看到这个参数有个星号,它就会将传递进来的参数合并成一个元组

申明函数时,可以将不定长参数可以与普通参数同时使用,但需要注意的是,如果这样做,要将不定长参数的位置放在可选参数之后。

#输入客户每套房产的价格,返回所有房产的总价值
def house_value(*all_house):
    s=0
    for h in all_house:
        s+=h
    return s

m=house_value(10000000,20000000)
print(m)

申明函数时如果参数前放上两个星号,调用函数时填入的参数,会被作为字典传入参数

该参数可以被叫做不定长关键字参数

不定长关键字参数,必须放在末尾,甚至在不定长参数之后

#接收多个参数,打包成字典交给info
def show_client_info(**info):
    print('客户姓名',info['name'])
    print('客户年龄:',info['age'])
    print('客户性别:',info['gender'])

if __name__=='__main__':
    show_client_info(name='n',age='200',gender='男')

4.小数点计算不精确,二进制背后做文章

许多十进制中的有限位小数(如0.1),用二进制只能表示为无限小数,

所以计算机只能将其截断,仅保留前几十位,

因此计算机使用的截断后的小数与真实的数值之间会有差异,

比如,让Python计算print(0.1+0.2),得到的会是0.30000000000000004

大多数时候,该误差小到可以被忽视,但在一些专业领域,比如金融,该问题必须想办法解决。

此处为语雀视频卡片,点击链接查看:29第五回:小数点计算不精确,二进制背后做文章.mp4

5.decimal做精算优于round,format调格式胜过其他

round函数可以对数字进行四舍五入,早期版本的Python中,当小数点是.5的时候,所有的数字都会按照正常的四舍五入,如今的Python中,四舍五入采用的是奇进偶不进,比如:

print(round(6.5)) #返回6

print(round(7.5)) #返回8

为了解决Python计算数字不精确的问题,Python有一个标准模块是Decimal,它内置了多种高精度的用于十进制计算的工具

其中最常见的是Decimal类,可以创建“真正的”Decimal十进制数字,比如:Decimal(‘2.10’),但需要注意的是,它的参数必须得是字符串形式

如果参数不是字符串,而是直接的数字,将无法得到精确的结果,因为它会先将数字形式按二进制转换成近似的十进制数字,再进行计算

如果是字符串形式,则可以正常计算,比如:

from decimal import Decimal

Decimal(‘0.1’)+Decimal(‘0.2’)

还需要注意的是,decimal模块创建的数字,是一个decimal对象,不能与Python中普通的数字进行运算,会提示类型错误,但可以通过print()语句正常打印,显示结果与普通数字没有区别。

如果要与普通数字进行运算,可以先通过int() / float() 等方法转换成普通的数字,再进行计算

如果对计算结果有精度要求,就可以使用decimal,但是decimal的运算结果会相对较慢,因此一般场景下,知己诶使用默认的数字格式即可。

如果对精度没有要求,但是普通数字的计算结果后面的小数位数很长,可以使用format()方法来“美化格式”,使用方法为:format(‘数字’,’格式说明’)

比如:

format(3.1415926,’0.2f’),就只会保留2位小数,变成3.14

在上面例子的0.2f中,0的位置代表结果字符串的总长度,如果为0则表示不指定长度,2表示结果保留几位小数,会进行四舍五入,f表示结果普通小数,如果将f改成3,则会采用科学计数法的形式。

如果在格式设置的参数的开头,填入<,数字会以左对齐,如果填入>,数字会向右对齐,比如print(format(22222.1615926,’>100.2f’))

Python中,无穷大可以表示为float(‘inf’),负无穷大可以表示为float(‘-inf’)

无穷大乘以正数会得到正无穷大,乘以负数会得到负无穷大,正无穷大减去负无穷大的结果仍然是正无穷大,无穷大的倒数为0,如果是正无穷大除以负无穷大,Python会返回NaN。

6.逻辑运算可以巧写代码,读写数据需要区分类型

解决Python计算小数精度不够的问题,还有一个解决方法是,先将小数转换成整数再计算,因为在Python中,只要内存足够计算整数就没有误差。

两个比较长的小数直接相乘,Python的计算结果大概不会精确,在转换成整数并相乘之后,再用str()方法将计算结果转换成字符串,然后进行切片操作,取整数乘积的整数部分加上小数点再取整数乘积的小数部分

#计算1.1乘以2.1
#先转换成整数计算11*21
x=11
y=21
r=str(x*y)
z=r[:1]+'.'+r[1:]
print(z)

如果不是采用整数转换成字符串再切片,而是使用除法,比如让231/100,依然会触发浮点数运算,因此计算结果可能会存在截断误差

此处为语雀视频卡片,点击链接查看:31. 逻辑运算可以巧写代码,读写数据需要区分类型.mp4

7. 时间流逝不过是数字加减,逻辑真假也无非零一相间

在算数运算中,如果用数字与True和False进行运算,那么True会被当成1,False会被当成0

不同数字之间也可以像True和False那样进行逻辑运算,and和or会返回两个数字之一,not则会将其视作True或False,再返回取反结果(True或False)比如:

print(1 and 0)  #0
print(1 or 0)   #1
print(25 and 26) #26
print(-6 or 0)  #-6
print(3 or 17)  #3
print(not 3)    #False

Python中的任何数据、对象都可以被if和while当做True或False来处理,有代表True,比如除零之外的任何数字(包括负数)、非空字符串等,无代表False,比如空字符串、数字0等、空字典、空列表等…

根据上述特性,在实际应用中,如果判断一个列表是否为空,直接用代码【if 列表】即可,而不需要【if len(列表)>0】

bool函数可以将任何数据转换为逻辑值True或False,值得一提的是,只有空字符串才会被转换成False,而’False’字符串,即字符串内容是”False”也会被转换成True

#如果用户输入列表中的任何一个内容,则返回True,否则返回False
def func(s):
    words=['yes','是的','ok','True']
    if s.strip().lower() in words:  #将输入内容转换为小写并删除字符串开头与结尾的空格
        return True
    else:
        return False

if __name__=='__main__':
    x=input('输入内容判断是否为True:')
    print(func(x))

时间也可以被转换成数字,Python中time模块的time函数可以看到当前的系统时间,调用后可以看见,它返回的其实是一个数字,这个数字可以理解为,从1970年1月1日0点0分至今一共过去了多少秒,由于计算机的计时精度可以精确到毫秒、微秒,因此看见的数字侯庙还有好几位小数比如:

import time
print(time.time())	#1681020448.4203398
print(time.time())	#1681020448.4203398
time.sleep(1)
print(time.time())	#1681020449.4209137
import time

#分别使用 循环 和 sum函数 两种方法,计算从0加到999999的总和,比较这两种方法的计算缩小的时间

t1=time.time()  #初始时间1
#循环
s=0
for i in range(1000000):
    s+=i
t2=time.time()  #初始时间1
print(1000*(t2-t1)) #t2减t1可以算出计算耗时多久,乘以1000表示以毫秒显示
#耗时123毫秒

t9=time.time()
#sum()函数
s=sum(range(1000000))
t10=time.time()
print(1000*(t10-t9)) #t10减t9可以算出计算耗时多久,乘以1000表示以毫秒显示
#耗时31毫秒

time模块的缺点是无法表示1970年之前的日期,但Python还提供了datetime模块,在datetime模块中的datetime类,可以通过它按年、月、日构造出任何一个日期,创造时,年、月、日是必选参数,时、分、秒、微秒、时区是可选参数

如果创造程序运行当时的时间,可以使用datetime,now()

有了datetime对象,可以通过year/month/day/hour/minute/second(后面无需加上括号)这些属性来得到相应的信息

strftime() 为时间对象设置显示格式,转换成字符串

datetime对象的strftime()方法可以将一个时间对象转换成任意格式的字符串,调用形式是【时间对象.strftime(‘期望的格式’)】,注意大小写,同一个字母大小写不同会有不一样的含义,在这些符号之间,还可以穿插任意字符来修饰日期格式,最后将自己设置的格式作为字符串当成参数返回给strftime方法,比如.strftime(‘%Y年%m月%d日’),

需要注意的是,中文显示可能会存在问题,需要在程序中加入设置,需要加入一条import local代码,将本地环境设置为中文:

import locale

locale.setlocale(locale.LC_CTYPE,’chinese’) #指定为中文字符格式

符号含义符号含义
%Y完整年份,比如1998%y两位年份,比如23即2023年
%M分钟数字,比如21%m月份数字,比如02
%S秒数,比如23%d日期数字,比如10
%H小时数字,24小时制,如21%f微秒,如666666
%A星期几的全名,比如Friday%a星期几的英文缩写,如Mon,Tue
%W本周是年内第几周,0到53%w星期几的数字,周日为0,周六为6
%B月份全民,如January%b月份缩写,如jan
%I(字母)十二小时制数字,如06%p上下午标记,即AM或PM
%j全年第几天,如365%%显示一个普通的百分号
import locale
locale.setlocale(locale.LC_CTYPE,'chinese') #指定为中文字符格式
#创建一个指定的日期时间
from datetime import datetime
h1=datetime(2023,4,9,8,23) #2023年4月9日8点23分
print(h1) #2023-04-09 08:23:00

print(datetime.now())	#2023-04-09 08:25:19.884345

print(h1.year)#2023

now=datetime.now()
print(now.strftime('%Y年%m月%d日')) #2023年04月09日

strptime()将时间字符串转换成日期对象

与strftime()可以将日期对象设置显示格式转换成字符串相反,strptime()可以将字符串转换成datetime对象

用法是datetime.strptime(‘待转换的字符串’,’该字符串使用的时间格式’)

在第二个参数中,只需要将原字符串中的数字替换成对应的标识,其他字符保持不变即可

s='2月10日,2022年22点,10分'
d=datetime.strptime(s,'%m月%d日,%Y年%H点,%M分')
print(d)

datetime.timedelta() 时间间隔

datetime.timedelta()用于表示时间间隔,也就是两个日期或时间之间的差值,它可以用于日期或时间之间的加减运算

timedelta类的构造函数如下,所有的参数都可以是正数或者负数:

timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

import datetime
#计算7天后的日期
now=datetime.datetime.now()
delta=datetime.timedelta(7)
future=now+delta
print('7天后的日期:',future)

#计算两个日期之间的间隔:

import datetime

d1=datetime.datetime(2001,6,1)
d2=datetime.datetime(1998,2,10)
delta=d2-d1
print(delta) #-1207 days, 0:00:00
print(type(delta)) #<class 'datetime.timedelta'>

创建时间差不能以年为单位,如果想要实现这个功能,只能使用第三方模块,比如dateutil、arrow以及workalendar。

dateutil:扩展增强了标准模块datetime的功能

arrow:功能强大,可以提到datetime

workalendar:可以判断某日是工作日还是法定节假日,涵盖包括中国在内的主要国家和地区(假日每年更新,不敢保证包分之百精确)

dateutil的relativedelta可以指定年作为时间差,比如:

from datetime import datetime
from dateutil.relativedelta import relativedelta
k=relativedelta(years=100)
now=datetime.now()
future=now+k
print(future)
'''假设现在运营一个网店,已近知道一些关键的日期节点上销量的变化情况,
现在想要做一个统计图,将数据展现出来
如果只是按照日期来绘图,因为这几个日期的间隔不一致,但用matplot上因为没有设置间隔,展示效果与实际间隔并不一致

如果横坐标都是数字,那么matplot可以自动根据数字之间的差来计算正确的相隔间距'''

'''大致的思路是,先创建一个空列表,用它来做很坐标,然后循环扫描日期字符串列表中每一个日期,将每个字符串转换成datetime对象,接下计算相邻两个日期之间的差距,得到一个时间差,再将时间差放入列表,得到一个时间差列表,将时间差列表作为横坐标

matplot还允许设置横坐标的显示,隐藏真正的横坐标,用自定义横坐标来展示'''

from matplotlib import pyplot as plt
from datetime import datetime

plt.rcParams['font.sans-serif']=['fangsong']
plt.rcParams['axes.unicode_minus']=False

sales=[5,22,48,78]
dates=['19-03-01','19-03-12','19-03-16','19-03-31']

#将days中的字符串,转换为代表“第几天”的数字保存到days列表中,再用days作为plot的横坐标,解决检举问题
days=[]

for d in dates:
    delta=datetime.strptime(d,'%y-%m-%d') - datetime.strptime(dates[0],'%y-%m-%d')
    days.append(delta.days)
plt.grid()
plt.title('销量')
plt.xticks(days,dates)	#设置显示的标签
print(days)
plt.plot(dates,sales)
plt.show()

chatGPT修改后的代码:

import matplotlib.pyplot as plt
from datetime import datetime

plt.rcParams['font.sans-serif']=['fangsong']
plt.rcParams['axes.unicode_minus']=False

sales=[5,22,48,78]
dates=['19-03-01','19-03-12','19-03-16','19-03-31']

#将dates中的字符串,转换为代表“第几天”的数字保存到days列表中,再用days作为plot的横坐标,解决间隔问题
days=[]
for d in dates:
    #使用多个格式字符串来匹配不同的分隔符
    delta=datetime.strptime(d,'%y-%m-%d') if '-' in d else datetime.strptime(d,'%y,%m,%d')
    delta -= datetime.strptime(dates[0],'%y-%m-%d')
    days.append(delta.days)

#在循环结束后调用plot和show函数
plt.plot(days,sales)
plt.xticks(days, dates)
plt.show()

8.with块管理文件显专业,try结构临危不乱解异常

#读取指定txt文件,计算文件内所有数字的平均数
file_name=input('请输入要统计的数据文件名:')

from os.path import exists
#导入exests函数,用于判断给定的文件路径是否存在,返回True或False

if exists(file_name):


    f=open(file_name,encoding='utf-8')
    all_data=f.readlines()
    #readline()的功能,就是将txt文件中,每一行的内容作为一个元素,存入一个列表

    #判断如果列表长度不为0才继续进行计算,如果是空文件,列表长度会为0
    if all_data:


        s=0 #初始化0
        for i in all_data:
            s+=float(i)#计算列表内数值之和

        a=s/len(all_data)   #除以列表中元素数量取平均值

        print(f'该文件数据平均值为{round(a,2)}')
        #round的功能是保留2位小数
        '''
        在这段代码中,f不是一个单独的变量或对象,而是一个Python 3.6及以上版本中的一种新的字符串格式化语法,称为 f-strings。f-strings是一种方便的方法,允许将表达式、变量和字面值嵌入到字符串中,而无需使用其他字符串连接或格式化方法。
        
        在这个例子中,f'该文件数据平均值为{round(a,2)}'是一个f-string,其中大括号中的表达式round(a, 2)会被计算并替换为其结果。在这个例子中,round(a,2)是计算的平均值,它将被替换到f-string中,产生一个包含平均值的字符串,该字符串将被打印到屏幕上。
        '''
    else:
        print('该文件中没有数据')

    f.close()

以上代码中,if else结构使代码看上去更加复杂,可以使用Python的异常处理功能,

try:

…尝试运行的代码…

except:

…如果出错则跳转至此

Python官方已经顶一哈了许多“内置异常类”,每个异常类都代表一种特殊的错误,比如fileNotFound类的对象代表一次“文件不存在”错误,ZeroDivisionError代表“除零”错误。

常见的错误类有:

KeyboardInterrupt(用户中断执行(通常是输入^C))

OverflowError 数值运算超出最大限制

ZeroDivisionError 除(或取模)零

AttributeError 对象没有这个属性

OSSError 操作系统错误

ImportError 导入模块/对象失败

IndexError 在列表、元组等序列中调用了不存在的下标

KeyError 在字典等映射结构中调用了不存在的键

MemoryError 内存溢出

程序触发异常时,Python会自动生成一个对应异常类对象,并交给try…except结构,从而可以针对性的执行处理

except Exception as e:  #将错误类型作为对象交给e
    print(e)	#输出错误类型

except可以并排书写多个,实现分类处理不同异常,也就是针对每一种异常提供专门的处理代码

try:

except 异常类名称1:

except 异常类名称2:

except 异常类名称N:

try:
    #尝试运行的代码
except FileNotFoundError:
    #要执行的语句
except ZeroDivisionError:
    #要执行的语句

如果要针对多种异常提供同一个处理代码,Python允许在一个except子句里写多种异常类型,但需要将这些异常类型放在一个圆括号中,变成一个元组结构:

except (异常1,异常2)

如果程序发生的异常不包括在括号中指定的多个异常里面,还可以再加一句:

except Exception as e:

#要执行的语句

还可以在except语句之后加入一个else,如果没有发生异常,则执行else语句下的内容

else:

print(‘程序正常运行’)

Python还为【Try】提供了finally语句,可以并排写在except、else之后,无论是否发生异常,都会执行finally中的语句:

finally:

finally应用的场景有许多,比如打开文件后,最后都还得关闭文件,否则可能造成数据丢失、文件锁死等情况。

with块管理文件

以下代码实现的功能是:打开一个文本文件,明明为f,然后在with结构内部均可使用f代表该文件,而with内部代码执行完毕后,Python会自动关闭该文件,不需要调用close()方法。

with open('01.txt',encoding='gb18030') as f:
    all_data=f.readlines()
    s=0
    for i in all_data:
        s+=float(i)
        a=s/len(all_data)
        print('平均数是:',a)

with结构可以用于任何实现了“上下文管理器”模式的对象(比如文件类),能够自动管理各种收尾工作,适用于Python2.5开始之后的版本。

9.类型函数眼里 哪个原形能躲?试看作用域中 谁家变量天下!

根据输入的数值,计算该数值的平方,输入的数值类型可以使整数、小数甚至是列表,因此,每次计算时都需要先判断要计算的对象的类型,可以先创建一个函数,然后通过type对象的__name__属性得到该对象所属的类型,然后再执行相对应的计算步骤

所有的type类对象都有一个属性【.__name__】,可以返回一个字符串,该字符串就是该对性所属类型的名字

比如【(type(1).__name__】会返回【int】

【type(1.1).__name__】会得到【float】

【type(‘a’).__name__】返回【str】

【(type((1,2)).__name__】返回【tuple】

from decimal import Decimal
def sqr(x):
    t=type(x).__name__
    result=''

    if t=='int':
        result=x**2
    elif t=='float':
        s=Decimal(str(x))   #decimal接受的是字符串
        result=s*s

    elif t=='list':
        result=[]
        for i in x:
            result.append(i*i)
    return result

type函数也有其局限性,首先是对字符串比较不够严谨,容易笔误,然后是无法合理判断类型之间的继承关系,比type()更为常用的是isinstance()

isinstance(变量名,类型名)

可以判断该变量是否属于该类型,如果是返回True,否则返回False,需要注意的是,类型名不需要是字符串,而直接写int、float等类名,比如isinstance(a,int)可以判断a是否属于int类型的一个实例

from decimal import Decimal
def sqr(x):
    result=''
    try:
        if isinstance(x,int):
            result=x**2
        elif issubclass(x,float):
            s=Decimal(str(x))
            result=s*s
        elif isinstance(x,list):
            result=[]
            for i in x:
                result.append(i*i)

    except Exception as e:
        print('计算出现问题,请检查要输入的数据类型')
        result=''
    return result

print(sqr(6))

如果a=1,那么isinstance(a,int)和isinstance(a,bool)都会返回True

10数据类型有可变有不可变,判断相同或等号或用 is

给变量赋值时,Python会现在内存中生成数据以及该数据对应的内存地址(唯一标识符),然后将地址链接到该变量,可以通过id(变量名)来得到变量名的内存地址,可以通过is来判断两个变量是否链接了同一个内存地址,比如【a is b】。

a=300
b=a
print(a is b)	#True
print(id(a))	#a与b的ID相同
print(id(b))

b=b+1
print(a is b)	#返回False	b被链接到了一个新的内存地址

b=b-1
print(a is b)	#再次变成True,教程上说应该是返回False

is可以判断两个变量是否链接了同一个内存地址,而==用来判断两个变量的数值是否相等

上面的实例中,最初给a的赋值为300,因此最后才会得到false,如果是-5到256区间的数字,最后通过is作比较还是会得到True,因为Python为了提高程序运行效率,已经将-5至256区间的数字创建好,并放入固定的内存位置,程序中的任何语句用到这几个数字,都会直接找到上述的地址,使用这些已经创建好的对象,而不会像其他数字那样新建对象

不仅仅是数字,字符串也会有同样的现象,如果程序中用到了一个字符串,Python会首先检查内存中是否已存在相同内容的字符串对象,如果存在则直接链接该字符串的地址,而不会创建新的字符串对象,从而提高效率,但需要注意的是,如果字符串内容中存在包括中文在内的特殊符号,则上述规则无效,此时即便已经存在相同内容的字符串对象,Python也会创建新的字符串对象。

(实测中,两个内容相同的中文字符串对象可以返回True)

在存储列表时,Python会为每个列表元素生成相应的内存地址,然后给一个新的内存地址存放列表中每个元素的内存地址

如果要将列表中的某个元素修改为字符串,比如a[1]=’abc],Python会现在内存中找到或创建’abc’,然后更新存放里列表里每个元素的内存地址的内容

如果对列表使用extend,那么就会扩建原有列表链接的内存地址内的列表地址,因此就会出现下面的现象

a=[100,200]
b=a
b.extend([300])	#b扩建列表后,a的内容也发生了变化,因为它们链接了同一个内存地址
print(a)

如果是列表加法,则会创建一个新的列表

a=[100,200]
b=a
b=b+[123]
print(a)    #[100, 200]
print(b)    #[100, 200, 123]

在Python中,整数、浮点数。逻辑、字符串、元组等类型的数据,一旦创建出来,其在内存中的内容就不可再修改,给变量赋予新值,会将变量链接到一个新的内存地址,这些对象被称为“不可变对象”

列表、集合、字典等类型的数据,其在内存中的内容可以随时修改、扩充,这些对象被称为“可变对象”,值得注意的是,元组与列表虽然相似,但其链接的内存地址的内容是不可修改的,因此修改元组对象中的元素的数值,Python就会报错,此外,如果元组中包含了一个列表元素,可以通过修改其中列表元素的内容来改变元组,因为列表链接的内存地址的内容是可以被修改的

1 thought on “全民一起玩Python【1】”

发表回复