1.初识对象:什么是数据的组织呢?组织数据就是把数据按照类别分到一起,例如要记录学生的信息,可以做一个表格:
这样把所有学生的姓名数据放到一起,进而实现数据的组织。在程序中,是可以做到和生活中的那样,设计表格,做表格,填写表格的。在程序中设计表格就是设计类(class),
class Student:
name None # 记录学生的姓名
在程序中做表格叫做创建对象:
# 基于类创建对象
stu_1 = Student()
stu_2 = Student()
在程序中填写表格就是对象属性赋值:
stu_1.name = "周杰伦" # 为学生1对象赋予名称属性值
stu_2.name = "林俊杰" # 为学生2对象赋予名称属性值
2.类的定义和使用:
可以看出:类不仅可以定义属性用来记录数据,也可以定义函数用来记录行为;其中类定义的属性(变量),可称之为:成员变量,类定义的行为(函数),可称之为成员方法。
成员方法的定义语法:在类中定义成员方法和定义函数基本一致,但有一些细微的区别。
def 方法名(self, 形参1,......,形参n):
方法体
可以看到,在类的成员方法定义的参数列表中,有一个:self关键词,这个关键词是成员方法定义时必须填写的,它用来表示类对象自身的意思,当使用类对象调用方法的是,self会自动被python传入,在方法内部,想要访问类成员的成员变量,必须使用self。但是,self关键字尽管在参数列表中,传参时依然可以忽略它。如下面代码:
class Student:
name = None
def say_hi(self):
print("Hello 大家好!")
def say_hi2(self,msg):
print(f"Hello 大家好, {msg}")
stu = Student()
stu.say_hi() # 调用的时候不需传参
stu.say_hi2("很高兴认识大家") # 调用的时候,需要传入msg参数
可以看到,在传入参数的时候,self是透明的,可以忽略的。
3.类和对象
在程序中我们要有用类描述现实世界事物的思想:现实事物也有属性和方法;事物名就是类的属性,事物要执行的行为就是类当中的方法,所以现实世界中的很多事物都可以用代码来表现出来。类和对象的关系: 类只是一种程序内的“设计图纸”,需要基于图纸生产实体(即对象),才能正常工作;这种套路就称之为:面向对象编程(使用对象进行编程)。如以下代码:
# 设置一个闹钟类
class clock: # 属性
id = None # 序列号
price = None # 价格
def ring(self): # 行为 响铃
import winsound #
winsound.Beep(2000, 3000) # 2000是闹钟的频率,3000是响铃的持续时间
# 构建2个闹钟
clock1 = clock() # 基于类创建对象
clock1.id = "0032"
clock1.price = "19.9"
print(f"闹钟id:{clock1.id},价格:{clock1.price}")
clock1.ring()
clock2 = clock() # 基于类创建对象
clock2.id = "0033"
clock2.price = "19.9"
clock2.ring()
print(f"闹钟id:{clock2.id},价格:{clock2.price}")
上面的代码创建了2个闹钟并实现它们的响铃行为。 4.构造方法:
Python类可以使用_init_()方法,称之为构造方法。使用这种方法它可以实现以下操作:(1)在创建类对象(即构造类的时候),会自动执行。(2)在创建类的时候,将传入的参数自动传递__init__()方法使用。 如以下的代码:
class Student:
name = None
age = None
telephone = None
def __init__(self, name, age, telephone):
self.name = name
self.age = age
self.telephone = telephone
print("Student创建了一个类对象")
stu = Student("周杰伦", 31, "190732162")
print(stu.name)
print(stu.age)
print(stu.telephone)
它的运行结果是:
从运行结果中我们可以看到“Student创建了一个类对象”放在最前面,说明了__init__()它有自动执行功能,而下面的“周杰伦,31,190732162”的出现说明了它会自动传入参数。
注意事项:1.构造方法名称:init,init前后都有2个下划线。2.构造方法也是成员方法,在参数列表中需要使用self关键字。3.在构造方法定义内定义成员变量,需要使用self关键字。
5.魔术方法:上面的__init__方法是python的内置方法之一,这些内置方法各有各的特殊功能,这些内置方法我们统称为:魔术方法。以下是要学习的一些常见的内置方法:
(1)字符串的方法:
内存地址没有多大的作用,可以通过__str__方法,来控制类转换为字符串的行为。
(2)lt()小于符号比较方法:
直接对2个对象比较是行不通的,但是在类中实现__lt__方法,就可以同时完成小于符号和大于符号2种比较了。方法名:lt;传入参数:other,另一个类对象;返回值:True或False;内容:自定义就好。
(4)__le__小于等于比较符号方法: __le__可用于>=和<=2种比较运算符上;方法名:le;传入参数:other,另一个类对象;返回值:True或False;内容:自定义即可。
(5)__eq__比较运算符实现方法
方法名:eq;传入参数:other,另一个类对象;返回值:True和False;内容:自行定义。注意:不实现__eq__方法,对象之间可以比较,但是比较的是内存地址,也就是不同对象比较一定是False。实现了__eq__方法,就可以按照自己的想法来决定2个对象是否相等了。
最后如以下代码:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self): # 字符串方法
return f"Student类对象,name:{self.name}, age:{self.age}" # 返回字符串
def __lt__(self, other): # 小于符号方法
return self.age < other.age
def __le__(self, other): # 小于等于符号方法 other是另一个类对象
return self.age <= other.age
def __eq__(self, other): # 等于符号方法
return self.age == other.age
stu = Student("周杰伦", 31)
print(stu)
print(str(str))
stu1 = Student("李荣浩", 30)
stu2 = Student("关晓彤", 25)
print(stu1 < stu2) # 结果是True
print(stu1 <= stu2) # 结果是True
print(stu1 == stu2) # 结果是True
面向对象的三大特性:封装,继承和多态。 面向对象编程是许多编程语言都支持的一种编程思想;即基于模板(类)去创建实体(对象),使用对象完成功能开发。
6.封装:封装表示的是,将现实世界事物的属性和行为封装到类中,描述为:成员变量和成员方法,从而完成程序对现实世界事物的描述。 私有成员:在现实生活中有些现实事物不能公开属性和行为,而在程序中类提供了私有成员的形式来支持。私有成员变量和方法:变量名和方法名都以2个下划线开头。注意:私有方法无法直接被类对象使用会报错,同样的私有变量无法赋值(即使赋值了不报错但也无效)也无法获取值。虽然私有成员无法被类对象使用,但是可以被其它的成员使用。如以下代码:
__current_voltage = 0.5 # 设置一个私有成员变量,当前手机运行电压
def __keep_single_core(self): # 设置一个私有成员方法
print("让cpu以单核模式运行")
def call_by_5g(self): # 设置类中另一个成员
if self.__current_voltage >= 1: # 在类的另一个成员中使用私有成员变量
print("5g通话已开启")
else:
self.__keep_single_core() # 在类的另一个成员中使用私有成员方法
print("电量不足,无法使用5g通话,并以设置为单核运行进行")
phone = Phone()
phone.call_by_5g()
7.继承 继承分为单继承和多继承。继承就是在原有的类上做出修改调整,复制父类的成员变量和方法(不含私有)。单继承语法:class 类名(父类名): 类内容体。多继承(即一个类,可以继承多个父类), 语法:class 类名(父类1,父类2,......,父类n):类内容体。如以下的代码:
# 单继承的演示
class Phone:
IMEI = None
producer = "HE"
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
face_id = "1011"
def call_by_5g(self):
print("2022年新功能:5g")
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
# 多继承的演示
class NFCReader:
nfc_type = "第五代"
producer = "HE"
def read_card(self):
print("NFC读卡")
def write_card(self):
print("NFC写卡")
class RemoteControl:
rc_type = "红外遥控"
def control(self):
print("红外遥控开启了")
class MyPhone(Phone, NFCReader, RemoteControl):
pass # pass只是一个普通的站位语句,用来保证函数或方法或者说类定义的完整性,表示无内容,空的意思。
phone = MyPhone()
phone.call_by_4g()
phone.read_card()
phone.write_card()
phone.control()
复写:子类继承父类的成员属性和成员方法后,如果对其"不满意",那么就可以进行复写,即在子类中重新定义同名的属性或方法即可。如下图所示:
调用复写父类的成员:一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员,如果需要使用被复写的父类成员,需要特殊的调用方式:(1)父类名.成员变量,父类名.成员方法(self)
(2)super().成员变量,super().成员方法()
IMEI = None
producer = "ITCAST"
def call_by_5g(self):
print("使用5g网络进行通话")
# 定义子类,复写父类成员
class MyPhone(Phone):
producer = "ITHEIMA"
def call_by_5g(self):
print("开启CPU单核模式,确保通话的时候省电")
# 调用父类成员
# 方式一
print(f"父类的厂商是:{phone.producer}")
Phone.call_by_5g(self)
# 方式二:
print(f"父类的厂商是:{super().producer}")
super().call_by_5g()
print("使用5g网络进行通话")
print("关闭CPU单核模式,确保性能")
phone = MyPhone()
phone.call_by_5g()
print(phone.producer)
8.多态 多态指的是多种形态,即完成某个行为时,使用不同的对象会得到不同的状态。
如下面代码的演示:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def make_noise(animal:Animal):
animal.speak()
# 演示多态,使用2个子类对象调用函数
dog = Dog()
cat = Cat()
make_noise(dog)
make_noise(cat)
从上面的代码中我们可以看到父类Animal的speak方法,是空实现;这种设计的含义是:父类用来确定有哪些方法和具体的方法实现由子类自行决定。这种写法,就叫做抽象类(也是接口)。那么什么是抽象类呢?含有抽象方法的类就称之为抽象类,同样的,方法体是空实现的(pass)就称之为抽象方法。
抽象类的作用: 多用于做顶层设计(设计标准),以便子类做具体实现,也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法并且配合多态去使用,从而获得不同的工作状态。