我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈
入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈
虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈
PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈
Oracle数据库教程:👉👉 Oracle数据库文章合集 👈👈
优 质 资 源 下 载 :👉👉 资源下载合集 👈👈
类&补充_内置私有属性&特殊方法
内置私有属性
内置类私有属性
- 内置类属性说明
__dict__ # 类的属性和值 __bases__ # 类的所有父类构成元组 __doc__ # 类的文档字符串 __name__ # 类名 __module__ # 类定义所在的模块
- 示例
class B(object): pass class Person(B,A): """Person类描述""" age = 18 def test(self): """test方法描述""" print('test方法') print(Person.__dict__) # 输出:{'__module__': '__main__', '__doc__': 'Person类描述', 'age': 18, 'test': <function Person.test at 0x000001F2C19D4280>} print(Person.__bases__) # 输出:(<class '__main__.A'>, <class '__main__.B'>) print(Person.__doc__) # 输出:Person类描述 print(Person.__name__) # 输出:Person print(Person.__module__) # 输出:__main__(主模块)
内置实例私有属性
- 内置实例属性说明
__dict__ # 实例的属性 __class__ # 实例对应的模块.类
- 示例
class A(object): pass class B(object): pass class Person(B,A): """Person类描述""" age = 18 def __init__(self): a = 99 self.b = 199 def test(self): """test方法描述""" c = 100 self.d = 200 print('test方法') p = Person() p.name = '失心疯' print(p.__dict__) # 输出:{'b': 199, 'name': '失心疯'} print(p.__class__) # 输出:<class '__main__.Person'>(主模块.Person类)
内置特殊方法
关于内置特殊方法
- 作用
- 当我们尝试去实现一些内置方法的时候,可以完成一些特定的功能
- 常见特定功能
- 初始化操作
- 信息格式化操作
- 调用操作
- 索引操作
- 切片操作
- 迭代器
- 描述器
- 实现不同的内置方法,可以完成实例不同的特定操作
内置特殊方法分类
生命周期方法
- 下一章节单独介绍
其他内置方法
初始化操作
- 作用
- 用于初始化实例变量。实例变量是对象的属性,用于存储数据
- 实现方法
__init__
方法
- 示例代码
class Person(object): def __init__(self, name, age): self.name = name self.age = age self.source = '地球' p1 = Person('张三', 18) p2 = Person('李四', 36) print(p1.name, p1.age, p1.source) # 输出:张三 18 地球 print(p2.name, p2.age, p2.source) # 输出:李四 36 地球
信息格式化操作
- 作用
- 访问实例对象的时候,自动调用执行这个操作方法
- 实现方法
__str__
方法__repr__
方法
__str__方法
示例class Person(object): def __init__(self): print('实例化对象的时候,自动调用__init__方法') self.name = '失心疯' self.age = 36 def __str__(self): return f'调用__str__方法,我的名称是:{self.name}, 年龄是:{self.age}' p = Person() # 输出:实例化对象的时候,自动调用__init__方法 print(p) # 输出:调用__str__方法,我的名称是:失心疯, 年龄是:36
__repr__方法
示例class Person(object): def __init__(self): print('实例化对象的时候,自动调用__init__方法') self.name = '失心疯' self.age = 36 def __str__(self): return f'调用__str__方法,我的名称是:{self.name}, 年龄是:{self.age}' def __repr__(self): return f'调用__repr__方法,我的名称是:{self.name},年龄是:{self.age}' p = Person() # 输出:实例化对象的时候,自动调用__init__方法 print(p) # 输出:调用__str__方法,我的名称是:失心疯, 年龄是:36 s = str(p) print(s, type(s)) # 调用__str__方法,我的名称是:失心疯, 年龄是:36 <class 'str'> r = repr(p) print(r, type(r)) # 调用__repr__方法,我的名称是:失心疯,年龄是:36 <class 'str'> p # 无输出
__str__
和__repr__
的区别-
__str__
和__repr__
大致差不多,都是通过一个字符串来描述这个对象 -
但是
__str__
和__repr__
面向的角色不一样__str__
面向的角色是用户,看起来比较友好,易懂__repr__
面向的角色是开发人员(Python解释器),是为了让开发人员看到这个实例的本质(如:类型、内存地址),或者Python解释器通过eval这个函数再次把它处理成相关的实例对象
-
在PyCharm中执行情况
-
在Python解释器中执行情况
-
eval函数转换
import datetime t = datetime.datetime.now() print(t) # 执行__str__方法,输出:2023-11-04 21:07:49.773549 print(repr(t)) # 行__repr__方法,输出:datetime.datetime(2023, 11, 4, 21, 7, 49, 773549) res = repr(t) print(res) # 输出:datetime.datetime(2023, 11, 4, 21, 22, 53, 180571) print(eval(res)) # eval函数,输出:2023-11-04 21:09:06.275814 # eval函数:将字符串str当成有效的表达式来求值并返回计算结果 # eval(repr(t)) 相当于是下面的步骤 aa = datetime.datetime(2023, 11, 4, 21, 7, 49, 773549) print(aa)
-
调用操作
-
作用
- 使得“对象”具备当做函数来调用的能力
-
实现方法
-
__call__方法
-
默认实例化对象是不能被调用的
class Person(object): pass p = Person() p()
-
添加
__call__
方法后,实例化对象就可以实现调用功能class Person(object): def __call__(self, *args, **kwargs): print('__call__方法,实现调用功能') p = Person() p()
-
同样,实例对象在调用的时候也是可以传入参数的
class Person(object): def __call__(self, *args, **kwargs): print('__call__方法,实现调用功能') print('接收参数:', args, kwargs) p = Person() p(123, 456, 888, name='失心疯')
-
-
应用场景
- 场景要求:创建很多个画笔,画笔的类型(钢笔.铅第),画笔的颜色(红色、蓝色、黄色、绿色…)
- 实现方法一:使用偏函数
# 正常情况 # def penFatory(pen_type, pen_color): # print(f'生产一支{pen_type}类型的笔,颜色是:{pen_color}') # # # gb1 = penFatory('钢笔','红色') # gb2 = penFatory('钢笔','蓝色') # gb3 = penFatory('钢笔','黄色') # gb4 = penFatory('钢笔','绿色') # 在生成多种颜色的钢笔时,每次都要重复输入笔的类型:钢笔,这个比较累赘 # 通过偏函数方式来优化 # # 方式一:自定义偏函数 # def penFatory(pen_type, pen_color): # print(f'生产一支{pen_type}类型的笔,颜色是:{pen_color}') # # # 定义偏函数 # def newPenFatory(new_color, new_type='钢笔'): # penFatory(new_type, new_color) # # # gb1 = newPenFatory('红色') # gb2 = newPenFatory('蓝色') # gb3 = newPenFatory('黄色') # gb4 = newPenFatory('绿色') # 方式二:使用标准库functools import functools # 这里需要注意的是,需要将定义偏函数时传递的参数放到最后,否在则定义实例的时候会报错 def penFatory(pen_color, pen_type): print(f'生产一支{pen_type}类型的笔,颜色是:{pen_color}') newPenFatory = functools.partial(penFatory, pen_type='钢笔') gb1 = newPenFatory('红色') gb2 = newPenFatory('黄色') gb3 = newPenFatory('蓝色') gb3 = newPenFatory('绿色')
- 实现方法二:使用
__call__
方法# 使用__call__方法 class PenFatory(object): def __init__(self, pen_type): self.type = pen_type def __call__(self, pen_color): print(f'生产一支{self.type}类型的笔,颜色是:{pen_color}') gb = PenFatory('钢笔') # 实例化对象的时候,定义其类型为:钢笔 gb('黄色') # 每次调用,设置其颜色 gb('绿色') gb('蓝色') gb('红色')
索引操作
- 作用
- 可以对一个实例对象进行索引操作(将我们所创建出来的实例对象,可以以一个字典或者列表的方式来进行操作)
- 实现步骤
- 1、实现三个内置方法
__setitem__
方法__getitem__
方法__delitem__
方法- 语法示例
class Person(object): def __setitem__(self, key, value): print('setitem', key, value) def __getitem__(self, item): print('getitem', item) def __delitem__(self, key): print('delitem', key)
- 2、可以以索引的形式操作对象
- 增/改
p[1] = 666 p['s'] = '失心疯'
- 查
p[1] p['s']
- 删
del p['s'] del p[1]
- 增/改
- 示例代码
class Person(object): def __init__(self): self.cache = {} def __setitem__(self, key, value): self.cache[key] = value def __getitem__(self, item): return self.cache[item] def __delitem__(self, key): del self.cache[key] p = Person() p['name'] = '失心疯' print(p['name']) del p['name']
- 1、实现三个内置方法
切片操作
- 作用
- 可以对一个实例对象进行切片操作
- 实现步骤
- (已过期)Python2.x版本中通过
__setspic__
、__getspic__
、__delspic__
三个方法实现 - Python3.x版本中统一由索引操作进行管理
__setitem__
、__getitem__
、__delitem__
- (已过期)Python2.x版本中通过
- 代码示例
class Person(object): def __init__(self): self.list = [1, 2, 3, 4, 5, 6, 7, 8, 9] def __setitem__(self, key, value): print(key, value) self.list[key] = value def __getitem__(self, item): print(item) return self.list[item] def __delitem__(self, key): print(key) del self.list[key] p = Person() # 通过切片操作进行值的修改(切片操作不能直接添加值) p[0:4:2] = ['a', 'b'] # 执行__setitem__方法,输出:slice(0, 4, 2) ['a', 'b'] # 从输出结果可以看到,key是一个slice实例对象(切片对象) # 查看 slice 切片实例对象 源码 # start = property(lambda self: 0) # 获取起始索引 # """:type: int""" # # step = property(lambda self: 0) # 获取步长 # """:type: int""" # # stop = property(lambda self: 0) # 获取结束索引 # """:type: int""" # 通过切片获取值 p[0:4:1] # 执行__getitem__方法,输出:slice(0, 4, 1) # 通过切片删除值 del p[0:2:1] # 执行__delitem__方法,输出:slice(0, 2, 1) p[:] # 通过删除操作后,输出:['b', 4, 5, 6, 7, 8, 9]
- 切片操作与索引操作都是通过
__setitem__
、__getitem__
、__delitem__
三个方法统一管理,所以我们在编写这三个方法的时候需要进行容错处理class Person(object): def __init__(self): self.cache = {} self.list = [1, 2, 3, 4, 5, 6, 7, 8, 9] def __setitem__(self, key, value): # 判断key是否是slice类的子类 if issubclass(key, slice): self.list[key] = value else: self.cache[key] = value def __getitem__(self, item): if issubclass(item, slice): return self.list[item] else: return self.cache[item] def __delitem__(self, key): if issubclass(key, slice): del self.list[key] else: del self.cache[key]
比较操作
- 作用
- 自定义两个对象“比较大小、是否相等”的规则
- 比较运算符:=、!=、>、>=、<、<=
- 实现步骤
- 通过以下方法分别实现
__eq__:是否等于(==)比较时,自动执行(没有写__ne__方法时,不等于比较时,会执行该方法) __ne__:是否不等于(!=)比较时,自动执行(不等于比较时,优先执行该方法) __gt__:是否大于(>)比较时,自动执行 __ge__:是否大于等于(>=)比较时,自动执行 __lt__:是否小于(<)比较时,自动执行 __le__:是否小于等于(<=)比较时,自动执行
- 示例代码
class Person(object): def __init__(self, age, width): self.age = age self.width = width # 通过下面方法设定两个对象进行比较时,比较的是age属性值 def __eq__(self, other): """实例对象进行 == 比较时,自动调用""" return '__eq__方法', self.age == other.age def __ne__(self, other): """实例对象进行 != 比较时,自动调用""" return '__ne__方法', self.age != other.age def __gt__(self, other): """实例对象进行 > 比较时,自动调用""" return '__gt__方法', self.age > other.age def __ge__(self, other): """实例对象进行 >= 比较时,自动调用""" return '__ge__方法', self.age >= other.age def __lt__(self, other): """实例对象进行 < 比价时,自动调用""" return '__lt__方法', self.age < other.age def __le__(self, other): """实例对象进行 <= 比较时,自动调用""" return '__le__方法', self.age <= other.age p1 = Person(18, 160) p2 = Person(17, 180) print(p1 == p2) # 输出:('__eq__方法', False) print(p1 != p2) # 输出:('__ne__方法', True) print(p1 > p2) # 输出:('__gt__方法', True) print(p1 >= p2) # 输出:('__ge__方法', True) print(p1 < p2) # 输出:('__lt__方法', False) print(p1 <= p2) # 输出:('__le__方法', False)
- 注意事项
- 1、如果对于方向操作的比较符(= 与 !=,> 与 <) ,只定义了其中一个昂发,但使用的是另一种比较运算时,解释器会采用调换参数的方式进行调用该方法
class Person(object): def __init__(self, age, name): self.age = age self.name = name def __lt__(self, other): """实例对象进行 < 比价时,自动调用""" print('self:', self.name, self.age) print('other:', other.name, other.age) return self.age < other.age p1 = Person(18, 'p1') p2 = Person(19, 'p2') print(p1 < p2) # self: p1 18 # other: p2 19 # True print(p1 > p2) # 实际执行的是 p2 < p1 比较 # self: p2 19 # other: p1 18 # False
- 2、几个方法不支持叠加操作(有==和<比较,并不能实现 <= 比较)
class Person(object): def __init__(self, age): self.age = age def __eq__(self, other): """实例对象进行 == 比较时,自动调用""" return self.age == other.age def __lt__(self, other): """实例对象进行 < 比价时,自动调用""" return self.age < other.age p1 = Person(18) p2 = Person(19) print(p1 == p2) # 输出:False print(p1 < p2) # 输出:True print(p1 <= p2) # 报错:TypeError: '<=' not supported between instances of 'Person' and 'Person'
- 3、通过一个装饰器(
functools.total_ordering
)实现方法叠加操作(实现==和<方法,即可实现 != 、> 、>=、<=的比较)import functools @functools.total_ordering class Person(object): def __init__(self, age, name): self.age = age self.name = name def __eq__(self, other): """实例对象进行 == 比较时,自动调用""" print('__eq__方法') return self.age == other.age def __lt__(self, other): """实例对象进行 < 比价时,自动调用""" print('__lt__方法', self.name, other.name) return self.age < other.age # print(Person.__dict__) """ 输出:{'__module__': '__main__', '__init__': <function Person.__init__ at 0x00000138AF224280>, '__eq__': <function Person.__eq__ at 0x00000138AF244A60>, '__lt__': <function Person.__lt__ at 0x00000138AF2451F0>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, '__hash__': None, '__gt__': <function _gt_from_lt at 0x00000138AF074DC0>, '__le__': <function _le_from_lt at 0x00000138AF074E50>, '__ge__': <function _ge_from_lt at 0x00000138AF074EE0>} """ p1 = Person(29, 'p1') p2 = Person(29, 'p2') print(p1 == p2) # 输出:__eq__方法 True print(p1 != p2) # 输出:__eq__方法 False # print(p1 < p2) # 输出:__lt__方法 False print(p1 <= p2) # 输出:__lt__方法 __eq__方法 True # 首先执行 < 判断,返回True, 则结束, # 返回False,再执行 == 判断 # print(p1 > p2) # 输出:__lt__方法 __eq__方法 False # 首先执行 < 判断,返回True, 则结束,返回:<判断结果取反False # 返回False, 再执行 == 判断,返回:==判断结果取反 print(p1 >= p2) # 输出:__lt__方法 True # 首先执行 < 判断,最终返回:<判断结果取反 # < 判断结果为True,则不会是大于和等于,所以返回False # < 判断结果为False, 则不是大于就是等于,所以返回True
- 1、如果对于方向操作的比较符(= 与 !=,> 与 <) ,只定义了其中一个昂发,但使用的是另一种比较运算时,解释器会采用调换参数的方式进行调用该方法
上下文布尔值
- 作用
- 控制实例对象返回的布尔值(True/False)
- 实现步骤
__bool__
方法控制- 非0即真,非空即真
- 示例代码
# 对比示例 class Person(object): pass p = Person() # 非空即真,p是实例对象,并非为空,所以判断为真,执行下面代码 if p: print('xxxxx') else: print('yyyyy') # 输出:xxxxx # __bool__方法演示示例 class Person(object): def __bool__(self): return False p = Person() if p: print('xxxxxx') else: print('yyyyyy') # 输出:yyyyyy
- 通过
__bool__
方法,我们就可以控制实例对象判断的返结果 - 如:如果实例对象的年龄大于18则返回True,否则返回False
class Person(object): def __init__(self, age, name): self.age = age self.name = name def __bool__(self): return self.age > 18 p1 = Person(16, 'p1') p2 = Person(26, 'p2') ps = [p1, p2] for p in ps: if p: print(f'{p.name}已经成年啦') else: print(f'{p.name}还是未成年') # 输出结果 # p1还是未成年 # p2已经成年啦
遍历操作
-
作用
- 实现通过遍历操作访问实例对象(能进行
for...in..
遍历 和next()
函数访问操作)
- 实现通过遍历操作访问实例对象(能进行
-
实现步骤
__getitem__
方法__iter__
+__next__
方法(优先级更高)
-
示例代码
-
对比示例
class Person(object): pass p = Person() for i in p: print('xxxx') # 输出结果:报错 # TypeError: 'Person' object is not iterable
-
__getitem__
方法示例class Person(object): def __init__(self): self.age = 18 def __getitem__(self, item): self.age += 1 if self.age > 30: raise StopIteration('年龄太大了...') return self.age p = Person() # for..in..操作会不断调用__getitem__方法,直到该方法抛出异常(raise StopIteration) for i in p: print(i)
-
这里的
for..in..
遍历是直接调用__getitem__
方法 -
__iter__
+__next__
方法示例class Person(object): def __init__(self): self.age = 18 def __iter__(self): print('xxxx') """实例对象调用iter()方法的时候自动调用,需要返回一个迭代器(iterator)对象""" return self def __next__(self): """实例对象使用next()函数的时候自动调用该方法""" self.age += 1 if self.age > 30: raise StopIteration('年龄太大了!') return self.age p = Person() # 通过for..in..遍历 # 1、先通过iter()方法将实例对象转换成一个迭代器 # iter(p) # 输出:xxxx # 2、再调用next()方法取值 for i in p: print(i) # 通过next()函数取值 print(next(p)) print(next(p)) print(next(p)) print(next(p))
-
这里的
for..in..
实际是先通过iter()
方法将实例对象转换成迭代器对象,再调用next()
方法- 执行
iter()
方法的时候会自动调用__iter__()
方法 - 执行
next()
方法的时候会自动调用__next__()
方法
- 执行
补充:迭代相关内容
-
可使用
next()
方法:对象内部实现__next__()
方法class Person(object): def __init__(self): self.age = 18 def __next__(self): self.age += 1 if self.age > 20: raise StopIteration return self.age p = Person() print(next(p)) # 19 print(next(p)) # 20 import collections # 判断实例对象是否是可迭代对象 print(isinstance(p, collections.Iterable)) # False # 判断实例对象是否是迭代器 print(isinstance(p, collections.Iterator)) # False
-
可迭代对象:对象内部实现
__iter__()
方法class Person(object): def __init__(self): self.age = 18 def __iter__(self): return self p = Person() # print(next(p)) # 报错:TypeError: 'Person' object is not an iterator # print(next(p)) # 报错:TypeError: 'Person' object is not an iterator from collections import abc # 判断实例对象是否是可迭代对象 print(isinstance(p, abc.Iterable)) # True # 判断实例对象是否是迭代器 print(isinstance(p, abc.Iterator)) # False
-
迭代器:对象内部既要实现
__next__()
方法又要实现__iter__()
方法class Person(object): def __init__(self): self.age = 18 def __iter__(self): return self def __next__(self): self.age += 1 if self.age > 20: raise StopIteration return self.age p = Person() from collections import abc # 判断实例对象是否是可迭代对象 print(isinstance(p, abc.Iterable)) # True # 判断实例对象是否是迭代器 print(isinstance(p, abc.Iterator)) # False print(next(p)) # 19 print(next(p)) # 20
-
iter()
函数的使用- 作用:将一个实例对象转换成一个迭代器
-
语法
iter(实例对象) iter(可执行对象, 值)
-
iter(实例对象)
模式将实例对象转换成迭代器-
想要通过
for..in..
遍历自定义实例对象,可以通过以下两种方式- 1、在自定义实例对象中实现
__getitem__()
方法 - 2、在自定义实例对象中实现
__iter__()
方法和__next__()
方法
- 1、在自定义实例对象中实现
-
要想使用
iter()
方法将自定义实例转换成一个迭代器,必须通过以下两种方法中的任意一种- 1、在自定义实例对象中实现
__getitem__()
方法 - 2、在自定义实例对象中实现
__iter__()
方法和__next__()
方法
- 1、在自定义实例对象中实现
-
示例1:实例对象内部实现
__getitem__()
方法class Person(object): def __init__(self): self.age = 18 def __getitem__(self, item): self.age += 1 if self.age > 25: raise StopIteration return self.age p = Person() pt = iter(p) print(pt) # <iterator object at 0x000002626777DF10> for i in pt: print(i) # 输出结果 # 19 # 20 # 21 # 22 # 23 # 24 # 25
-
示例2:在实例对象内部只实现
__iter__()
方法class Person(object): def __init__(self): self.age = 18 def __iter__(self): return self p = Person() pt = iter(p) # 报错:TypeError: iter() returned non-iterator of type 'Person' # 报错原因: # 使用iter()函数时会自动调用__iter__()方法,__iter__()方法要求返回值是一个迭代器,此处返回的是self(示例对象本身) # 但是此时的Person类内部仅仅只实现了__iter__()方法,并没有实现__next__()方法,所以Person类实例化出来的对象仅仅是一个可迭代对象并不是一个迭代器
-
示例3:在示例对象内部实现
__iter__()
方法和__next__()
方法class Person(object): def __init__(self): self.age = 18 def __iter__(self): return self def __next__(self): self.age += 1 if self.age > 25: raise StopIteration return self.age p = Person() pt = iter(p) print(pt) # 输出:<__main__.Person object at 0x000001B574C4DFD0> # 执行iter()函数,实际就是执行的自定义类对象中的__iter__()方法,返回的是self(Person实例化对象本身p) # 因为Person类内部实现了`__iter__()`方法和`__next__()`方法,所以实例化出来的对象p就是一个迭代器 # 因此:pt就是p,就是一个迭代器,就可以通过for..in..遍历,也可以通过next()函数访问值 print(pt == p, pt is p) # 输出:True True # for i in pt: # print(i) print(next(p)) print(next(p))
-
- 特殊方法汇总
__init__(self)
# 创建实例化对象的时候会自动调用
__setattr__(self, key, value)
# 实例新增/修改属性的时候自动调用
__str__(self)
# 访问实例对象的时候自动调用
__repr__(self)
# 访问实例对象的时候自动调用
__setitem__(self, key, value)
# 实例对象以key-value的方式添加属性和值的时候自动调用
# 实例对象通过切片进行值修改的时候自动调用,key是slice类型
__getitem__(self, item)
# 实例对象以key-value的方式获取属性值的时候自动调用
# 实例对象通过切片进行值获取的时候自动调用,item是slice类型
# 实例对象进行for..in..遍历时候不断调用该方法,直到方法抛异常,优先级低于__iter__方法
__delitem__(self, key)
# 实例对象以key-value的方式删除属性和值的时候自动调用
# 实例对象通过切片进行值删除的时候自动调用,key是slice类型
__eq__(self, other):
# 实例对象进行 == 比较时,自动调用
__ne__(self, other):
# 实例对象进行 != 比较时,自动调用
__gt__(self, other):
# 实例对象进行 > 比较时,自动调用
__ge__(self, other):
# 实例对象进行 >= 比较时,自动调用
__lt__(self, other):
# 实例对象进行 < 比价时,自动调用
__le__(self, other):
# 实例对象进行 <= 比较时,自动调用