变量
注意看代码注释!
题外话:Python作为“胶水”语言、兼容性很强,不是因为Python本身很厉害,是因为社区环境很好
字符串操作
使用[]方便的分割字符串:
会切割字符串内[“起始位置” : “结束位置(不包含)”]的字符
输入方式多样,输入负数即会反向切割
输入第三参数会 步进一段距离切割/反向表示切割内容
#字符串索引、切片、自带的函数测试
s = "abcdefghigklmno"
#使用索引获取元素
print("获取元素")
print( s[0] )
#两种使用索引拿到最后一个的元素的方式
print( s[len(s) - 1 ] )
print( s[-1] )
#使用索引进行切片
print("进行切片")
print( s[ : ] )#:左右什么都不写,会将字符串完整保留
print( s[0:1] )#左开右闭进行选择,只拿到第一个元素
print( s[1:5] )
print( s[0:12:2] )
"""切片时加入第二个引号代表:
①为正时,代表进行隔*个字符选择
②为负时,代表反向表示,但不能在已切片的情况下用"""
print("反向切片‘当索引为负时’")
print( s[-5:-1] )#由数字上的从小到大切片,方向依然从左到右
print("字符串的常见用法")
s = " tom "
print(len(s)) #获取长度
print(len(s.strip())) #去字符串前后的空格
s = s.strip()
print(s.capitalize()) #首字母大写
print(s.find("om")) #找指定字符位置
print(s.startswith("t")) #开头是不是这个?
print(s.endswith("m")) #结尾是不是这个?
print(s.center(11,"*")) #用填充字符使字符串居中
print(s.isdigit()) #是否只有数字
print(s.isalpha()) #是否只有字符
print(s.upper()) #转全大写!
print(s.lower()) #转全小写……
可改值/不可改值的区别(以字符串/StringIO为例)
可改值类型在效率上,秒杀不可改值
string(自带)、int等数值类型都是“不可改值”
list列表、set集合、dict字典都是“可改值”
#两种类型——可改值和不可改值——字符串的性能对比
#对可改值的字符串类型——StringIO模组的引入
#以及对时间模组——time的引入,注意两种不同的引入方式
from io import StringIO
import time
#开始时间和结束时间的定义,相减即可得到时间性能
start_time = time.time()
#s = "abc"
sio = StringIO("abc") #对可改值类型字符串的定义
#循环执行1000k万次更改操作
for i in range(10000000):
#s += "efg" #49.10713267326355
sio.write("efg") #1.8615856170654297
#对两种字符串类型的“添加”内容操作,注意不止是更改
end_time = time.time()
print( end_time - start_time)#输出的时间对比
原版string需要49秒
可改值StringIO只需1秒
列表+字典操作:数据库增删改查
注意列表中对键值对操作方式:
for i in students:
然后再i[‘score’]
'''
家庭作业:操作一个简单数据库
1、统计不及格学生的个数
2、打印所有男生的信息
3、计算女生的平均分
4、统计男生的最高分
5、查询手机尾号是2838的同学信息
'''
students = [
{'name':'Tom', 'age': 19, 'score': 92, 'sex': '女', 'tel':'15300022839'},
{'name':'Jerry', 'age': 20, 'score': 40, 'sex': '男', 'tel':'15300022838'},
{'name':'Andy', 'age': 18, 'score': 85, 'sex': '女', 'tel':'15300022837'},
{'name':'Jack', 'age': 16, 'score': 65, 'sex': '男', 'tel':'15300022428'},
{'name':'Rose', 'age': 17, 'score': 59, 'sex': '男', 'tel':'15300022653'},
{'name':'Bob', 'age': 18, 'score': 78, 'sex': '男', 'tel':'15300022867'} ]
not_great = 0 #不及格学生个数
famale_score = 0 #女生的平均分
Number_of_famale = 0 #女生总数
male_max_score = 0 #男生的最高分
tel_2838 = "" #电话号码为2838的学生信息
print("所有男生信息为:")
for i in students:
if(i['score'] < 60):
not_great += 1 #统计不及格人数
if(i['sex'] == '男'):
print(i) #统计男生个数
if(i['sex'] == '女'):
famale_score += i['score'] #统计女生总分
Number_of_famale += 1 #统计女生个数
if(i['sex'] == '男' and i['score'] >= male_max_score):
male_max_score = i['score'] #找出男生最高分
if(i['tel'][-4:] == "2838"):
tel_2838 = i #找到尾号2838的人,并保存他的信息
famale_score = famale_score/Number_of_famale #计算女生平均分
print("不及格学生个数:", not_great)
print("女生的平均分:", famale_score)
print("男生的最高分:", male_max_score)
print("电话号码为2838的学生信息:", tel_2838)
使用递归实现阶乘(重)、登录系统、lambda 懒人函数生成
注意:在这里展示的一种常见递归使用方式——在函数返回值中递归
#使用递归实现阶乘
def multiply_loop(c):
if c == 0:
return 0 #防止输入值为0
elif c == 1:
return 1 #当递减为1时,阻止递归继续递减,以防止全为零
elif c != 0:
return int(c * multiply_loop(c - 1)) #将输入值 和 比输入值小 1 的值相乘
print(multiply_loop(5))
#用户输入的登录系统,但信息存放到字典中
#以用户名为键、以密码为值、用户名不重复
database = {
"tom":"123"
}
def login_register():
#用于控制登录/注册的哨兵变量
mode = int(input("登录请按1、注册请按2"))
if mode == 1:
error_try = 0 # 试错次数
print("-登录模式-")
while (error_try < 3):
user_name = input("请输入用户名")
password = input("请输入密码")
# 当 存在此用户名 且 密码不匹配时 :
if database.get(user_name) and database.get(user_name) != password:
error_try += 1 #试错标记增加1
print("密码错误,还可以重试%d次!" % (3 - error_try))
# 当 不存在此用户名时 :
elif not database.get(user_name):
print("此用户名不存在,请重试")
else:
print("登录成功")
break
if (error_try > 3):
print("密码错误超过三次!")
if mode == 2:
print("-注册模式-")
while (mode == 2):
user_name = input("请输入用户名")
password = input("请输入密码")
# 当 找得到此用户名时 :
if database.get(user_name):
print("此用户名已存在,请重试")
else:
database[user_name] = password
print("成功注册,您注册的信息为:" + user_name + ":" + database[user_name])
break
print("当前数据库状态为", end="\t")
print(database)
#列表在函数中是否可变
list = [1, 2, 3]
def change_list(list):
list.append("4")#在列表中加入字符串的“4”
change_list(list)
print(list) #答案是:列表可以被函数直接改变
#lambda的使用
x = lambda a,b: a ** b #用lambda实现幂运算
print(x(2,8))
str_output = lambda a,b: print(str(a) + str(b)) #用lambda实现两段数据转化为字符串,并输出
str_output(90,"人")
#文件读取
import os #引入文件读取模块
path = "D:\\A_PyCharm\\PycharmProjects\\Day3_Test1" #指定路径以方便后续访问
file_list = os.listdir(path) #获取所有的文件列表
for f in file_list:
if os.path.isdir(path + f): #判断是否文件夹的方法(注意输入值是路径+文件本身)
print("这是文件夹" + os.getcwd() + "\\" + f)
if os.path.isfile(path + f): #判断是否是文件
print("这是文件" + os.getcwd() + "\\" + f)
面向对象:封装基础知识
注意类中的两大基础对立组合
类属性、对象属性(class=、self.class=)
类方法、对象方法(@classmethod def(cls)、def(self))
所有对象共享类属性、而每个类属性都只有唯一一个
所有对象的对象属性都独立
类方法可以直接用类来引用,对象方法必须得从实例化的对象中引用
三大隐式调用的自带函数__start__、__init __、__del __
(注意__start__是初始化函数、__init__是构造函数,
严格来说这两个合在一起才是“构造函数”,但__start__很少用)
以及一个少用的@staticmethod静态方法
#类的封装:基础方法
#基础方法有两个:__init__、__del__
#一个会在初始化类时自动使用,一个会在对象“生命周期结束时”自动使用
class Apple:
def __init__(self):
print("初始化函数__init__")
#小细节1:定义类时,函数与函数之间要空一行
#小细节2:每一个类中的方法都有一个叫 self 的输入值
def __del__(self):
print("析构函数__del__")
a = Apple()
#类的封装:self
#self代表“当前所有对象”,可以使用这个来内部访问所有变量/方法
#所有函数都以self为第一个参数
class Apple:
name = "apple"
def get_name(self):
print(self.name) #用self访问变量的例子
def display(self):
self.get_name() #用self访问函数
Apple().display() #直接使用类名来使用方法
#注意:类名后面有括号(),即代表“这是一个对象”
#在此基础上使用方法,都是通过对象来使用
#封装:__new__
#基础方法之一,这个才是真正的“构造函数”,init只是“初始化函数”
#严格意义上来说,new 和 init 合在一起才是完整的构造函数,
#一般不会手动去写__new__
#三个基础函数中,使用频率为:init > new > del
class Apple:
def __new__(cls):
return super().__new__(cls)
#注意上方的cls,这代表了当前这个新建的类,
#由于当前没有初始化完成,所以self现在还用不了
#同时,其中还出现了super(),这表示“使用基类”
def __init__(self):
print("初始化函数__init__")
def __del__(self):
print("析构函数__del__")
a = Apple() #此处的运行结果展示了三个基础函数的使用顺序
#①new、②init、③del
#封装:类属性
#特点是“全局,唯一”
#能被类名直接使用,也能被对象使用,结果都会得到保存
#注意:如果使用“不可变的类型”(如字符串、数字),会看不出来保存了的效果
#推荐使用列表、键值对等数据来当类属性
class Apple:
name = "tom"
l = [1, 2, 3] #全局、唯一
a = Apple()
print("对比:修改类属性的值,对于不可改值的str又会怎样")
print(id(Apple.name))
print(id(a.name))
a.name = "jack"
a.l += [4, 5, 6,]
print(id(Apple.name)) #两次id的对照可以看出
print(id(a.name)) #对于可变类型,“类属性”的更改确实可以被类、对象1、对象2访问
#封装:类属性的操作
#操作类属性时,只用在 类属性前+类名
#此例子展示的是:每次新建对象时,使一个类属性+1
class Student:
count = 0
def __init__(self):
Student.count += 1
@classmethod #@:一个"装饰器"
#classmethod:在此处的用法是,使这个方法变为“类方法”(不常用)
def get_count(self):
print("共有%d个学生" % Student.count)
s1 = Student()
s2 = Student()
Student.get_count() #结果为count=2
#定义为类方法,即可像这样直接通过类名来引用
#封装:对象属性
#类中的属性分为两种:类属性、对象属性
#对象属性即“只能被实例化的对象访问的属性”
class A:
def __init__(self, name = "Jerry", age = 18): #初始化的参数也可以有默认值
#声明对象属性,对象属性只能在方法中声明
#同时、对象属性在init中声明,最方便后续使用
self.name = name
self.age = age
a1 = A("tom", 18)
print(a1.name)
print(a1.age)
a2 = A()
print(a2.name)
print(a2.age) #对比可得,对象属性的不同之处
#封装:修饰器
class A:
#修饰器property把一个方法变成属性调用
@property
def counter(self):
return 10000
a = A()
print(a.counter) #可以作为一个变量直接使用
#封装:公有与私有(以__开头)
#默认情况下都是共有属性/方法
#加上__、外部就不能“直接”访问
class Apple:
i = 100 #公有变量
__j = 1000 #私有成员变量,外部不能访问
def test1(self):
print(self.i, "内部输出")
print(self.__j, "内部输出") #内部想用私有变量,没有问题
self.__test2() #内部想用私有方法,没问题
print("Apple.test1()")
def __test2(self):
print("Apple.__test1()")
a = Apple()
print(a.i , "外部输出")
a.test1() #借由方法的内部引用,我们可以读取到私有的属性和方法
#封装,私有实现揭秘1
#实际上Python做不到真的“私有”,它只是用一种特殊方法把属性/方法换了个名字
class A:
__name1 = "Tom"
def __test1(self):
self.__name2 = "Jerry"
print("__test1")
a = A()
#用“对象名._类名__私有名”,就可以使用私有化的属性/方法了
a._A__test1()
print(a._A__name1)
print(a._A__name2)
#封装:私有化实现揭秘2
class Apple:
__name = "tom" #私有类属性
def __init__(self):
self.__age = 18 #私有对象属性
def __test(self): #私有函数
print("__test()")
a = Apple()
a._Apple__test() #私有函数访问方式
print(a._Apple__name) #私有成员变量访问方式
print(a._Apple__age) #私有属性访问方式
#属性总体练习
#尝试使用__dict__,将所有属性以键值对的形式输出
class Apple:
count = 0 #类属性
def __init__(self,name,age,address):
self.name = name #对象属性
self.age = age #对象属性
self.address = address #对象属性
Apple.count += 1 #每有一个新对象初始化时,类属性count+=1(计算实例化了多少个类)
def display(self):
print("我叫%s,今年%d岁,我来自%s。" % (self.name, self.age, self.address))
a1 = Apple("Tom" , 18 ,"USA")
a1.display()
a2 = Apple("jerry", 19, "USA")
print(a1.count) #访问类属性,其数值会统一发生变化
print(a1.__dict__) #此处输出结果为:a1中所有可以访问的属性
print(a2.__dict__) #此处输出结果为:a2中所有可以访问的属性
print(A.__dict__) #此处输出结果为:类A中所有可以访问的属性
#封装扩展:类方法,纯扩展,不常用
class Apple:
#类方法(属于类,不属于对象)
@classmethod
def test(cls):
print("ClassMethod")
#类.方法名() 或者 对象.方法名()都可以访问类方法
Apple.test()
a = Apple()
a.test() #在这一部分中,请感受,类属性/对象属性和类方法/对象方法 的不同
#封装拓展:静态方法(生命周期长)
class Apple:
#静态方法:寄居在类中,独立存在,其中不能调用对象方法和类方法(类名.方法名()除外)
@staticmethod
def test():
print("ClassMethod")
#类.方法名() 可以访问静态方法
Apple.test() #不用实例化,直接使用
对对象属性,类属性,继承的总体练习
注意:
#在父类进行初始化时,通过引入参数(父类的init),对其对象属性进行设置
为什么不能修改父类的类属性?
为什么不能单个修改父类的对象属性:因为就是不能,要子类自己重写,覆盖父类的对象属性
#水果类、和他的两个苹果、香蕉子类
#两个水果子类有专属方法,卖()、吃()
class Furit:
sum = 0 #水果的总数
def __init__(self, weight = 0, color = "无", place = "未知"): #给水果父类设置默认值
self.weight = weight
self.color = color
self.place = place #产地
Furit.sum += 1 #每新建一个“水果”,"水果"总量+1
class Apple(Furit):
def __init__(self, price = 0, content = "normal"):
self.price = price #价格
self.content = content #好吃程度
#设置父类属性
super(Apple, self).__init__(20, "red", "佛罗里达州") #在父类进行初始化时,通过引入参数,对其对象属性进行设置
#为什么不能修改父类的类属性?
#为什么不能单个修改父类的对象属性:因为就是不能,要用自己重写
def buy(self):
return self.price
def eat(self):
return self.content
class Banana(Furit):
def __init__(self, price = 0, content = "normal"):
self.price = price #价格
self.content = content #好吃程度
#设置父类属性
super(Banana, self).__init__(40, "yellow", "密西西比州")
def buy(self):
return self.price
def eat(self):
return self.content
a = Apple(10, "好吃")
print("水果的总数", a.sum) #这个是父类的类属性
print("苹果的产地:", a.place)
print("苹果的重量:", a.weight) #这两个是父类的对象属性
print("苹果的好吃程度:", a.eat()) #这个是自己的方法访问自己的对象属性
b = Banana(50, "稍甜")
print("水果的总数", b.sum) #"水果"的总数随着新水果的建立而增多
print("香蕉的产地:", b.place)
print("香蕉的重量:", b.weight)
print("香蕉的价格:", b.buy())
#随机4位生成验证码,但是在类里
from random import randint
class RanCode:
def get_codes(self, l): #参数l决定需要的随机数大小
codes = ""
#使用字符串索引,直接获取值
s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for i in range(0, l): #注意range为左闭右开区间
code = s[randint(0, len(s) - 1)]
codes += code
return codes
r = RanCode()
print(r.get_codes(4))
#猜随机数游戏,但是在类里
class Random_Guess_number:
def __init__(self):
self.targetNumber = randint(0, 100) #目标
self.massage = "猜字游戏!猜一个100以内的数?"
#massag:需要输出的信息,外部会持续输出这个值,内部值更改这里 就可以改变输出
self.chance = 0 #猜的次数
def guess_time(self, i):
self.chance += 1
if i == self.targetNumber:
self.massage = "猜中了!!!!一共猜了%d次!" % self.chance
return "win" #通过函数返回值来判断输赢
elif i < self.targetNumber:
self.massage = "比目标值小,往大了猜"
self.save_chance(i) #福利机会,当猜错两次时,会给出与目标值的距离
return "mini"
else:
self.massage = "比目标值大,往小了猜"
self.save_chance(i)
return "huge"
def save_chance(self, now_number):
if(self.chance != 0 and self.chance % 2 == 0):
print("特别福利!现在距离目标值还差 %d 个数左右" % abs(now_number - self.targetNumber))
#abs函数:即绝对值函数
def unite(self):
while True:
print(self.massage) # 展示需要输出的信息
guess = int(input("来,猜个数")) # 记录输入值
if self.guess_time(guess) == "win": # 通过函数返回值来判断输赢
print(self.massage)
break
r = Random_Guess_number()
r.unite()
文件操作+类的封装
os.listdir():获取输入值中的所有目录
os.path.exists():检查输入值的在当前目录是否已经存在
os.mkdir():创建新文件夹
open():打开文件,有多种打开模式,"r"读、"w"写(覆盖)、“a”(追加)、“rb”(二进制读)、“wb”(二进制写)。此方法需要存入变量中才能正常使用
# update1:把项目封装到类里
# update2:当未排序完成时,提示使用顺序
# 文件分类任务:将多个文件、根据文件名备份到对应文件夹,并对备份的文件重命名为原文件名+时间的模式
# DocumentClassify方法:给定:输入文件夹、输出文件夹;使用下文两个方法进行排序
# classify方法:遍历所有文件,根据文件后缀的不同,创建多个文件夹,同时建立一个“集合”(不能重复)储存所有不同后缀文件夹
# 根据后缀,将备份放入不同文件夹,同时给后缀加上时间标志
# showList方法:展示输出文件夹状态
import time
import os
class DocumentClassify:
documentType = set() # 文件属性集合,创建空集合只能这样。不能使用 = {},因为={}是字典专属的方法
def __init__(self, chaos_path, classify_path):
self.chaosPath = chaos_path # 待排序文件夹
self.classifyPath = classify_path # 输出文件夹
self.chaosPathList = os.listdir(self.chaosPath) # 获取混乱文件夹列表下的所有文件,放入列表
def classify(self):
for i in self.chaosPathList: # 抓取待排序文件夹列表
if not os.path.exists(self.classifyPath + "/" + i[i.rfind(".") + 1:]): # 检查是否已经存在此种文件夹
DocumentClassify.documentType.add(i[i.rfind(".") + 1:]) # 向“文件种类”集合中添加不同的文件种类
os.mkdir(self.classifyPath + "/" + i[i.rfind(".") + 1:]) # 有新的种类被发现,创建对应的文件夹
for j in DocumentClassify.documentType: # 按照“文件种类”分类
if j == i[i.rfind(".") + 1:]: # 当文件种类匹配时,进行备份操作
old_file = open(self.chaosPath + "/" + i, "rb")
new_file_name = \
i[0: i.rfind(".")] + \
str(time.strftime("%Y%m%S", time.localtime())) + \
i[i.rfind("."):]
# 新文件名: 原文件名 + 格式化时间 + 原后缀
new_file = open(self.classifyPath + "/" + j + "/" + new_file_name, "wb")
# 新文件位置:分类文件夹 / 文件种类 / 新文件名
new_file.write(old_file.read()) # 读完就写
def show_list(self):
classify_path_list = os.listdir(self.classifyPath) # 获取整理好的分类文件夹目录
if classify_path_list:
for i in classify_path_list:
son_path = os.listdir(self.classifyPath + "/" + i) # 获取所有“文件类型”子目录
print("文件夹名", i, ":", end="")
for j in son_path:
print(j + "、", end="") # 按照格式输出
print()
else:
print("分类文件夹为空,请先使用classify()进行排序")
classify = DocumentClassify("混乱文件夹", "分类文件夹")
classify.classify()
classify.show_list()
print(classify.documentType)
高级特性(列表生成式、错误处理)
#列表生成式基本写法
list = [1, 2, 3]
print([i for i in list])
#列表生成式,待条件
print([i *3 for i in [1, 2, 3] if i >= 2])
print({ i : i*2 for i in [1, 2, 3]})
#异常检测:try与except
#实际使用中,应该避免在写try写很多东西,因为效率会很低
try:
i1 = int(input("请输入一个值"))
i2 = int(input("请输入第二个值"))
print("%d / %d = %0.2f" % (i1, i2, (i1 / i2)))
except :
print("warning!warning!")
# 完整的try except else finally
try:
10 * (1 / 0)
except ZeroDivisionError as error:
# 上面是:except 错误状态 as 存放错误码的地方
print(error) # 输出错误码
print("有异常的时候会执行的部分")
else:
print("没有异常时,执行的代码")
finally:
print("这句话,有没有异常")
# 线程: 多线程使用
import time
import threading
def display(count):
for i in range(1, count):
print(i, end="")
time.sleep(1)
for i in range(3):
s = threading.Thread(target=display, args=(5,))
# 启动线程,target是函数名,args是参数,为了防止有多个参数,多余的逗号必须留
# 我们在“Python”这个进程中,新建了“s”这几个线程
s.start()