笔者学过Java,对面向对象有一定了解,故内容可能不够全面
在类中,不仅可以定义属性用来记录数据,也可以定义函数,用来记录行为
- 类中定义的属性(变量),我们称之为:成员变量
- 类中定义的行为(函数),我们称之为:成员方法
class Student:
name = None
age = None
gender = None
#上面的3个变量为Student类的属性,下面的函数为它的行为
def sayHi(self):
print(f"Hi,我是{self.name}")
def sayHi1(self,msg):
print(f"Hi,我是{self.name},{msg}")
stu1 = Student()
stu1.name = "root"
stu1.age = 23
stu1.gender = "female"
stu1.sayHi()
print(f"我的年龄是{stu1.age}")
stu2 = Student()
stu2.name = "坤坤"
stu2.sayHi1("哎呦你干嘛")
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
def 方法名(self,形参):
方法体
可以看到,在方法定义的参数列表中有一个self关键字
self关键字是成员方法定义的时候必须填写的
- 它用来表示类对象自身的意思
- 当我们实用类对象调用方法时,self会自动被python传入
- 在方法内部,想要访问类的成员变量,必须使用self
类比this关键字
魔术方法
构造方法
python类可以使用:__init__()方法,称之为构造方法
- 在创建类对象(构造类)的时候,会自动执行
- 在创建类对象(构造类)的时候,将传入参数自动传递给__init__()方法使用
class Student:
name = None
age = None
gender = None
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
print("Student类创建了一个对象")
stu1 = Student("Fat Cat",21,"男")
print(stu1.name)
字符串方法
__str__()
用于实现类对象转字符串的行为
class Student:
name = None
age = None
gender = None
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def __str__(self):
return f"Student类对象,name:{self.name},age:{self.age},gender:{self.gender}"
stu1 = Student("Fat Cat",21,"男")
print(stu1)
如果没有字符串方法,直接输出stu1会输出内存地址
小于符号比较方法
__lt__()
自定义对象比较规则
class Student:
name = None
age = None
def __init__(self,name,age):
self.name = name
self.age = age
def __lt__(self, other):
return self.age < other.age
stu1 = Student("张三",28)
stu2 = Student("罗翔",35)
print(stu1 < stu2)#True
print(stu1 > stu2)#False
小于等于符号比较方法
__le__()
小于符号比较方法不能比较等于的情况
class Student:
name = None
age = None
def __init__(self,name,age):
self.name = name
self.age = age
def __le__(self, other):
return self.age <= other.age
stu1 = Student("李四",35)
stu2 = Student("罗翔",35)
print(stu1 <= stu2)#True
print(stu1 >= stu2)#True
等于符号比较方法
__eq__()
不使用此方法,两个对象可以用"==“运算符进行比较,比较的是内存地址,两个不同的对象这样比较,结果必然是"False”,而使用此方法可以自定义比较规则
class Student:
name = None
lastname = None
def __init__(self,name,lastname):
self.name = name
self.lastname = lastname
def __eq__(self, other):
return self.lastname == other.lastname
stu1 = Student("罗永浩","罗")
stu2 = Student("罗翔","罗")
print(stu1 == stu2)#True
封装
私有成员
- 私有成员变量:变量名以两个下划线开头
- 私有成员方法:方法名以两个下划线开头
对于私有成员,类对象无法直接使用,但其内部其他成员可以使用
class Phone:
__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()
继承
class 类名(父类名):
类内容体
子类从父类那里继承成员变量和方法(不含私有)
class Phone:
IMEI = None #序列号
producer = None #厂商
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
face_id = True #面部识别
def call_by_5g(self):
print("2022最新5g通话")
iPhone14Pro = Phone2022()
iPhone14Pro.producer = "锤子"
print(iPhone14Pro.producer)
iPhone14Pro.call_by_4g()
iPhone14Pro.call_by_5g()
上面示例为“单继承”
多继承
顾名思义,继承多个父类
class 类名(父类1,父类2,...父类N):
类内容体
代码示例省略
这里我们说一种情况,当我们子类继承了多个父类后,继承的很完善,不需要再添加内容,但我们也不能直接空着,这时候我们可以写一个"pass"
多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级,即按照先继承的。
复写
子类继承父类的成员属性和成员方法后,可以对其进行“复写”,即在子类中重新定义同名的属性或方法
class Phone:
IMEI = None #序列号
producer = "锤子" #厂商
def call_by_4g(self):
print("4g通话")
class Phone2022(Phone):
producer = "苹果"
face_id = True #面部识别
def call_by_4g(self):
print("您当前选择使用4g通话,如果要使用5g通话请进行切换")
def call_by_5g(self):
print("2022最新5g通话")
iPhone14Pro = Phone2022()
print(iPhone14Pro.producer)
iPhone14Pro.call_by_4g()
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类的成员,需要特殊的调用方式:
方式1:
- 使用成员变量:父类名.成员变量
- 使用成员方法:父类名.成员方法(self)
方式2:
- 使用成员变量:super().成员变量
- 使用成员方法:super().成员方法()
代码示例省略
类型注解
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)
主要功能:
- 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
- 帮助开发者自身对变量进行类型注释
支持:
- 变量的类型注解
- 函数(方法)形参列表和返回值的类型注解
对变量设置类型注解
#基础语法:变量:类型
import json
import random
#基础数据类型注解
var1:int = 10
var2:float = 3.1415926
var3:bool = True
var4:str = "Sweet Dreams (Mixed)"
#类对象类型注解
class Student:
pass
stu:Student = Student()
#基础容器类型注解
list1:list = [1,2,3]
tuple1:tuple = (1,2,3)
set1:set = {1,2,3}
dict1:dict = {"rainy":1}
#容器类型详细注解
my_list:list[int] = [1,2,3]
my_tuple:tuple[str,int,bool] = ("root",1111,True)
my_set:set[int] = {1,2,3}
my_dict:dict[str,int] = {"windy":5}
#在注释中进行类型注解
data = '{"春":1,"夏":2,"秋":3,"冬":4}'
def func():
pass
test1 = random.randint(1,10) # type:int
test2 = json.loads(data) # type:dict[str,int]
test3 = func() #type:Student
- 元组类型设置类型详细注解,需要将每一个元素都标记出来
- 字典类型设置类型详细注解,需要2个类型(key和value)
类型注解不是强制性的,如果注解的和实际的不一致也不会报错(会提示警告),程序也能正常运行
sentence:int = "hello"
print(sentence)
对函数(方法)形参列表和返回值进行类型注解
#对形参进行类型注解
def add(x:int, y:int):
return x+y
#对返回值进行类型注解
def func(data) -> list:
return data
Union类型
#可以使用Union[类型,......,类型]定义联合类型注解
from typing import Union
my_list:list[Union[str,int]] = [1,2,"itheima","itcast"]
my_dict:dict[str,Union[str,int]] = {"name":"周杰轮","age":31}
def func(data:Union[int,str]) -> Union[int,str]:
pass
多态
多态,指的是多种状态,即完成某个行为时,使用不同的对象会得到不同的状态
class Animal:
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()
dog = Dog()
cat = Cat()
make_noise(dog)#输出:汪汪汪
make_noise(cat)#输出:喵喵喵
多态常作用在继承关系上,比如:
- 函数(方法)形参声明接收父类对象
- 实际传入父类的子类对象进行工作
即:
- 以父类做定义声明
- 以子类做实际工作
- 用以获得同一行为,不同状态
上述代码中父类Animal的speak方法是空实现(pass)
这种设计的含义是:父类用来确定有哪些方法,具体的方法实现由子类自行决定
这种写法,就叫做抽象类(也可以称之为接口)
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法