学习 Python 之 面向对象
Posted _DiMinisH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习 Python 之 面向对象相关的知识,希望对你有一定的参考价值。
学习 Python 之 面向对象
python面向对象
类与对象, 类的最基本作用是封装
类的操作 | 如何操作 |
---|---|
类的定义 | 使用class 关键字 |
类的实例化 | 变量名 = 类名(参数) |
类函数的定义 | 使用classmethod 装饰器, 第一个参数代表该类 |
实例函数的定义 | 直接在类中定义函数, 第一个参数代表该对象 |
静态函数 | 使用staticmethod 装饰器 |
1. 类的定义
使用class
关键字定义一个类
类中可以定义变量, 定义函数
学生类
class Student:
name = ''
age = 0
def fun(self):
pass
2. 类的实例化
class Student:
name = ''
age = 0
def fun(self):
pass
student = Student()
3. 调用类中的实例方法
类中实例方法的一个参数代表对象本身, 它用来访问对象中的实例变量
class Student:
name = ''
age = 0
def fun(self):
print(self.name, self.age)
student = Student()
student.fun()
4. 使用实例变量
使用.
运算符
class Student:
def fun(self):
print(self.name, self.age)
student = Student()
print(student.name, student.age)
5. 类与对象
类是现实世界或思维世界中的实体在计算机中的反映, 它将数据以及这些数据上的操作封装在一起
类中的函数和变量称为数据成员
类的特征由成员变量表示, 类的行为由成员函数表示
6. 类的构造函数
构造函数用来初始化类中的变量, 构造函数的名字必须是__init__
def __init__(self):
pass
当对象实例化时, 会自动调用构造函数, 不需要显式的调用
class Student:
name = ''
age = 0
def fun(self):
print(self.name, self.age)
def __init__(self, name, age):
self.age = age
self.name = name
student = Student('a', 10)
student.fun()
a 10
注意:
- 构造函数只能返回None
- 构造函数可以显式调用, 但是返回值是None
- 定义了构造方法后, 如果构造方法需要传入参数, 创建对象时必须传入参数
7. 类变量与实例变量
(1). 理解类变量与实例变量
类变量: 与类相关的变量
实例变量: 与对象相关的变量, 即对象可以访问的变量
简单理解: 类中直接定义的变量是类变量, 使用self.xxx定义的变量是实例变量
学生类中, x
和y
是类变量
self.age
, self.name
是实例变量
class Student:
x = ''
y = 0
def fun(self):
print(self.name, self.age)
def __init__(self, name, age):
self.age = age
self.name = name
下面给实例变量赋值
student1 = Student('a', 10)
student2 = Student('b', 10)
注意打印结果
class Student:
x = ''
y = 0
def fun(self):
print(self.name, self.age)
def __init__(self, name, age):
self.name = name
self.age = age
student = Student('a', 10)
print(student.name)
print(Student.name)
a
AttributeError: type object 'Student' has no attribute 'name'
第一个输出的是对象的实例变量的值
第二个应该输出的是类的变量的值, 但是类没有该变量, 所以抛出异常了
类只能调用类变量, 实例可以调用实例变量和类变量
(2). 类变量和实例变量的查找顺序
使用内置属性__mro__
可以查看查找顺序
无继承
对于一个对象
class A:
pass
a = A()
print(a.x)
查找x
的顺序是: 实例变量 -> 查找类变量, 都没有就报错
单继承
查找的顺序是: 该类实例变量 -> 该类类变量 -> 父类实例变量 -> 父类的类变量, 都没有就报错
class A:
x = 'A的类变量'
def __init__(self):
# self.x = 'A的实例变量'
pass
class B(A):
# x = 'B的类变量'
def __init__(self):
super().__init__()
# self.x = 'B的实例变量'
b = B()
print(b.x)
结果:
A的类变量
多继承
查找顺序: C3算法
(3). __dict__
使用__dict__
类变量查看对象的实例变量
class Student:
name = '默认名字'
age = 0
def __init__(this, name, age):
pass
student = Student('a', 10)
print(student.__dict__)
这种情况下, student
对象无实例变量, 下面这种情况是有实例变量的
class Student:
name = '默认名字'
age = 0
def __init__(this, name, age):
this.name = name
this.age = age
student = Student('a', 10)
print(student.__dict__)
‘name’: ‘a’, ‘age’: 10
使用__dict__
类变量查看类变量
print(Student.__dict__)
__module__: '__main__', 'name': '默认名字', 'age': 0, '__init__': <function Student.__init__ at 0x000002A23B62E950>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None
8. 类中函数的第一个参数
类中方法的一个参数代表类本身, 它用来访问类中变量, 必须要创建, 它代表当前这个对象
当调用类中的方法时, 不用传值
实例方法: 对象可以调用的方法, 第一个参数必须指定, 代表当前这个对象
9. 类变量
类变量定义方式: 在类中定义 或 类外使用类名.xxx = vvv
class Student:
pass
Student.a = 5
print(Student.a)
结果:
5
直接在类外定义了一个类名变量, 这样的方式也可以定义实例变量
类变量使用方式: 类.变量名
或 self.__class__.变量名
class Student:
name = '默认名字'
age = 0
def __init__(this, name, age):
this.name = name
this.age = age
print(Student.name)
Student.name = 5
print('类中访问', this.__class__.name)
student = Student('a', 10)
print('类外访问', Student.name)
结果:
默认名字
类中访问 5
类外访问 5
9. 类函数(类方法)
(1). 定义
定义类方法, 使用@classmethod
装饰器
类方法的第一个参数代表类本身
class Student:
studentCount = 0
@classmethod
def fun(cls):
cls.studentCount += 1
print(cls.studentCount)
(2). 使用
Student.fun()
类方法关联类变量
实例方法关联实例变量
使用场景
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def fromString(cls, string):
year, month, day = string.split('-')
return cls(year, month, day)
def __str__(self):
return f"self.year/self.month/self.day"
date = Date.fromString('2022-6-5')
print(date)
结果:
2022/6/5
10. 静态方法
(1). 定义
定义类方法, 使用@staticmethod
装饰器
class Student:
studentCount = 0
@staticmethod
def fun(x):
print(x)
静态方法第一个参数不代表类本身, 而是一个参数
(2). 使用
类和对象都可以调用静态方法
class Student:
studentCount = 0
@staticmethod
def fun(x):
print(x)
student = Student()
student.fun(2)
Student.fun(3)
静态方法可以使用类变量
使用场景
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def fromString(cls, string):
year, month, day = string.split('-')
return cls(year, month, day)
@staticmethod
def validateDateString(string):
year, month, day = string.split('-')
if (month < 31) and (month > -1):
return True
else:
return False
def __str__(self):
return f"self.year/self.month/self.day"
date = Date.fromString('2022-6-5')
print(date)
结果:
2022/6/5
11. 布尔类型与类的关系
如果不手动写出这两个函数, 默认类对象的布尔值是True
实际上, 对象的布尔值取决与__bool__()
方法的返回值, 如果没有该方法, 取决于__len__()
方法的返回值
在魔法函数中详细解释
12. 魔法函数
在类中, 以__
双下划线开头和结尾的函数, 用于制定类的特性, 这些方法的调用是隐式的
使用hasattr(对象, 函数名) -> bool
方法可以检查该类对象是否有指定的函数
(1). 分类
非数字类
类别 | 函数 |
---|---|
字符串表示 | __repr__ , __str__ |
集合序列相关 | __len__ , __getitem__ , __setitem__ , __delitem__ , __contains__ |
迭代 | __iter__ , __next__ |
可调用 | __call__ |
with上下文管理器 | __enter__ , __exit__ |
数值转换 | __abs__ , __bool__ , __int__ , __float__ , __hash__ , __index__ |
元类相关 | __new__ , __init__ |
属性相关 | __get__ , __set__ , __delete__ |
协程 | __await__ , __aiter , __aenter__ , __aexit__ |
数字类
类别 | 函数 |
---|---|
一元运算符 | __neg__ 取反, __pos__ 取正, __abs__ 绝对值 |
二元运算符 | __lt__ 小于, __le__ 小于等于, __eq__ 等于, __ne__ 不等于, __gt__ 大于, __ge__ 大于等于 |
算术运算符 | __add__ 加法, __sub__ 减法, __mul__ 乘法, __truediv__ 除法, __floordiv__ 地板除, __mod__ 取余 |
算术运算符 | __divmod__ divmod()函数, __pow__ 乘方, __round__ 四舍五入取整 |
反向算术运算符 | __radd__ , __rsub__ , __rmul__ , __rtruediv__ , __rfloordiv__ , __rmod__ , __rdivmod__ , __rpow__ |
增量赋值算数运算符 | __iadd__ 加法, __isub__ 减法, __imul__ 乘法, _i_truediv__ 除法, __ifloordiv__ 地板除, __imod__ 取余, __ipow__ 乘方 |
位运算 | __invert__ 取反, __lshift__ 左移, __rshift__ 右移, __and__ 且, __or__ 或, __xor__ 异或 |
反向位运算 | __rinvert__ , __rlshift__ , __rrshift__ , __rand__ , __ror__ , __rxor__ |
增量赋值位运算符 | __ilshift__ 左移, __irshift__ 右移, __iand__ 且, __ior__ 或, __ixor__ 异或 |
(2). str(self)
函数 | 作用 |
---|---|
str(self) -> 字符串 | 对对象调用str()函数或者对象字符化时, 会隐式调用该方法 |
实际上, 调用print函数时, 首先会调用一次str函数
class Company:
def __init__(self, employeeList):
self.employee = employeeList
def __str__(self):
return "123"
company = Company(['tom', 'cat', 'bill'])
# 调用print会隐含调用str(company)
print(company)
结果:
123
(3). repr(self)
函数 | 作用 |
---|---|
repr(self) -> 字符串 | 打印时会隐式调用该方法 |
当__str__()
方法没有定义时, 对对象使用str()函数会调用该方法
在idle中直接输入变量, 会打印出结果, 这时调用的是该方法
class Company:
def __init__(self, employeeList):
self.employee = employeeList
def __repr__(self):
return '__repr__方法'
# def __str__(self):
# return '__str__方法'
company = Company(['tom', 'cat', 'bill'])
print(company)
print(str(company))
结果:
__repr__方法
__repr__方法
(4). getitem(self, item)
函数 | 作用 | 参数解释 |
---|---|---|
getitem(self, item) -> any | 可以允许该类对象使用[]访问类中数据, 访问的方式是自己实现, 实际类中有该方法, 该类对象是一个可迭代对象 | item: 索引值, 即a[0]中的0 |
类中有该方法, 该类对象是一个可迭代对象
使用索引方式访问对象,调用了__getitem__
函数
实际上, 实现了__iter__
函数才表示该类是一个迭代器, 可以用for-in遍历
但是python做了优化, 如果没有实现这个方法, 就会调用__getitem__
方法
class Company:
def __init__(self, employeeList):
self.employee = employeeList
def __getitem__(self, item):
return self.employee[item]
company = Company(['tom', 'cat', 'bill'])
for em in company:
print(em)
结果:
tom
cat
bill
当然, 你可以随便定义函数体
class Company:
def __init__(self, employeeList):
self.employee = employeeList
def __getitem__(self, item):
print('item的值', item)
return '调用了__getitem__函数'
company = Company(['tom', 'cat', 'bill'])
print(company[2.5])
结果:
item的值 2.5
调用了__getitem__函数
(5). len(self)
函数 | 作用 | 参数解释 |
---|---|---|
len(self) -> int或bool | 当对对象调用len()函数时隐式调用该函数, 如果没有__bool__函数时, 对对象调用bool()函数时也会隐式调用该函数 |
该方法的返回值是: int 和 bool 类型, 它与对象的布尔值相关
class A:
def __len__(self):
return 1
print(bool(A()))
class B:
def __len__(self):
return 0
print(bool(B()))
class C:
def __len__(self):
return True
print(bool(C()))
class D:
def __len__(self):
return False
print(bool(D()))
结果:
True
False
True
False
对对象使用bool()
和len()
函数时, 实际上调用的是__len__()
方法
class A:
def __len__(self):
return 1
print(bool(A()))
print(bool(len(A())))
结果:
True
True
但是, 如果没有手动定义__len__()
方法, 不能够对对象调用len()
函数
(6). bool(self) 方法
函数 | 作用 | 参数解释 |
---|---|---|
bool(self) -> bool | 当对对象调用bool()函数时会隐式调用该函数 |
该函数的返回值直接决定该类对象的布尔值
该函数的返回值必须是bool类型
class A:
def __len__(self):
return True
def __bool__(self):
return False
a: A = A()
print(bool(a))
结果:
False
13. 访问修饰符
(1). 私有变量
默认情况下, 定义的变量和函数可以在类外直接访问
使用__
开头的且结尾不是以__
结尾的变量或函数, 系统会认为是私有的, 不可以在类外直接访问
class Student:
__studentCount = 2
def __fun(self):
print(self.__studentCount)
student = Student()
print(student.__studentCount)
student.__fun()
这样访问是错误的, 会报错
注意下面这种情况
class Student:
__studentCount_ = 2
def __fun(self):
print(self.__studentCount_)
student = Student()
student.__studentCount_ = 5
print(student.__studentCount_)
结果
5
为什么这种情况可以直接访问呢?
因为student.__studentCount_ = 5
语句动态为student对象添加了一个__studentCount_
变量, 所以可以访问
查看一下, 改一下代码
class Student:
__studentCount_ = 2
def __fun(self):
print(self.__studentCount_)
student = Student()
student.__studentCount = 5
print(student.__studentCount)
print(student.__dict__)
5
‘__studentCount’: 5
(2). 类外访问私有变量
最好不要这么做, 不然定义私有变量就无意义了
访问方法_类名 + 私用变量名
class Student:
__v = '私有变量'
def fun(self):
print(self.__v)
student = Student()
print(student._Student__v)
结果
私有变量
14. 继承
python支持多继承, 即一个子类可以继承多个父类
语法:
class 类名(继承的类名):
pass
class People:
pass
class Student(People):
pass
object类
是所有类都要继承的一个基础类
使用__bases__
内置变量查看父类
class People:
pass
class Student(People):
pass
print(People.__bases__)
print(Student.__bases__)以上是关于学习 Python 之 面向对象的主要内容,如果未能解决你的问题,请参考以下文章