class Student: # 定义Student类,有两个属性name和age
name=None
age=None
stu1 = Student() # 创建对象stu1,包含student中的两个属性name和age
stu2 = Student() # 创建对象stu2
stu1.name="jack" # 赋值
stu1.age=18
stu2.name="peter"
stu2.age=17
print(stu1.age) # 18
print(stu2.name) # peter
(1)成员变量:在类中定义的变量/属性叫成员变量
(2)成员方法:在类中定义的函数/行为叫成员方法,类外定义的函数仍叫做函数
在成员方法中必须使用self,在成员方法中访问成员变量也必须使用self;对于只有self的成员方法,调用时可按照无参处理;对于有多个参数的成员方法,调用时可忽略self传参
class Student():
name=None
age=None
def f1(self): # 成员方法
print(self.name) # 在成员方法中访问成员变量必须使用self
def f2(self,x): # 成员方法
print(self.name)
print(x)
stu=Student() # 定义对象stu
stu.name="jack"
stu.f1() # 调用f1
stu.f2("hello") # 调用f2
"""输出
jack
jack
hello
"""
用 _ _ init_ _(self) 表示构造方法,在创建对象时,构造方法会自动执行
class Student():
name=None
age=None
def __init__(self): # 构造方法
print(1)
stu=Student() # 创建对象
# 输出:1
创建对象时,可将参数传递给构造方法。例如在创建对象时完成赋值
class Student():
name=None
age=None
def __init__(self,name,age): # 构造方法
self.name=name # 传入的name给stu的name赋值
self.age=age
stu=Student("jack",18) # 创建对象stu时赋值
print(stu.name) # 输出:jack
以上代码可进一步简化,在构造方法中对name和age创建并赋值
class Student():
# name=None
# age=None
def __init__(self,name,age):
self.name=name
self.age=age
stu=Student("jack",18)
print(stu.name)
init、str、lt、gt、le、eq
通过使用 _ _ str _ _可返回特定的字符串
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return f"hello,{self.age}岁的{self.name}" # 返回特定的字符串
a=A("jack",18)
print(a) # hello,18岁的jack
lt对应的是小于号“<”,可通过lt方法指明比较的对象
若lf方法内仍为小于号,则正常比较
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __lt__(self,x): # 明确比较的是age;此处的self和x并非关键字,可任意替换
return self.age<x.age # 小于号,正常比较
a1=A("jack",18)
a2=A("peter",17)
a3=A("nihao",16)
print(a1>a2) # True
# a1当做self传入,a2当做x传入
# 正常比较:a1的age>a2的age为True
print(a1<a3) # False
# 正常比较:a1的age
若lf方法内改为大于号,则比较结果相反
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __lt__(self,x):
return self.age>x.age # 改为大于号
a1=A("jack",18)
a2=A("peter",17)
print(a1>a2) # Flase
# a1的age>a2的age,但输出False
print(a1>=a2) # TypeError: '>=' not supported,可使用下文的le比较
对应大于号,若gt方法内仍为大于号则正常比较,否则结果相反
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __gt__(y,x):
return y.age>x.age # gt大于号正常比较
a1=A("jack",18)
a2=A("peter",17)
print(a1>a2) # True
对应小于等于
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __le__(self,x):
return self.age<=x.age # 小于等于,正常比较
a1=A("jack",18)
a2=A("peter",17)
a3=A("nihao",18)
print(a1>=a2) # True
print(a1>=a3) # True
print(a1<a2) # TypeError:le只能比较≤或≥
若le方法中改为≥,则结果相反(相等的不反)
class A:
def __init__(self,name,age):
self.name=name
self.age=age
def __le__(self,x):
return self.age>=x.age # 大于等于号,结果相反
a1=A("jack",18)
a2=A("peter",17)
a3=A("nihao",18)
print(a1>=a2) # False
print(a1>=a3) # True
判断对象的指定属性是否相等
class A:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(x,y):
return x.age == y.age
a1 = A("jack", 18)
a2 = A("peter", 17)
a3 = A("aaa", 18)
print(a1 == a2) # Flase
print(a1 == a3) # True
如果直接比较而不使用eq方法,则比较的是两个对象的内存地址,一定不同,返回False
class A:
def __init__(self, name, age):
self.name = name
self.age = age
# def __eq__(x,y):
# return x.age == y.age
a1 = A("jack", 18)
a2 = A("peter", 18)
print(a1 == a2) # Flase
私有属性在类外部无法直接进行访问
_ _ 变量 # 私有变量
_ _ 方法 # 私有方法
class A:
name="jack"
__age=18 # 私有变量
def f1(self):
print(1)
def __f2(self): # 私有方法
print(2)
a=A()
print(a.name) # jack
print(a.__age) # AttributeError: 'A' object has no attribute '__age'
a.f1() # 1
a.__f2 # AttributeError: 'A' object has no attribute '__f2'
类内访问
class A:
__age=18
def f(self):
print(self.__age) # 类内可以访问私有变量
a=A()
a.f() # 18
class Phone:
__is_5g_enable=None
def __check_5g(self,x):
self.__is_5g_enable=x
if self.__is_5g_enable:
print("5g开启")
else:
print("5g关闭,使用4g网络")
def call_by_5g(self,x):
self.__check_5g(x)
print("正在通话中")
phone=Phone()
phone.call_by_5g(True)
phone.call_by_5g(False)
"""
5g开启
正在通话中
5g关闭,使用4g网络
正在通话中
"""
class Phone:
__is_5g_enable=True
def __check_5g(self):
if self.__is_5g_enable:
print("5g开启")
else:
print("5g关闭,使用4g网络")
def call_by_5g(self):
self.__check_5g()
print("正在通话中")
phone=Phone()
phone.call_by_5g()
"""
5g开启
正在通话中
"""
class People:
name = None
age = None
__weight = None # 子类无法直接访问私有属性
def __init__(self,n,a,w): # 构造方法
self.name=n
self.age=a
self.__weight=w
def speak(self):
print("我叫%s,今年%d岁" % (self.name,self.age))
class Student(People): # Student继承People
grade = None
def __init__(self,n,a,w,g):
People.__init__(self,n,a,w) # 调用父类的构造方法
self.grade=g # 添加新功能
def speak(self): # 重写父类的方法
print("我叫%s,今年%d岁,考了%d分"%(self.name,self.age,self.grade))
print(self.__weight) # error
s=Student("jack",18,200,100)
s.speak()
"""
我叫jack,今年18岁,考了100分
AttributeError: 'Student' object has no attribute '_Student__weight'
"""
class People:
name = None
age = None
__weight = None # 子类无法直接访问私有属性
def __init__(self,n,a,w):
self.name=n
self.age=a
self.__weight=w
def speak(self):
print("我叫%s,今年%d岁" % (self.name,self.age))
class Student(People): # Student继承People
grade = None
def __init__(self,n,a,w,g):
People.__init__(self,n,a,w) # 调用父类的构造方法
self.grade=g
def speak(self): # 重写父类的方法
print("我叫%s,今年%d岁,考了%d分"%(self.name,self.age,self.grade))
class Speaker:
topic=None
name=None
def __init__(self,n,t):
self.name=n
self.topic=t
def speak(self):
print("我叫%s,我演讲的主题是%s"%(self.name,self.topic))
class Sample(Speaker,Student): # Sample类继承Speaker和Student
def __init__(self,n,a,w,g,t):
Student.__init__(self,n,a,w,g)
Speaker.__init__(self,n,t)
sample=Sample("jack",18,200,100,"nihao")
sample.speak() # Student和Speaker都有speak方法,会调用先继承的方法(排在前面的)Speaker
"""输出
我叫jack,我演讲的主题是nihao
"""
①在类外调用父类
class A:
name="jack"
class B(A):
name="peter" # 子类重写父类的变量
b=B()
print(b.name) # peter
# 调用父类方式1:使用super(子类,子类对象).变量 的方式可以访问父类的属性
print(super(B,b).name) # jack
#调用父类方式2
print(A.name) # jack
②在子类调用父类
class A:
name="jack"
class B(A):
def f(self):
name="peter" # 子类重写父类的属性
print(name)
print(super().name) # 方式一:在子类中使用super可以省略参数
print(super(B,b).name) # 方式二:不省略参数
print(A.name) # 方式三
b=B()
b.f()
"""
peter
jack
jack
jack
"""
①在类外调用父类
class A:
def f(self):
return 1
class B(A):
def f(self):
return 2
b=B()
print(b.f()) # 2
print(super(B,b).f()) # 1 调用了父类的方法
②在子类调用父类
class A:
def f(self):
self.name="jack"
class B(A):
def f(self):
self.name = "peter"
print(self.name)
super().f() # 方式一:调用了父类的方法,给name赋值jack
print(self.name)
self.name = "peter"
print(self.name)
A.f(self) # 方式二:使用此方法调用必须加self
print(self.name)
b=B()
b.f()
"""输出
peter
jack
peter
jack
"""
用途:帮助IDE对代码类型判断、便于查看(备注)
在冒号后面指明类型
x:int =10 # x是int型的变量,值为10
y:float=2.5
x1:list=[1,2,3] # x1是list型
x2:list[int] =[1,2,3] # x2是list型,里面的元素是int型
x3:tuple[str,int,bool]=("hello",18,True)
x4:dict[str,int]={"hello",18}
注释注解
注明a和b的类型,便于IDE识别
通过"->"指明函数的返回值类型
def add(a,b) -> int:
return a+b
from typing import Union
a=[1,2,"jack",3] # 普通定义列表
b:list[Union[str,int]]=[14,23,"jackw",4]
# 指明b是一个列表,由str和int类型的数据联合组成
c=dict[str,Union[str,int]]={"name":"jack","age":18}
# 字典,键str,值str和int组成
对于函数同样可以使用Union
多态指对于某个行为,不同对象有不同反应,很好地解决了函数的重名问题
class Animal: # 抽象类
def speak(self): # 抽象方法
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def shout(x):
x.speak()
dog=Dog()
cat=Cat()
shout(cat) # 喵喵喵
shout(dog) # 汪汪汪
# 同样的shout函数,传入的对象不同,会得到不同的结果
在此形式中,父类只需要定义方法,而子类负责实现。我们把这种方法体是pass的方法叫做抽象方法,把含有抽象方法的类叫做抽象类。可以看出,抽象类不能独立工作,也不会去构建对象,它必须被子类继承并重写后才有意义。
数据获取下载
有2份数据文件,计算每日的销售额并以柱状图表的形式进行展示(如下图),要求使用面向对象的思想
参考思想如下:
①设计一个类,完成对数据的封装
②设计一个抽象类,定义文件读取的相关功能,并用子类实现具体功能
③读取文件,生成数据对象
④计算每一天的销售额
⑤图像绘制
文件2:JSON格式
[解]
1.新建包和main文件
创建data_define.py文件,在类中对数据进行封装
class Data:
def __init__(self,date,ID,price,province):
self.date=date
self.ID=ID
self.price=price
self.province=province
2.定义抽象类和子类
创建文件相关定义file_define.py
定义抽象类
class FileReader:
def read_data(self): # 抽象方法
pass
针对文件1:字符串文件的处理,继承父类,重写方法
class File1(FileReader): # 针对文件1:字符串类文件
def __init__(self, path):
self.path = path # path存放文件路径
def read_data(self):
f = open(self.path, "r", encoding="UTF-8")
Data_list = [] # 用于存放数据
for x in f.readlines():
x = x.strip() # 处理每一行数据后面的换行符
a_list = x.split(",") # 数据分割存入a
data=Data(a_list[0], a_list[1], int(a_list[2]), a_list[3]) # 调用Data函数赋值
Data_list.append(data) # 存入列表
f.close()
return Data_list
针对文件2:JSON文件的处理,继承父类,重写方法
class File2(FileReader):
def __init__(self, path):
self.path = path # path存放文件路径
def read_data(self):
f = open(self.path, "r", encoding="UTF-8")
Data_list = [] # 用于存放数据
for x in f.readlines():
a_dict=json.loads(x)
data=Data(a_dict["date"],a_dict["order_id"],int(a_dict["money"]),a_dict["province"]) # 通过键获取值,进行赋值
Data_list.append(data)
f.close()
return Data_list
3.读取文件,生成数据对象
在main.py中
from data_define import Data
from file_define import FileReader,File1,File2
file1=File1("D:/面向对象资料1/2011年1月销售数据.txt")
file2=File2("D:/面向对象资料1/2011年2月销售数据JSON.txt")
ffile1=file1.read_data() # 调用方法,进行处理
ffile2=file2.read_data() # 调用方法,进行处理
all_data=ffile1+ffile2 # 全部数据整合到了列表中
4.计算每一天的销售额
在main.py中
data_dict={} # 用字典存储数据(字典的键是不能重复的)
for x in all_data:
if x.date in data_dict.keys(): # 如果当前数据的日期在data_dict字典中,进行累加
data_dict[x.date]+=x.price # 在字典中根据键查找对应的值,累加money
else: # 当前数据不在字典中,创建新键值
data_dict[x.date]=x.price
输出:{‘2011-01-01’: 59242, ‘2011-01-02’: 58479, ‘2011-01-03’: 52336, ‘2011-01-04’: 35696, ‘2011-01-05’: 58860…
5.绘图
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
from pyecharts.options import TitleOpts, LabelOpts, InitOpts
bar=Bar(init_opts=InitOpts(theme=ThemeType.LIGHT)) # 颜色
bar.add_xaxis(list(data_dict.keys())) # x轴为日期,需要转成列表
bar.add_yaxis("销售额",list(data_dict.values()),label_opts=LabelOpts(is_show=False)) # "销售额"为图例,y轴为销售额,不显示每个柱状图的数据
bar.set_global_opts(
title_opts=TitleOpts(title="每日销售额") # 标题
)
bar.render("每日销售额柱状图.html")
6.完整代码
main.py
from pyecharts.charts import Bar
from pyecharts.globals import ThemeType
from pyecharts.options import TitleOpts, LabelOpts, InitOpts
from file_define import File1,File2
file1=File1("D:/面向对象资料1/2011年1月销售数据.txt")
file2=File2("D:/面向对象资料1/2011年2月销售数据JSON.txt")
ffile1=file1.read_data() # 调用方法,进行处理
ffile2=file2.read_data() # 调用方法,进行处理
all_data=ffile1+ffile2
data_dict={} # 用字典存储数据
for x in all_data:
if x.date in data_dict.keys(): # 如果当前数据的日期在data_dict字典中,进行累加
data_dict[x.date]+=x.price # 在字典中根据键查找对应的值,累加money
else: # 当前数据不在字典中,创建新键值
data_dict[x.date]=x.price
# 绘图
bar=Bar(init_opts=InitOpts(theme=ThemeType.LIGHT)) # 颜色
bar.add_xaxis(list(data_dict.keys())) # x轴为日期,需要转成列表
bar.add_yaxis("销售额",list(data_dict.values()),label_opts=LabelOpts(is_show=False)) # "销售额"为图例,y轴为销售额,不显示每个柱状图的数据
bar.set_global_opts(
title_opts=TitleOpts(title="每日销售额") # 标题
)
bar.render("每日销售额柱状图.html")
data_define.py
class Data:
def __init__(self,date,ID,price,province):
self.date=date
self.ID=ID
self.price=price
self.province=province
file_define.py
import json
from data_define import Data
class FileReader:
def read_data(self):
pass
class File1(FileReader): # 针对文件1:字符串类文件
def __init__(self, path):
self.path = path # path存放文件路径
def read_data(self):
f = open(self.path, "r", encoding="UTF-8")
Data_list = [] # 用于存放数据
for x in f.readlines():
x = x.strip() # 处理每一行数据后面的换行符
a_list = x.split(",") # 数据分割存入a
data=Data(a_list[0], a_list[1], int(a_list[2]), a_list[3]) # 调用Data函数赋值
Data_list.append(data) # 存入列表
f.close()
return Data_list
class File2(FileReader):
def __init__(self, path):
self.path = path # path存放文件路径
def read_data(self):
f = open(self.path, "r", encoding="UTF-8")
Data_list = [] # 用于存放数据
for x in f.readlines():
a_dict=json.loads(x)
data=Data(a_dict["date"],a_dict["order_id"],int(a_dict["money"]),a_dict["province"]) # 通过键获取值,进行赋值
Data_list.append(data)
f.close()
return Data_list
效果图