面向对象
1. 面向对象
面向对象都有两个基本概念, 分别是 类 和 对象。
面向对象的三大特征:
继承
: 即一个派生类(derived class)继承基类(base class)的字段和方法。- 继承允许把一个派生类的对象作为一个基类对象对待。
- 一个 Dog 类型的对象派生自 Animal 类
多态
: 指对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为封装
: 将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体(即类)- 封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。
2. 类的定义和调用
2.1 类的定义
语法格式:
1 2 3 4 5
| class ClassA(): var1 = 100
def fun1(): print("hello fun1")
|
2.2 调用类属性和类方法
- 类中的变量叫
属性
—-> 调用格式: 类名.属性名
- 类中的函数叫
方法
—-> 调用格式: 类名.方法名()
1 2 3 4 5 6 7 8
| class ClassA(): var1 = 100
def fun1(): print("hello fun1")
print(ClassA.var1) print(ClassA.fun1())
|
3. 类方法
3.1 类方法调用类属性
1 2 3 4 5 6 7 8
| class ClassA(): var1 = 'hello'
@classmethod def fun1(cls): print(f'{cls.var1} world')
ClassA.fun1()
|
@classmethod
: 类方法装饰器, 用来声明类方法, 只有声明了类方法才能使用类属性cls
: 类的引用,指向类本身, 是类方法的第一个参数, 类似于self
- 无论是
@classmethod
还是cls
都不能省去, 否则会报错
3.2 类方法传参
1 2 3 4 5 6 7 8
| class ClassA(): var1 = 'hello'
@classmethod def fun1(cls, var2): print(f'{cls.var1} {var2}')
ClassA.fun1('world')
|
4. 修改和增加类属性
4.1 从内部增加和修改类属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class ClassA: var1 = '两点水'
@classmethod def method1(cls): print(f'原来的 var1 值为:{cls.var1}') cls.var1 = '三点水' print(f'修改后的 var1 值为:{cls.var1}') cls.var2 = '新添加的类变量' print(f'新添加的 var2 值为:{cls.var2}')
ClassA.method1()
输出结果为: 原来的 var1 值为:两点水 修改后的 var1 值为:三点水 新添加的 var2 值为:新添加的类变量
|
4.2 从外部增加和修改类属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class ClassA: var1 = '两点水'
@classmethod def fun1(cls): print(f'var1 值为:{cls.var1}')
ClassA.fun1() ClassA.var1 = 'twowater' ClassA.fun1()
ClassA.var2 = '四点水' print(ClassA.var2)
|
5. 类和对象
5.1 类和对象的概念
类是对象的模板,对象是类的实例。
类相当于模具, 对象就是根据模具制造出来的产品
从模具变成产品的过程就是类的实例化, 类实例化之后就是对象
5.2 类的实例化
类的实例化和直接使用类的区别:
- 类方法里面没有了
@classmethod
声明了,不用声明他是类方法 - 类方法里面的参数
cls
改为self
- 实例化对象
实例名 = 类()
, 调用实例方法 实例名.函数()
,使用 实例名.变量名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class ClassA: var1 = '两点水'
@classmethod def fun1(cls): print(f'var1 值为:{cls.var1}')
class ClassB: var2 = 'Python'
def fun2(self): print(f'var2 值为:{self.var2}')
ClassA.fun1() ClassB().fun2()
|
cls
和 self
是我们的编程规范, 并非不可更改cls
是类方法中的第一个参数, self
是实例方法中的第一个参数cls
和 self
都是引用, cls
是类引用, self
是实例引用
5.3 实例属性和类属性
- 修改类属性时, 实例属性也会被修改
- 修改实例属性时, 类属性不会被修改
1 2 3 4 5 6 7 8 9 10
| class ClassA: var1 = '两点水'
def fun1(self): print(f'var1 值为:{self.var1}')
a = ClassA() a.var1 = 'twowater' a.fun1() print(ClassA.var1)
|
5.4 实例方法和类方法
- 类方法更改后, 实例方法也会更改, 相当于
类的重写
1 2 3 4 5 6 7 8 9 10 11 12 13
| class ClassA: var1 = '两点水'
def fun1(self): print(f'第一次打印')
def new_fun1(): print(f'第二次打印')
a = ClassA() a.fun1() a.fun1 = new_fun1 a.fun1()
|
6. 初始化函数及析构函数
__init__(self)
: 初始化函数,也叫构造函数,类创建时自动执行__del__(self)
: 析构函数,类销毁时自动执行- 初始化函数和析构函数的写法是固定的,第一个参数一定是
self
1 2 3 4 5 6 7 8 9 10
| class ClassName: def __init__(self): print("实例化成功")
def __del__(self): print("实例化销毁")
c1 = ClassName() del c1
|
7. 类的继承
7.1 继承的概念
继承是面向对象编程中一个重要的概念,它允许我们定义一个类,该类可以继承另一个类,从而获得父类的方法和属性。
继承的类通常叫子类
, 被继承的类通常叫父类
, object
是所有类的父类
基本语法:
多继承语法:
1 2
| class 子类(父类1, 父类2, ...): pass
|
多继承中,如果父类中有相同的方法名,而子类使用时未指定,则从左到右
搜索父类方法,如果父类中没有该方法,则报错
继承子类的好处:
7.2 调用父类方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class UserInfo: lv = 5
def __init__(self, name, age, account): self.name = name self._age = age self.__account = account
def get_account(self): return self.__account
class UserInfo2(UserInfo): pass
if __name__ == '__main__': user_info_2 = UserInfo2('Tom', 18, '123456') print(user_info_2.get_account())
|
7.3 父类方法重写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class UserInfo: lv = 5
def __init__(self, name, age, account): self.name = name self._age = age self.__account = account
def get_account(self): return self.__account
@classmethod def get_name(cls): return cls.lv
@property def get_age(self): return self._age
class UserInfo2(UserInfo): def __init__(self, name, age, account, sex): super().__init__(name, age, account) self.sex = sex
if __name__ == '__main__': user_info_2 = UserInfo2('Tom', 18, '123456', '男') print(dir(user_info_2)) print(user_info_2.__dict__) print(user_info_2.get_name())
|
7.4 子类的类型判断(isinstance
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class User1(object): pass
class User2(User1): pass
class User3(User2): pass
if __name__ == '__main__': user1 = User1() user2 = User2() user3 = User3() print(isinstance(user3, User2)) print(isinstance(user3, User1)) print(isinstance(user3, User3)) print(isinstance('两点水', str)) print(isinstance(347073565, int)) print(isinstance(347073565, str))
|
8. 类的多态
多态是面向对象编程中一个重要的概念,它允许我们定义一个方法,该方法可以接受多个不同的类型参数,从而实现不同的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class User(object): def __init__(self, name): self.name = name
def printUser(self): print('Hello !' + self.name)
class UserVip(User): def printUser(self): print('Hello ! 尊敬的Vip用户:' + self.name)
class UserGeneral(User): def printUser(self): print('Hello ! 尊敬的用户:' + self.name)
def printUserInfo(user): user.printUser()
if __name__ == '__main__': userVip = UserVip('两点水') printUserInfo(userVip) userGeneral = UserGeneral('水水水') printUserInfo(userGeneral)
|
9. 类的访问控制
9.1 类属性的访问控制
Python 语言中没有真正的私有属性,用_
开头只是语法规范,并非无法访问
__
: 双下划线开头的属性是私有属性
, 只能被类内部访问_
: 单下划线开头的属性是受保护的属性
, 只能被类内部和子类访问- 不以下划线(
_
)开头的属性都是公共属性
, 可以被类内部, 子类和外部访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class UserInfo: lv = 5
def __init__(self, name, age, account): self.name = name self._age = age self.__account = account
def get_account(self): return self.__account
class UserInfo2(UserInfo): pass
if __name__ == '__main__': user_info_2 = UserInfo2('Tom', 18, '123456') print(user_info_2.get_account())
|
9.2 方法的访问控制
具体规则和类属性的访问控制一样,只是语法不同
1 2 3 4 5 6 7 8 9
| class User(object): def upgrade(self): pass
def _buy_equipment(self): pass
def __pk(self): pass
|
9.3 类专有的方法
方法 | 说明 |
---|
__init__ | 构造函数,在生成对象时调用 |
__del__ | 析构函数,释放对象时使用 |
__repr__ | 打印,转换 |
__setitem__ | 按照索引赋值 |
__getitem__ | 按照索引获取值 |
__len__ | 获得长度 |
__cmp__ | 比较运算 |
__call__ | 函数调用 |
__add__ | 加运算 |
__sub__ | 减运算 |
__mul__ | 乘运算 |
__div__ | 除运算 |
__mod__ | 求余运算 |
__pow__ | 乘方 |
当然有些时候我们需要获取类的相关信息,我们可以使用如下的方法:
type(obj)
:来获取对象的相应类型;isinstance(obj, type)
:判断对象是否为指定的 type 类型的实例;hasattr(obj, attr)
:判断对象是否具有指定属性/方法;getattr(obj, attr[, default])
获取属性/方法的值, 要是没有对应的属性则返回 default 值(前提是设置了 default),否则会抛出 AttributeError 异常;setattr(obj, attr, value)
:设定该属性/方法的值,类似于 obj.attr=value;dir(obj)
:可以获取相应对象的所有属性和方法名的列表: