python 第二周
九、字典
1.基础介绍
①Python将单词称为键(key),将单词对应的含义称为值(value)
②字典是python唯一的映射类型,字符串、元组和列表都是序列类型
列表中的索引值和对应元素的值没有关系,两个列表中唯一的关系是索引值相同的元素有对应关系
③用{}表示字典,由多个健和其对应的值组成,索引时用[ ];健和值的组合称为项
④也可用dict这个工厂函数(类型,不是一般的BIF)创建一个字典
2.基本用法
2.1空字典:dict={}
2.2键入方式:
2.2.1
dict = (1:’one ‘,2:’two’,3:’three’)
索引:dict[2]
‘two’
2.2.2元组的方式
括号的个数,因为dict()只接受一个参数,所以用()把键值对包括起来成为元组
2.2.3关键字参数
dict4 =dict(小甲鱼=‘让编程改变世界’) #小甲鱼不能加引号
索引:dict4
小甲鱼=‘让编程改变世界’
2.2.4 直接改变字典的值
①若改变字典中原有健的值:
dict4[‘小甲鱼‘] = ‘让python改变世界’
索引:dict4
{‘小甲鱼’: ‘让python改变世界’}
②字典中没有的健
dict4[‘爱迪生’]=’天才是…’
索引:ditc4
{‘小甲鱼’: ‘让python改变世界’, ‘爱迪生’:’天才是…’}
3.内置方法
3.1 adict.keys() 返回一个包含字典所有KEY的列表;
3.2 adict.values() 返回一个包含字典所有value的列表;
3.3 adict.items() 返回一个包含所有(键,值)元祖的列表;
3.4 adict.clear() 删除字典中的所有项或元素;
3.5 adict.copy() 返回一个字典浅拷贝的副本;
直接赋值并没有创建新的内存空间
3.6 adict.fromkeys(seq, val=None) 创建并返回一个新字典,以seq中的元素做该字典的键,val做该字典中所有键对应的初始值(默认为None);
fromkeys(…) 创建并返回一个新的字典
dict. fromkeys(s[,v]) -> New dict with keys from S and
values equal to v (v defaults to None)
初始化一个空字典:
注意,仅仅是返回一个新字典,并不能改变旧字典,要想改变必须用a = a.fromkeys
3.7 adict.get(key, default = None)
返回字典中key对应的值,若key不存在字典中,则返回default的值(default默认为None);
一般来说如果试图访问字典中不存在的项时会出错,而用get就不会
3.8 in 、 not in;
3.9 adict.iteritems()、adict.iterkeys()、adict.itervalues() 与它们对应的非迭代方法一样,不同的是它们返回一个迭代子,而不是一个列表;
3.10 adict.pop(key[,default]) 和get方法相似。如果字典中存在key,删除并返回key对应的vuale;如果key不存在,且没有给出default的值,则引发keyerror异常;
3.11 adict.setdefault(key, default=None) 和set()方法相似,但如果字典中不存在Key键,由 adict[key] = default 为它赋值;
3.12 adict.update(bdict) 将字典bdict的键值对添加到字典adict中。
字典中的键,值,键值对用 .keys() .values() .items()表示
十、集合
无序 去重 不能索引
num = {}
type(num) –>’dict’
num2 ={1,2,3,4,5}
type(num2) –> ‘set’
num2 = {1,1,1,1,1,2,2,2,,2,,2}
–> {1,2}
1.创建的两种方法
用{} 把数字 括起来.
set() : set1 = set([1,1,1,1,2,2,2,2,2,2])
2.如何访问set中的值
for 打印
in 方法 1 in num1
3.num2.add(9) 添加
4.num2.remove(9) 删除
frozen 冻结的,设置一个不可变set
num3 = frozeset([1,2,3,666])
这种set不能添加
28-文件-想输出.
1.打开文件
使用 open 打开文件.
help()
十一、文件
1.用open打开文件:
打开的模式有:
‘r’-以只读方式打开文件(默认)
‘w’-以写入的方式打开 文件,会覆盖已存在的文件
‘x’-如果文件已经存在,使用此模式打开将引发异常
‘a’-0双写入模式撕开,如果文件存在,则在末尾追加写入
‘b’-以二进制模式打开文件
‘t’-以文本模式打开(默认)
‘+’-可读写模式(可添加到其他模式中使用)
‘U’-通用换行符支持.
例:
open(‘e:\test.txt’) # 两个\因为要转译(可以用u”),打开方式用了默认所以就不用写
f = open(‘e:\test.txt’) # 赋值给一个对象
2.文件对象的方法:
f.close() 关闭文件
f.read(size = -1) 从文件读取size个字符,当未给定size或给定负值的时候,
读取剩余的所有字符,然后作为字符串返回.指针移动到文件的不可末尾.
f.readline() 以写入模式打开,如果文件存在,则在末尾追加写入
f.write(str) 将字符串str写入文件
f.writelines(seq) 向文件写入字符串序列seq,seq应该是一个返回字符串的可迭代对象.
f.seek(offset,from) 在文件中移动文件指针,从from(0代表文件起始位置,1代表当前位置,2代表文件末尾)偏移offset个字节
f.tell() 返回当前在文件中的位置.
可以用list(f)把文件直接转换成为一个列表.
3.读取文件对象中的内容:
for i in f: (推荐这种方法)
print(i)
4.文件的写入:
打开方式一定要是 ‘a’或’w’
f = open(‘e:\test.txt’,’w’)
f.write(‘xxoo’)
f.close
5.
例1:
def save_file(goy, girl, count):
file_name_boy = ‘boy_’ + str(count) + ‘.txt’
filr_name_girl = ‘girl’ + str(count) + ‘.txt’
boy_file = open(file_name_body, ‘w’)
girl_file = open(file_name_girl, ‘w’)
boy_file.writelines(boy)
boy_file.writelines(girl)
boy_file.close()
girl_file.close()
def split_file(file_name):
f= open(‘test.txt’)
boy = []
girl = []
count = 1 # 计算
for each_line in f:
if each_line[:6] != ‘====’: # 前6个字符是等号
这里我们进行字符串分割
(role, line_spoken) = each_line.split(‘:’, 1)
if role == ‘小甲鱼’:
boy.append(line_spoken)
if role == ‘小客服’:
girl.append(line_spoken)
else:
6.文件的保存
save_file(boy, girl, count)
boy = []
boy = []
count += 1
save_file(boy, girl, count)
f.close()
split_file(‘recode.txt’)
十二、os模块和os.path模块
Python os
模块包含普遍的操作系统功能,注意括号中需要使用字符串
1.getcwd()
返回当前工作目录
2.chdir(path)
改变工作目录
3.listdir(path='.')
列举指定目录中的文件名('.'表示当前目录,'..'表示上一级目录)
4.mkdir(path)
创建单层目录,如该目录已存在抛出异常
5.makedirs(path)
递归创建多层目录,如该目录已存在抛出异常,注意:'E:\\a\\b'和'E:\\a\\c'并不会冲突
6.remove(path)
删除文件
7.rmdir(path)
删除单层目录,如该目录非空则抛出异常
8.removedirs(path)
递归删除目录,从子目录到父目录逐层尝试删除,遇到目录非空则抛出异常
9.rename(old, new)
将文件old重命名为new
10.system(command)
运行系统的shell命令
以下函数没有参数
11.os.curdir
指代当前目录('.')
12.os.pardir
指代上一级目录('..')
13.os.sep
输出操作系统特定的路径分隔符(Win下为'\\',Linux下为'/')
14.os.linesep
当前平台使用的行终止符(Win下为'\r\n',Linux下为'\n')
15.os.name
指代当前使用的操作系统(包括:'posix', 'nt', 'mac', 'os2', 'ce', 'java')
os.path模块
1.basename(path)
去掉目录路径,单独返回文件名
2.dirname(path)
去掉文件名,单独返回目录路径
3.join(path1[, path2[, ...]])
将path1, path2各部分组合成一个路径名
4,split(path)
分割文件名与路径,返回(f_path, f_name)元组。如果完全使用目录,它也会将最后一个目录作为文件名分离,且不会判断文件或者目录是否存在
5.splitext(path)
分离文件名与扩展名,返回(f_name, f_extension)元组
6.getsize(file)
返回指定文件的尺寸,单位是字节
7.getatime(file)
返回指定文件最近的访问时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
8.getctime(file)
返回指定文件的创建时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
9.getmtime(file)
返回指定文件最新的修改时间(浮点型秒数,可用time模块的gmtime()或localtime()函数换算)
以下为函数返回 True 或 False
10.exists(path)
判断指定路径(目录或文件)是否存在
11.isabs(path)
判断指定路径是否为绝对路径
12.isdir(path)
判断指定路径是否存在且是一个目录
13.isfile(path)
判断指定路径是否存在且是一个文件
14.islink(path)
判断指定路径是否存在且是一个符号链接
15.ismount(path)
判断指定路径是否存在且是一个挂载点
16.samefile(path1, paht2)
判断path1和path2两个路径是否指向同一个文件
十三、pickle模块
以二进制保存数据
三步走:打开文件,用pickle.dump()方法将数据放入文件,关闭文件
1 import pickle
2 my_list = [1,2,'老王',['abc']]
3 pickle_file = open('my_list.pkl','wb') #文件名后缀无所谓
4 pickle.dump(my_list,pickle_file)
5 pickle_file.close()
这样文件夹中就保存了my_list.pkl文件,(查询当前目录是用 import os os.getcwd())
读取数据
打开文件,调用pickle.load()方法
pickle_file = open('my_list.pkl','rb')
list2 = pickle.load(pickle_file)
print(list2)
十四、异常
常见异常类型:
AttributeError:属性错误,特性引用和赋值失败时会引发属性错误
NameError:试图访问的变量名不存在
SyntaxError:语法错误,代码形式错误
Exception:所有异常的基类,因为所有python异常类都是基类Exception的其中一员,异常都是从基类Exception继承的,并且都在exceptions模块中定义。
IOError:一般常见于打开不存在文件时会引发IOError错误,也可以解理为输出输入错误
KeyError:使用了映射中不存在的关键字(键)时引发的关键字错误
IndexError:索引错误,使用的索引不存在,常索引超出序列范围,什么是索引
TypeError:类型错误,内建操作或是函数应于在了错误类型的对象时会引发类型错误
ZeroDivisonError:除数为0,在用除法操作时,第二个参数为0时引发了该错误
ValueError:值错误,传给对象的参数类型不正确,像是给int()函数传入了字符串数据类型的参数。
捕获异常
try语句一旦被检测出异常,剩下的语句将不会被执行
几种搭配:
1.try except
1 try:
2 sum = 1/0
3 except ZeroDivisionError:
4 print('出错')
可以指明出错原因:
1 try:
2 sum = 1/0
3 except ZeroDivisionError as reason:
4 print('出错,错误原因:',str(reason))
可以用多个except语句:
1 try:
2 f = open("nofile.txt")
3 sum = 1/0
4 except IOError as reason:
5 print('出错,错误原因:',str(reason))
6 except ZeroDivisionError as reason:
7 print('出错,错误原因:',str(reason))
可以用一个元组捕获多个异常:
1 try:
2 sum = 1/0
3 f = open("nofile.txt")
4 except (IOError,ZeroDivisionError) as reason:
5 print('出错,错误原因:',str(reason))
用while True 和 else 组合,else后的语句在没有异常的情况下才执行,注意缩进,输入错误后会重新输入直到正确:
1 while True:
2 try:
3 x = int(input("input first num"))
4 y = int(input("input first num"))
5 z = x/y
6 print(z)
7 except ZeroDivisionError:
8 print("error,try again")
9 else:
10 break
不管try语句中是否发生异常,finally语句后都会执行:
1 try:
2 x = int(input("input first num"))
3 y = int(input("input first num"))
4 z = x/y
5 print(z)
6 except ZeroDivisionError:
7 print("error:")
8 finally:
9 print("结束")
十五、else语句及简洁的whith语句
else:
if-else语句:
和各种语言相同的用法,在条件语句中,与if语句搭配使用的else语句。如果if语句的条件表达式的结果布尔值为假,那么程序将执行else语句后的代码。
elif(else-if)语句:
elif是python提供的else-if语句,它检查多个条件表达式的值是否为真,并在为真时执行特定代码块中的代码。和else一样,elif是可选的,但是要注意的是,一个if语句可以跟多个elif语句,但最后只能有一个else语句
while-else/for-else语句:
在其他语言中,除了条件语句,是不会见到else分支的,但在Python中,while和for循环中,也是可以使用else语句的。它们的工作顺序为:在循环中使用时,else语句只在循环完成后执行,也就是说,break语句也会跳过else代码块,只要循环是正常结束,而不是通过break,else语句就会执行
求素数:
1 def fun(num):
2 count = int(num/2)
3 while count>1:
4 if(num%count == 0):
5 print("%d的最大公约数是:%d" %(num,count))
6 break
7 count -= 1
8 else:
9 print("%d是素数" %num)
10
11 n = int(input("请输入一个整数:"))
12 fun(n)
执行结果:
注意:Python中没有自增自减运算符,格式化输出多个字符要用元组的形式
try-else语句:
对于python中的错误和异常,try-except语句段,也可以和else连用,其功能和循环中的else语句没有多大区别:在try范围内没有检测到异常的时候,执行else子句。
with:
这个语法是用来代替传统的try...finally语法的。
with EXPRESSION [ as VARIABLE] WITH-BLOCK
1 try:
2 with open("e://1.txt",'r') as f:
3 for each_line in f:
4 print(each_line)
5 except IOError as reason:
6 print("Error:",str(reason))
如果用finally,若是文件不存在,也要走f.close(),这样的话文件存在打开后会自动关闭
十六、图形用户界面入门
1.动动手
0.先练练手,把我们的刚开始的那个猜数字小游戏加上界面吧?
import easygui as g
import random
g.msgbox('嗨,欢迎进入第一个界面小游戏!')
secret = random.randint(1,10)
msg = "猜猜我心中的数字是什么(0~10):"
title = "数字小游戏"
guess = g.integerbox(msg, title, lowerbound = 0, upperbound = 10)
while True:
if guess == secret:
g.msgbox('你是我肚里的蛔虫吗!')
break
else:
if guess > secret:
g.msgbox('猜大了呀,再试试')
else:
g.msgbox('猜小了呀,再试试')
guess = g.integerbox(msg, title, lowerbound = 0, upperbound = 10)
g.msgbox('游戏结束,不玩啦!')
1.实现一个用于登记用户账号信息的界面(如果是带*号的必填项,要求一定要有输入并且不能是空格)。
from easygui import *
msg = "输入你的个人信息"
title = "登录界面"
fieldNames = ["账号名*","密码*","地址","联系电话*","邮箱地址"]
fieldValues = [] # 创建一个空列表存放账号信息
fieldValues = multenterbox(msg,title, fieldNames)
# 确保带*号的信息不为空
while 1:
if fieldValues == None:
break
errmsg = ""
for i in range(len(fieldNames)):
if (fieldValues[i].strip() == "") and (fieldNames[i][-1] == "*"):
errmsg = errmsg + ('"%s" 是必填项.\n\n' % fieldNames[i])
if errmsg == "":
break
fieldValues = multenterbox(errmsg, title, fieldNames, fieldValues)
print("个人信息:", fieldValues)
2.提供一个文件浏览框,让用户选择需要打开的文本文件,打开并显示文件内容。
import easygui as g
import os
file_path = g.fileopenbox(default = "*.txt")
with open(file_path) as f:
title = os.path.basename(file_path)
msg = "文件【%s】的内容如下:" %title
text = f.read()
g.textbox(msg, title, text)
3.在上一题的基础上增强功能:当用户点击“OK”按钮的时候,比较当前文件是否修改过,如果修改过,则提示“覆盖保存”、“放弃保存”或“另存为…”并实现相应的功能。
import easygui as g
import os
file_path = g.fileopenbox(default = "*.txt")
with open(file_path) as old_file:
title = os.path.basename(file_path)
msg = "文件【%s】的内容如下:" %title
text = old_file.read()
text_after = g.textbox(msg, title, text)
if text != text_after[:-1]:
#textbox的返回值会追加一个换行符
choice = g.buttonbox("文件已修改,请做出选择:", "警告", ("覆盖保存", "放弃保存", "另存为…"))
if choice == "覆盖保存":
with open(file_path, "w") as old_file:
old_file.write(text_after[:-1])
if choice == "放弃保存":
pass
if choice == "另存为…":
another_path = g.filesavebox(default = ".txt")
if os.path.splitext(another_path)[1] != '.txt':
another_path += '.txt'
with open(another_path, "w") as new_file:
new_file.write(text_after[:-1])
4.写一个程序统计你当前代码量的总和,并显示离十万行代码量还有多远?
要求一:递归搜索各个文件夹
要求二:显示各个类型的源文件和源代码数量
要求三:显示总行数与百分比
import easygui as g
import os
def show_result(start_dir):
lines = 0
total = 0
text = ""
for i in source_list:
lines = source_list[i]
total += lines
text += "【%s】源文件 %d 个,源代码 %d 行\n" % (i, file_list[i], lines)
title = '统计结果'
msg1 = '您目前共写了 %d 行代码,完成进度:%.2f %%\n离10万行代码还差 %d 行,请继续努力!' % (total, total/1000, 100000 - total)
msg2 = '您目前共写了 %d 行代码,完成进度:%.2f %%\n超额完成 %d 行,真棒!' % (total, total/1000, total - 100000)
if total <= 100000:
g.textbox(msg1, title, text)
else:
g.textbox(msg2, title, text)
def calc_code(file_name):
lines = 0
with open(file_name) as f:
print('正在分析文件:%s ...' % file_name)
try:
for each_line in f:
lines += 1
except UnicodeDecodeError:
pass
return lines
def search_file(start_dir):
os.chdir(start_dir)
for each_file in os.listdir(os.curdir):
ext = os.path.splitext(each_file)[1]
if ext in target:
lines = calc_code(each_file)
try:
file_list[ext] += 1
except KeyError:
file_list[ext] = 1
try:
source_list[ext] += lines
except KeyError:
source_list[ext] = lines
if os.path.isdir(each_file):
search_file(each_file)
os.chdir(os.pardir)
target = ['.c', '.cpp', '.py', '.cc', '.java','.pas', '.asm']
file_list = {}
source_list = {}
g.msgbox("请打开您存放所有代码的文件夹......", "统计代码量")
path = g.diropenbox("请选择你的代码库:")
search_file(path)
show_result(path)
十七、类和对象
类:
–封装(数据,函数)
–对象也是封闭,模拟真实世界
–从表态分类,从动作分类.,也就是属性和方法.属性+方法=对象
–属性可以理解为变量,方法可能理解为函数.
–类,实例对象. 类就是为了量产对象.
–类命名大写字母开头
OO的特征:OO = Object Oriented 面向对象
1.封闭 ,信息隐蔽技术.
2.继承,继承别的类的方法和属性
3.多态,不同对象对同一方法响应的行动.
对象:
1.self是什么?
–定义的时候必须写在函数的第一个参数
例:
class Ball:
def setName(self, name):
self.name = name
def kick(self):
print(‘我叫s%,谁踢我…’% self.name)
a = Ball
a.setName(‘1’)
b = Ball
b.setName(‘2’)
c = Ball
c.setName(‘3’)
–>a.kick()
–>b.kick()
–>c.kick()
2.魔法方法
init(self) 构造方法
例:
class Ball:
def init(self, name)
self.name =name
def kick(self):
print(‘我叫s%,谁踢我…’% self.name)
b = Ball(‘222’)
b.kick()
3.公有和私有
–对象的属性和方法都是公有的
例:
class Person:
name = ‘xx’
p = Person()
p.name
私有:
在Python中定义私有变量只需要在变量名或函数名前加上’__’两个下划线,
那么这个函数或变量就会为私有的了.
class Person:
__name = ‘xx’
p = Person()
p.name # 就调用不出来了.须要加上下面的语句
def getName(self):
return self.__name
p.getName() # 这样就可以调用
其实Python把__name改为了p._person__name来存储,所以找不到了.
4.继承:
–对于相似的类,就可以继承
语法: class 类名(父类名):
例:
class Parent(object):
def hello(self):
print(‘正在调用父类方法’)
class Child(Parent):
p = Person
p.hello()
c = Child()
c.hello()
如果子类中定义与父类同名的方法或属性,则会自动覆盖浆糊对应的方法或属性.
class Child(Parent):
def hello(self):
print(‘正在调用子类的方法…’)
这样就会覆盖掉子类的方法.
例:
import random as r
class Fish:
def init(self):
self.x = r.randint(0, 10)
self.y = r.randint(0, 10)
def move(self):
self.x -= 1
print(‘我的位置是:’,self.x, self.y)
class Goldfish(Fish):
pass
class Carp(Fish):
pass
class Salmon(Fish):
pass
class Shark(Fish):
def init(self):
self.hungry = True
def eat(self):
if self.hungry:
print(‘吃吃吃吃吃~~’)
else:
print(‘我特么不饿~~~’)
开始调用:
fish = Fish()
fish.move()
fish.move()
goldfish = Goldfish()
goldfish.move()
goldfish.move()
shark = Shark()
shark.eat()
shark.eat()
shark.move() # 这样会出错,因为子类的 def__int__(self)覆盖了父类的def__init__方法所以没有坐标了.
所以就要腹用如下方法:
-调用未绑定的父类方法
在__init__下加入:
Fish.__init__(self) # 这就是未绑定的父类方法.这里的self代表shark
-使用super函数
只要写 super().__init__() 就可以了. 这种更方便好用.
好处是不用给出父类的名字
!!#!#!#!#!!这里没听懂!!!!
多重继承:
class Base1:
def foo1(self):
print(‘1’)
class Base2:
def foo2(self):
print(‘2’)
class Base3(Base1, Base2)
pass
c = Base3()
c.foo1
c.foo2
上面就是多重继承,但是如果不是已经明确的了解就不要使用.
多重继承容易导致不可预见的BUG,对于程序来讲不可预的BUG几乎就是致命的
类的组合
类之间没用明显继承关系可以用组合,比如一个电话簿的类由电话和地址类组合起来:
1 class Tel:
2 def __init__(self,x):
3 self.info = x
4
5 class Add:
6 def __init__(self,y):
7 self.info = y
8
9 class Notebook:
10 def __init__(self,x,y):
11 self.tel = Tel(x)
12 self.add = Add(y)
13 def print_info(self):
14 print("Tel:%s\nAdd:%s" %(self.tel.info,self.add.info))
类 类对象 实例对象
类对象就像C++中的static变量,一个对象有了实例对象后就将类对象的值覆盖了
属性名如果和方法名相同,属性会覆盖方法
绑定
对象.__dict__返回对象拥有的属性
对象调用后方法绑定到实例对象上del类后,a的方法还是存在的,因为A的方法和属性都是static,程序退出前不会消失
一些和类相关的BIF
issubclass(class, classinfo)
isinstance(object, classinfo)
hasattr(object, name) 注意第二个参数要用字符串格式
getattr(object, name[, default])
setattr(object, name, value) 设置属性
delattr(object, name) 删除属性,属性不存在抛出异常
property()
为什么用property
首先一个实例化的对象可以进行直接的赋值和修改,如c.age = 10,但是这样没法做参数检查,我就可以让c.age = 1000,这显然是不合理的
于是,用方法可以对参数进行检查,可以用c.setage(66)来设置年龄,但是这样就不方便了
函数property的基本功能就是把类中的方法当作属性来访问,为什么用方法来操作
1 class C:
2 def __init__(self,age = 10):
3 self.age = age
4 def getage(self):
5 return self.age
6 def setage(self,value):
7 if 0 <= value <= 120:
8 self.age = value
9 else:
10 print("年龄非法")
11 def delage(self):
12 del self.age
13 x = property(getage,setage,delage)