全民一起玩Python提高篇第四课:深入数据类型与语法细节(下)

提高健壮性

如果 try 结构的位置不当,可能导致死循环等问题。

file_name=input('请输入文件名:')
try:
    with open(file_name) as f:
        #用with的方式读写更加安全
        #因为出错可能在打开时,可能是关闭时
        #所以这样读写能保证正确处理
        print('你好')
except (FileNotFoundError,FileExistsError):
    #用元组放错误类型
    print('文件不存在')
except ZeroDivisionError:
    print('文件中没有数据')
except Exception as e:
    #所有异常都属于Exception类
    print('特殊错误:',e)
else:
    print('没有任何异常才会到这句话')
finally:
    print('有没有异常都会执行这句话!')
    #这句话必须执行,甚至会影响语句上面的return语句

题目:比较销量

编写一个程序读取该文件的每一行记录;对于每一条记录,如果其数字健全并且格式正确,则在屏幕上输出该产品A地区销量与B地区销量的比例;否则提示该产品无法计算,然后跳过这一行,继续检查计算下一条记录。

file_name=input('请输入文件名:')
with open(file_name) as f:
    for i in f.readlines():
        try:
        #try写在这里面,再次循环扫下一行才行
            s=i.split(',')
            print(s[0],'在AB两地区的销量分别为',format(float(s[1].strip())/float(s[2].strip()),'0.2f'))
        except Exception as err:
            print(s[0],'该行数据存在问题')

如果想自己测试,可以手动通过raise关键字来人为添加异常

raise ZeroDivisionError('除数为0异常')
Traceback (most recent call last):
  File "E:/拷贝过来的文件/全民一起玩Python/MyProject/实战案例/小甲鱼练习.py", line 1, in <module>
    raise ZeroDivisionError('除数为0异常')
ZeroDivisionError: 除数为0异常

作用域和类型函数

  1. 用 type(x) 可以得到一个type类对象,该对象的属性中保存了名称 x 的数据类型信息。特别是该对象的 name 属性,就是变量 x 的类型名称。比如 type(3.14).name 得到的就是字符串 ‘float’
  2. 由于 type 函数将类型名称作为字符串返回,所以实际编程时容易因为字符串笔误等原因造成隐患;同时该函数无法用于分辨一个类型是否属于其父类(比如bool类型数据True是否也是一个int类型的数据),因此一般更推荐使用 isinstance 函数。
  3. isinstance(x, 类型名) 可以返回一个逻辑值True或False,代表x是否属于指定类型。其中类型名不是字符串形式,而是直接书写,比如 isinstance(x, int) 。
  4. 变量从被首次赋值起正式创建可用,针对该变量的第一条赋值语句,相当于该变量的定义或声明。在变量赋值之前,尝试使用该变量会导致错误。
  5. 在模块中定义的变量,其作用域是整个模块,即该模块中的所有代码都可以使用该变量(对于该模块中的函数相对特殊,请见后几条笔记);而定义在函数和类中的变量,其作用域只是该函数或类,外部代码无法访问。
  6. 作用域只有模块、函数和类几种区别,而 if、for、while、try…catch 等流程结构并不影响作用域。
  7. 模块中只能调用本模块全局变量,无法调用函数等作用域内部的局部变量。
  8. 函数内部如果没有赋值过与全局变量同名的变量,则可以读取该全局变量的数值。
  9. 如果函数内部通过指定参数名、赋值语句或for循环等方式定义了自己的局部变量,则该函数内部无法读取修改与之同名的全局变量。注意:即使函数中没有使用赋值语句,但只要该名字出现在函数的参数列表中,或者是 for 循环的循环变量,也相当于赋值、会创建相应的局部变量。
  10. 如果在函数中先使用 global 关键字对某个变量进行特别声明,则该函数中所用到的这个变量名,一律指代全局变量,即使赋值也不会创建新的局部变量。

变量的一些原理

程序运行时,Python会在内存中维护一个“变量表”。里面每条记录都保存了一个变量的信息.其中关键两个信息是该变量的名字、该变量所指向的内存地址号码,而该变量的真实取值则存放在该地址号码指向的内存单元。当 Python 需要读取数据时,首先根据变量名得到这个地址,然后再根据该地址,找到真实数据。类似于C语言的指针

使用内置函 id() 可以取出一个变量所指向的地址号码。在使用官方解释器 CPython 时,id 函数返回的这个数字就是内存地址。

修改一个变量的取值时,Python 只是修改了这个变量所存储的地址号码,从而让它指向新数值的所在位置,并不会修改原来那个位置的原数值。原数值将一直保留在其内存单元中,直到Python将其收回。

使用 is 可以比较两个变量是否指向同一地址,即其 id 是否相同。
对于 a 和 b 两个变量,如果 a is b 为 True,则 a== b 一定为 True;反之如果 a==b 为True,a is b 有可能是 False。

a=400
b=400
a is b
False
a==b
True

为提高程序效率,Python会预先创建好 -5 至 256 范围内的常用小整数,保存在内存中固定位置。当程序用到这些整数时,不必再次重复创建,因而执行 a=3 和 b=1+2 后,a 与 b 指向同一内存地址,即 a is b 返回 True。

y=id(x)
y
8791415183040
x=x+1
y=id(x)
y
8791415183072
x=x-1
y=id(x)
y
8791415183040

比较一下上下的代码

y
59421904
x=x+1
y=id(x)
y
58453296
x=x-1
y=id(x)
y
58453232

当在程序中创建一个字符串并赋值给某个变量时,Python会先检查内存中是否已经存在同样内容的字符串。如果已经存在,则不会再重复创建,而是让该变量直接指向这个已存在的字符串。

但是对于含有特殊字符以及中文等文本的字符串,Python不会按此机制检查,即使内存中已经存在相同内容,也会直接创建一个新的字符串对象。

如果将一个变量赋值为容器(比如列表),那么这个变量的门牌号会指向内存中一个较大的空间,也就是容器所在位置。而这个位置的内存中也存放有多个地址数字,每个地址再指向另外一处内存,也就是容器中每个元素的数值存放位置。

如果一块内存中保存了数字或字符串,那么这块内存就不再允许修改;那如果其中保存的是列表,那么其内部存储的各个地址号码都允许修改,以便使对应元素指向其他数值。在Python中,我们将前者称为“不可变对象”,后者称为“可变对象”。

>>> a=[1,2,3]
b=a
b.extend([4,5])
# 扩建不是新建
b
[1, 2, 3, 4, 5]
a
[1, 2, 3, 4, 5]
a=[1,2]
b=a
b=b+[4,5]
b
[1, 2, 4, 5]
a
[1, 2]

基本的不可变对象包括数字、字符串、布尔值(也算数字)以及元组;可变对象包括列表、集合、字典。

元组对象的“不可变性”,是指元组内部保存的各个地址号码不允许修改;但是这些号码所指向的内存单元中如果是可变对象(比如列表),那么这些可变对象仍可随意修改,与元组无关。

列表与循环

price=[100,220,310]

for i in price:
    print(i)
for i in price:
    i=i*7
print(price)
100
220
310
[100, 220, 310]

按上述写法,并不能修改列表元素
只是变化的i,不会变化price

要修改元素,最好直接用while语句

price=[100,220,310]

i=0

while i<len(price):
    price[i]=price[i]+7
    #直接改列表
    i+=1
print(price)
import xlwings as xw
import random
app=xw.App()
wb=app.books.open('E:\拷贝过来的文件\全民一起玩Python\MyProject\皇帝寿命.xlsx')
names=wb.sheets['Sheet2'].range('A2:B23').value
wb.close()
app.quit()

def order(s):
    return s[1]
names.sort(key=order,reverse=True)
#以order为函数排列
#循环打印
for n in names:
    print(n)
random.shuffle(names)
#重新洗牌,随机生成序列
award=random.sample(names,2)
print(award)
#随机抽取几个

[‘弘历’, 87.43]
[‘玄烨’, 68.67]
[‘旻宁’, 67.49]
[‘朱棣’, 64.32]
[‘颙琰’, 59.84]
[‘朱厚熜’, 59.39]
[‘朱翊钧’, 56.99]
[‘胤禛’, 56.85]
[‘朱高炽’, 46.81]
[‘朱祐杬’, 43.0]
[‘朱见深’, 39.78]
[‘朱常洛’, 38.11]
[‘朱瞻’, 36.9]
[‘朱祁镇’, 36.26]
[‘朱载垕’, 35.36]
[‘朱祐樘’, 34.88]
[‘朱由检’, 33.24]
[‘奕詝’, 30.12]
[‘朱厚照’, 29.5]
[‘福临’, 22.91]
[‘朱由校’, 21.75]
[‘载淳’, 18.72]
[[‘朱高炽’, 46.81], [‘弘历’, 87.43]]

Process finished with exit code 0

对这个学历进行排序,并且保留修改之前的顺序
在这里插入图片描述

import xlwings as xw
import random
app=xw.App()
wb=app.books.open('E:\拷贝过来的文件\全民一起玩Python\MyProject\皇帝寿命.xlsx')
names=wb.sheets['Sheet3'].range('A2:B10').value
wb.close()
app.quit()

d={'初中':0,'高中':1,'本科':2,'硕士':3,'博士':4}
def degree_order(s):
    t=s[1]
    return d[t]
    #用字典存储要比较的键值,然后以此为排序的函数
'''sort 是直接改了列表,没办法读回原来的值
#如果写b=names企图来备份,是不行的
#因为这里的b是指向的地址,names变,b指的位置还是要变'''

c=sorted(names,key=degree_order)
#sorted是不改变原来列表,直接创新表
#这样就可以实现了

#循环打印
for n in names:
    print(n)
#print(b)
for n in c:
    print(n)

或者写为

b=names.copy()

names.sort(key=degree_order)
#循环打印
print(b)
for n in names:
    print(n)

题目一:三种读列表的方式

读列表
三种形式

a = [3,5,7,9]

for x in a:
    print(x)

x = 0
while x<len(a):
    print( a[x] )
    x += 1

for x in range( len(a) ):
    print( a[x] )

题目二:指定列表中所有元素乘指定倍数

请编写一个函数,能够将指定的列表中所有元素都乘以指定倍数。该函数接收两个参数:需要修改的列表、需要乘以的倍数。具体调用形式如下(假设该函数名字是 list_times ):

lst=[1,3,5,7]
def list_times(s,i):
    for x in range(len(s)):
        s[x]*=i
    return s
list_times(lst,15)
print(lst)

题目三:按照《百家姓》顺序对该列表排序

《百家姓》的前八位顺序是“赵钱孙李周吴郑王”。假设现在有一个列表 ,其中是公司里多位员工的姓氏(该公司每位员工都是这八姓之一):
请编写一个排序函数,从而能够按照《百家姓》顺序对该列表排序。
names=[‘钱图’,‘李义’,‘吴天’,‘王力’,‘李新’,‘吴永’,‘赵清’,‘王刚’,‘王伍’,‘郑朵’,‘周青’,‘孙莲’,‘王义’,‘李宏’,‘孙月’,‘赵婷’,‘周显’ ]

names=['钱图','李义','吴天','王力','李新','吴永','赵清','王刚','王伍','郑朵','周青','孙莲','王义','李宏','孙月','赵婷','周显' ]
d={'赵':0,'钱':1,'孙':2,'李':3,'周':4,'吴':5,'郑':6,'王':7}
def degree_order(s):
    t=s[0]
    return d[t]
    #用字典存储要比较的键值,然后以此为排序的函数

b=names.copy()
names.sort(key=degree_order,reverse=True)
#循环打印
print(b)
for n in names:
    print(n)

题目四:按照员工姓氏排序

对表格中 B3:D657 范围内的全部员工记录,按照员工姓氏排序。

import xlwings as xw

app=xw.App()
wb=app.books.open('E:\拷贝过来的文件\全民一起玩Python\MyProject\第十二课作业.xlsx')
wb.sheets['Sheet3'].range('C3').value='Nihao'
names=wb.sheets['Sheet1'].range('B3:D657').value
d={'赵':0,'钱':1,'孙':2,'李':3,'周':4,'吴':5,'郑':6,'王':7}
def degree_order(s):
    t=s[0][0]
    return d[t]
    #用字典存储要比较的键值,然后以此为排序的函数

names.sort(key=degree_order,reverse=False)

wb.sheets['Sheet1'].range('F3:H657').value=names
for n in names:
    print(n)

wb.close()
app.quit()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值