目录
- 一、面向对象编程
- 1、成员方法
- a、类的定义和使用
- b、案例
- 2、类和对象
- 3、构造方法
- 4、其他内置方法(魔术方法)
- 5、面向对象三大特性——封装
- a、介绍:
- b、表现形式:私有成员变量与私有成员方法
- c、作用
- 6、面向对象三大特性——继承
- a、介绍
- b、语法
- c、分类
- d、pass关键词
- e、复写
- 7、类型注解
- a、介绍
- b、变量的类型注解
- c、函数(方法)的类型注解
- c、Union类型
- 8、面向对象三大特性——多态
- a、介绍
- b、普通示例
- c、抽象类示例
一、面向对象编程
1、成员方法
a、类的定义和使用
定义在类外面的函数称为函数,定义在类内部的函数称为方法
#类的定义语法
class 类名称:
类的属性名: 属性值 #这里就是成员变量
def 方法名(self,形参1,形参2...): #这里就是成员方法,当外部调用此方法时,self参数可忽略不传
方法体
#创建类的语法
对象 = 类名称()
b、案例
案例:创建一个人的类,编辑人的信息并调用方法输出信息
class people:
name: None #人名
age: None #年龄
sex: None #性别
def introduce(self):
print("我叫%s,今年%d岁,性别%s" % (self.name, self.age, self.sex))
p1 = people()
p1.name = "张三"
p1.age = 18
p1.sex = "男"
print(p1.name)
print(p1.age)
print(p1.sex)
p1.introduce()
结果为:
张三
18
男
我叫张三,今年18岁,性别男
2、类和对象
- 类是指创建出一个模板,提供给具体的个人使用
- 对象是基于模板的基础上创建一个具体实例,修改对象的属性不会更改类本身的内容,并且多个对象之间的数据值不会影响
- 面向对象编程就是使用类创建对象,并且使用对象来完成具体的工作
3、构造方法
- python类可以使用__init__()方法,称之为构造方法
- 注意:构造方法前后各有两个下划线
- 在创建类对象时,构造方法会自动执行,可以将参数自动传递给构造方法给对象赋值
- 当有构造方法时,类中定义字段可省略
class people:
name: None #人名 此可省略
age: None #年龄 此可省略
sex: None #性别 此可省略
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def introduce(self):
print("我叫%s,今年%d岁,性别%s" % (self.name, self.age, self.sex))
p1 = people("张三", 18, "男")
p1.introduce()
结果为:
我叫张三,今年18岁,性别男
4、其他内置方法(魔术方法)
- __str__:字符串方法
- 当类中未定义此方法时,输出类时输出的内容为内存地址
- 当类中定义了此方法时,输出类时输出的是str方法中的内容
#当类中未定义此方法时,输出类为内存地址
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
student = Student("张三", 18, "北京")
print(student)
print(str(student))
结果为:
<__main__.Student object at 0x0000025921C64310>
<__main__.Student object at 0x0000025921C64310>
#当类中定义了此方法时,输出类时输出的是str方法中的内容
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __str__(self):
return f"我叫{self.name},今年{self.age}岁,地址{self.address}"
student = Student("张三", 18, "北京")
print(student)
print(str(student))
结果为:
我叫张三,今年18岁,地址北京
我叫张三,今年18岁,地址北京
- __lt__:小于大于符号比较
- 当类中未定义此方法, 两个对象比较会报错
- 当类中定义了此方法,会根据此方法中定义的内容比较大小
#当类中未定义此方法, 两个对象比较会报错
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")
print(student < student1)
报错信息:
Traceback (most recent call last):
File "F:\Pycharm\workspaces\test\main.py", line 761, in <module>
print(student < student1)
^^^^^^^^^^^^^^^^^^
TypeError: '<' not supported between instances of 'Student' and 'Student'
#当类中定义了此方法,会根据此方法中定义的内容比较大小
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __lt__(self, other):
return self.age < other.age #定义根据年龄来比较
student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")
print(student < student1)
结果为:
True
- __le__:小于等于、大于等于符号比较
- 当类中未定义此方法, 两个对象比较会报错
- 当类中定义了此方法,会根据此方法中定义的内容比较大小
# 当类中未定义此方法, 两个对象比较会报错
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")
print(student <= student1)
报错信息为:
Traceback (most recent call last):
File "F:\Pycharm\workspaces\test\main.py", line 764, in <module>
print(student <= student1)
^^^^^^^^^^^^^^^^^^^
TypeError: '<=' not supported between instances of 'Student' and 'Student'
#当类中定义了此方法,会根据此方法中定义的内容比较大小
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __le__(self, other):
return self.age < other.age #定义根据年龄来比较
student = Student("张三", 18, "北京")
student1 = Student("李四", 19, "上海")
print(student <= student1)
结果为:
True
- __eq__:==符号比较
- 当未定义此方法时,会比较两个对象的内存地址是否一致
- 当定义了此方法时,会根据方法中定义的内容进行比较
#当未定义此方法时,会比较两个对象的内存地址是否一致
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
student = Student("张三", 18, "北京")
student1 = Student("张三", 18, "北京")
print(student == student)
print(student == student1) #尽管赋值一样,对象不同内存地址也不同
结果为:
True
False
#当定义了此方法时,会根据方法中定义的内容进行比较
class Student:
name = None
age = None
address = None
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __eq__(self, other):
return self.age == other.age #根据对象年龄来比较
student = Student("张三", 18, "北京")
student1 = Student("李四", 18, "上海")
print(student == student)
print(student == student1)
结果为:
True
True
5、面向对象三大特性——封装
a、介绍:
封装就是将现实世界事务的属性和行为,封装到类中,描述为成员变量和成员方法,从而完成程序对现实世界事务的描述
b、表现形式:私有成员变量与私有成员方法
- 在类中,只提供给内部使用的变量叫做私有成员变量,只提供给内部使用的方法叫做私有成员方法。封装最主要的表现形式就是私有成员变量和私有成员方法,其封装特性只能被内部调用,外部无法调用成功
- 私有成员变量和方法,定义方式为在前面加上两个下划线即可
class Student:
name = None
age = None
address = None
__sex = None #私有成员变量
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def __introduce(self): #私有成员方法
print(f"我叫{self.name},今年{self.age}岁,地址{self.address}")
student = Student("张三", 18, "北京")
student.__sex = '男' #此不会报错,但是赋值无效
student.introduce()
错误信息为:
Traceback (most recent call last):
File "F:\Pycharm\workspaces\test\main.py", line 763, in <module>
student.introduce()
^^^^^^^^^^^^^^^^^
AttributeError: 'Student' object has no attribute 'introduce'
c、作用
私有成员变量和方法能在类中提供仅供内部使用的属性和方法,而不对外开放,保护内部数据
6、面向对象三大特性——继承
a、介绍
如果新的类A中部分信息与现存的另一个类B中的内容一样,则可以类A直接继承类B,这部分重复信息就无需重复定义了
b、语法
class 子类名(父类1,父类2,父类3...):
类内容体
c、分类
- 单继承:只继承一个父类的叫单继承
#ClassA继承ClassB
class ClassB:
name = None
age = None
class ClassA(ClassB): #类A继承类B,自动拥有类B中的全部内容
sex = None
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def introduce(self):
print(f"我叫{self.name},今年{self.age}岁,性别{self.sex}")
c = ClassA("张三", 18, "男")
c.introduce()
结果为:
我叫张三,今年18岁,性别男
- 多继承:同时继承多个父类的叫多继承
#ClassA同时继承ClassB和ClassC
class ClassB:
name = None
age = None
class ClassC:
address = None
class ClassA(ClassB,ClassC):
name = None
age = None
address = None
sex = None
def __init__(self, name, age, address, sex):
self.name = name
self.age = age
self.address = address
self.sex = sex
def introduce(self):
print(f"我叫{self.name},今年{self.age}岁,地址{self.address},性别{self.sex}")
c = ClassA("张三", 18, "北京", "男")
c.introduce()
结果为:
我叫张三,今年18岁,地址北京,性别男
但是当多继承时多个父类中存在同名属性或者方法,按父类继承的顺序从左到右,优先使用左边的属性或者方法。左边优先级更高
#ClassA继承ClassB和ClassC,同时ClassB和ClassC中有同名属性age
class ClassB:
name = "张三"
age = 18
class ClassC():
address = "北京"
age = 20
class ClassA(ClassB,ClassC):
pass
c = ClassA()
print(f"年龄:{c.age}") #继承时ClassB在ClassC左边,则会展示ClassB中的结果
结果为:
年龄:18
d、pass关键词
当某个子类同时继承多个父类,并且子类无需定义其他内容时,可以使用pass关键词
#ClassA同时继承ClassB和ClassC
class ClassB:
name = "张三"
age = 18
class ClassC():
address = "北京"
class ClassA(ClassB,ClassC):
pass #类中无需定义其他内容时用pass关键字
c = ClassA()
print(f"姓名:{c.name},年龄:{c.age},地址:{c.address}")
结果为:
姓名:张三,年龄:18,地址:北京
e、复写
- 普通复写
子类继承父类的成员属性和成员方法后,如果对其不满意,则可以进行复写,即在子类中重新定义同名的属性和方法即可
#子类ClassA复写父类ClassB的属性和方法
class ClassB:
name = "我是ClassB的成员属性"
def introduce(self):
print(f"这是ClassB的成员方法,属性内容为:{self.name}")
class ClassA(ClassB):
name = "我是ClassA的成员属性"
def introduce(self):
print(f"这是ClassA的成员方法,属性内容为:{self.name}")
c = ClassA()
c.introduce() #这里输出的是子类中复写后的结果
结果为:
这是ClassA的成员方法,属性内容为:我是ClassA的成员属性
- 调用父类内容
当子类对父类进行复写后,还想要获取父类中原先的成员变量和方法,有两种方式
class ClassB:
name = "我是ClassB的成员属性"
def introduce(self):
print(f"这是ClassB的成员方法,属性内容为:{self.name}")
class ClassA(ClassB):
name = "我是ClassA的成员属性"
def introduce(self):
#方式1:调用父类成员
#直接使用父类名.属性或者父类名.方法就可以获得父类的信息
print(f"父类的成员变量为{ClassB.name},父类的成员方法为{ClassB.introduce(self)}")
#方式2:使用super()调用父类成员
print(f"父类的成员变量为{super().name},父类的成员方法为{super().introduce()}")
c = ClassA()
c.introduce()
结果为:
这是ClassB的成员方法,属性内容为:我是ClassA的成员属性
父类的成员变量为我是ClassB的成员属性,父类的成员方法为None
这是ClassB的成员方法,属性内容为:我是ClassA的成员属性
父类的成员变量为我是ClassB的成员属性,父类的成员方法为None
7、类型注解
a、介绍
- Python在3.5版本之后引入了类型注解,以方便静态类型检查工具。
- 类型注解是对变量或者方法中的形参和返回值进行类型标注,方便程序员调用时使用正确的类型数据
- 方法调用时鼠标停留在调用的地方可以显示类型注解的内容
- 类型注解只是提示性的,非决定性的。如果定义的类型注解和实际类型不一致,也不会报错
b、变量的类型注解
- 语法1:
变量:类型
#基础数据类型注解
var_1: int = 10
var_2: float = 3.1415
var_3: bool = True
var_4: str = 'test'
#基础容器类型注解
my_list: list = [1,2,3]
my_tuple: tuple = (1,2,3)
my_set: set = {1,2,3}
my_dict: dict = {"age": 18}
my_str: str = "test"
#容器类型详细注解
my_list: list[int] = [1,2,3]
my_tuple: tuple[str,int,bool] = ("test",18,True) #元组类型设置详细注解需要将每个元素类型都标注出来
my_set: set[int] = {1,2,3}
my_dict: dict[str,int] = {"age": 18} #字典类型设置详细注解需要标注key和value的类型
#调用函数方法类型的注解
class Student:
pass
stu: Student = Student()
- 语法2
#type:类型
#对基础数据类型注解
var_1 = random.randint(1,10) #type: int
var_2 = json.loads(data) #type: dict[str, int]
var_3 = func() #type: Student
c、函数(方法)的类型注解
- 形参注解
#语法:
def 函数方法名(形参名:类型,形参名:类型,....)
函数内容体
#案例,定义add函数传入两个int类型数字
def add(x:int,y:int):
return x + y
- 返回值注解
#语法:
def 函数方法名(形参名:类型,形参名:类型,....) -> 返回值类型
函数内容体
#案例,定义add函数传入两个int类型数字,返回int类型结果
def add(x:int,y:int) -> int:
return x + y
c、Union类型
-
语法:
Union[类型1,类型2,类型3…] -
案例
#对变量进行类型注解
from typing import Union
my_list:list[Union[str,int]] = ['1', 2, 3]
my_dict:dict[str,Union[str,int]] = {"name":"张三", "age": 18}
#对函数(方法)进行类型注解
def add(x:Union[str,int],y:Union[str,int]) -> Union[str,int]:
return x + y
8、面向对象三大特性——多态
a、介绍
多态指多种状态,完成某个行为时,使用不同的对象会得到不同的状态
b、普通示例
class Dog:
def speak(self):
print("汪汪汪")
class Cat:
def speak(self):
print("喵喵喵")
def make_sound(animal):
animal.speak()
dog = Dog()
cat = Cat()
make_sound(dog)
make_sound(cat)
结果为:
汪汪汪
喵喵喵
c、抽象类示例
- 使用多态的属性,可以直接在父类中定义有那些方法,方法体为pass, 在子类中具体实现
- 方法体是pass的称为抽象方法,含有抽象方法的类叫做抽象类
class Animal: #此为抽象类
def speak(self): #此为抽象方法
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
def make_sound(animal):
animal.speak()
结果为:
汪汪汪
喵喵喵