1. python面向对象编程
1.1 面向对象是什么
- Python 是一门面向对象的语言
- 面向对象编程(
OOP
):Object Oriented Programming
所谓的面向对象,就是在编程的时候尽可能的去模拟真实的现实世界,按照现实世界中的逻辑去处理问题,分析问题中参与其中的有哪些实体,这些实体应该有什么属性和方法,我们如何通过调用这些实体的属性和方法去解决问题。
1.2 两种编程思想
-
面向过程
- 一种以过程为中心的编程思想
- 首先分析解决问题所需要的步骤
- 然后用函数将这些步骤一步一步的实现
- 最后按顺序依次调用运行
-
面向对象
- 是一种更符合我们人类思维习惯的编程思想
- 面向对象开发就是不断的创建对象,使用对象,操作对象做事情
- 可以将复杂的事情简单化
1.3 类与对象
- 类(
class
): 用来描述具有相同的属性和方法的对象的集合。它定义了集合中每个对象所共有的属性和方法。 - 对象(
object
):也称为类的实例,是一个具体存在的实体。
2. python类与对象
2.1 类的定义
class
关键字
# 语法
class 类名(父类名):
"""类的帮助信息"""
属性
方法
# class_def.py
# 类的声明
class Human(object): #object可以省略。在python中如果没有声明继承的类的话,那默认继承的是超类object。
"""人类"""
# 定义属性(类属性)
message = "这是类属性"
# 通过类访问类属性
print(Human.message)
2.2 类的方法
2.2.1 实例方法
2.2.1.1 构造方法
- 作用:实例化对象。构造方法用于构造并直接返回该类的对象,每当创建一个类的新的实例时,python会自动执行构造方法,这是创建对象的基本途径。如果开发者没有在类中定义构造方法,python会自动给该类默认添加一个构造方法。
- 语法:
def __init__(self, 参数列表)
- self:self参数是一个指向实例的引用,用于访问类的属性和方法,在方法调用时会自动绑定到调用这个方法的本身。
- self参数必须有,且必须处于首位。
- 访问:
类名(参数列表)
# constructor_method.py
class Human:
# 定义属性(类属性)
message = "这是类属性"
# 构造方法
def __init__(self, name, age):
# 实例变量(实例属性)
self.name = name
self.age = age
print("这是构造方法")
# 实例化对象
person = Human("哈利波特", 12)
# 通过实例访问类属性
print(person.message)
# 通过实例访问实例属性
print(person.name)
print(person.age)
2.2.1.2 实例方法
- 作用:实例方法是在类中定义的函数,该函数是一种在类的实例上操作的函数。实例方法提供每个类的实例共享的方法
- 语法:
def 方法名(self, 参数列表)
- self:类的实例自身,也可以是self之外的其他单词,但建议使用约定俗成的self。第一个参数必须是self,不可省略。
- 参数列表:自定义参数,每个参数间使用逗号分隔
- 访问:
实例.方法名(参数列表)
- 实例方法与函数的区别:函数是实现某个独立功能;实例方法是实现类的某个行为,属于类的部分。实例方法用于定义该类的对象行为和行为实现。在类中的方法都属于实例方法。
# instance_method.py
class Human:
# 实例方法
def study(self, course):
print("正在学习{course}")
# 实例化
person = Human()
# 通过实例访问实例方法
person.study("python")
2.2.2 类方法
- 作用:类方法是指在类中使用
@classmethod
装饰器装饰的方法。用于设置或获取类的详细信息或者状态。 - 语法:
@classmethod
- 访问:
类名.类方法名(参数列表)
- 注意:不能访问或者修改实例对象的数据 ,因为类方法绑定的是
cls
参数不是self
参数。不使用cls不会报错,但是最好按照惯例来,cls指向对象其实就是类名本身。
# class_method.py
class Human:
# 类属性
population = []
# 类方法
@classmethod
def born(cls): #使用类方法装饰器,定义类时会自动添加cls参数
print("这是类方法")
cls.population += 1
# 通过类名访问类方法
Human.born()
print(Human.population)
2.2.3 静态方法
- 静态方法是类中使用
@staticmethod
装饰的方法。静态方法不需要访问数据,没有cls、self这种关键字。静态函数可以独立工作,不能设置类的状态或者实例的状态。 - 作用:静态方法用于创建通用的工具函数。这样就可以把常用的工具函数放在一个类里,使用的时候不需要实例化就可以直接调用。
- 语法:
@staticmethod
- 调用:
类名.静态方法名()
- 注意:调用类方法和静态方式时,我们是使用类名访问。虽然实例也可以调用类方法和静态方法,但是一般不会这样进行操作。这样可以省去实例化的步骤。
# static_method.py
class Human:
# 静态方法
@staticmethod
def grow_up():#使用静态方法声明后,不会绑定cls或者self参数
print("这是静态方法")
# 通过类名访问静态方法
Human.grow_up()
3. python封装
3.1 封装的概念
封装(Encapsulation
):
- 隐藏:属性和实现细节,不允许外部直接访问
- 暴露:公开方法, 实现对内部信息的操作和访问
3.2 封装的作用
- 限制不合理的访问和操作,提高数据安全性
- 可进行数据检查,从而有利于保证对象信息的完整性
3.3 封装的实现
3.3.1 隐藏
python中没有既定的关键字或者机制来实现真正的封装,但是使用命名方式来实现
- 保护属性:
_属性名
- 私有属性:
__属性名
- 定义私有属性之后,python将会自动添加
_类名
,变相的实现了属性的隐藏,即被视为:_类名__属性名
- 当想要通过
__属性名
去访问属性的话,实际上访问不到的。
- 定义私有属性之后,python将会自动添加
#定义一个Account类
class Account:
# 普通属性
bank = "BOC"
# 内部属性
_username = "Hogwarts"
# 私有属性
__password = "888"
# 通过类名访问类属性
print(Account.bank) # 将会打印 BOC
print(Account._username) # 将会打印 Hogwarts
print(Account.__password) # 将会引发 AttributeError,打印内容:AttributeError: type object 'Account' has no attribute '__password'
print(Account.__dict__) # 将会打印类中实际有用属性
#打印内容:{'__module__': '__main__', 'bank': 'BOC', '_username': 'Hogwarts', '_Account__password': '888', '__dict__': <attribute '__dict__' of 'Account' objects>, '__weakref__': <attribute '__weakref__' of 'Account' objects>, '__doc__': None}
#注:__dict__:python内置特殊属性,字典格式,保存类中所拥有的可写的属性
3.3.2 暴露
- 提供数据访问功能(getter)
- 计算属性(通过
@property
合成的属性成为计算属性) - 语法:使用
@property
装饰器 - 作用:把类中的一个方法变成一个属性
- 调用:
实例.方法名
注意: 计算属性并不真正的存储状态,其值是通过某种算法计算得到的,当程序对该属性赋值时,所赋值实际是存放在对应的实例变量中。
class Account:
# 普通属性
bank = "BOC"
# 内部属性
_username = "Hogwarts"
# 私有属性
__password = "888"
@property
def password(self):
return self.__password
# 实例化对象
obj = Account()
# 访问实例的私有属性
print(obj.password) # 将会打印 888
#注意:password虽然是方法,但是已经被装饰成计算属性,因此访问的时候不需要加()
- 提供数据操作功能(setter)
- 语法:使用
@计算属性名.setter
装饰器 - 作用:对计算属性进行赋值操作
- 调用:
实例.方法名
class Account:
# 普通属性
bank = "BOC"
# 内部属性
_username = "Hogwarts"
# 私有属性
__password = "888"
@property
def password(self):
return self.__password
@password.setter
def password(self, value):
# 增加数据的校验
if len(value) >= 8:
self.__password = value
else:
print("密码长度最少要有8位!")
# 实例化对象
obj = Account()
# 修改私有属性(满足校验条件)
obj.password = "hogwarts666" # 修改成功
print(obj.password) # 将会打印 hogwarts666
# 修改私有属性(不满足校验条件)
obj.password = "123" # 修改不会生效
print(obj.password) # 将会打印 888
4. python继承
4.1 继承的概念
继承(Inheritance
):
- 复用父类的公开属性和方法
- 拓展出新的属性和方法
4.2 继承的实现
- 语法:
class 类名(父类列表)
- 默认父类是
object
- Python 支持多继承
# inheritance_demo.py
class Human:
"""人类"""
# 类属性
message = "这是Human的类属性"
# 构造方法
def __init__(self, name, age):
# 实例属性
self.name = name
self.age = age
# 实例方法
def live(self):
print("住在地球上")
class Student(Human):
"""学生类"""
def study(self):
print("正在学习")
# 实例化子类对象
stu = Student("哈利波特", 12)
# 访问类属性(继承)
print(stu.message)
# 访问实例属性(继承)
print(stu.name, stu.age)
# 访问实例方法(继承)
stu.live()
# 访问实例方法(扩展)
stu.study()
4.3 类型检查
isinstance(实例, 类名)
- 检查对象是否是某个类及其派生类的实例
issubclass(类名1, 类名2)
- 检查类名 1 是否是类名 2 的子类
# relation_demo.py
# 人类
class Human:
pass
# 学生类
class Student(Human):
pass
# 老师类
class Teacher(Human):
pass
# 检查实例与类的关系
stu = Student()
print(isinstance(stu, Human)) # 将会打印 True
# 检查类与类的关系
print(issubclass(Student, Human)) # 将会打印 True
print(issubclass(Student, Teacher)) # 将会打印 False
5. python多态
5.1 多态的概念
多态(Polymorphism
):同名方法呈现多种行为
python弱类型语言,变量并没有声明类型,因此完全可以在不同的时间代表不同的变量,当同一个变量在调用同一个方法时,完全可能呈现出多种行为,具体呈现的哪些行为由该变量所引用的对象来决定。这就是多态。
5.2 多态的表现
5.2.1 运算符的多态表现
+
号- 加法:数字+数字
- 拼接:字符串+字符串
- 合并:列表+列表
# 加法:数字+数字
print(1 + 1) # 打印 2
# 拼接:字符串+字符串
print("Hello" + "World") # 打印 Hello World
# 合并:列表+列表
print([1, 2] + [3]) # 打印 [1, 2, 3]
5.2.2 函数的多态表现
-
len()
函数- 可以接收字符串
- 可以接收列表
# 参数是字符串
print(len("Hogwarts"))
# 参数是列表
print(len([1, 3, 5]))
5.2.3 方法的多态表现
同名变量调用同名方法呈现多种行为。
# poly_method.py
class China:
def speak(self):
print("汉语")
class Usa:
def speak(self):
print("英语")
# 实例化对象
cn = China()
us = Usa()
for x in (cn, us):
# 同一个变量在调用同名方法时,呈现不同的行为
# 具体呈现哪种行为,由该变量所引用的对象决定
x.speak()
5.3 多态与继承
- 方法重写(
Override
):子类的方法名称与父类的相同 - 重写构造方法
super().__init__()
父类名.__init__(self)
# override_demo.py
class Human:
"""人类"""
message = "这是Human的类属性"
# 构造方法
def __init__(self, name, age):
# 实例属性
self.name = name
self.age = age
# 实例方法
def live(self):
print(f"住在地球上")
class Student(Human):
"""学生类"""
# 重写父类的构造方法
def __init__(self, name, age, school):
# 方式一:访问父类的构造方法
super().__init__(name, age)
#方式二:访问父类的构造方法
# super(Student, self).__init__(name, age)
#方式三:访问父类的构造方法
# Human.__init__(self, name, age)
# 子类特有的实例属性(个性)
self.school = school
# 重写父类的实例方法
def live(self):
print(f"住在{self.school}")
# 实例化子类对象
stu = Student("哈利波特", 12, "Hogwarts")
# 访问实例方法
stu.live() # 将会打印 住在Hogwarts