33.Python面向对象类的专有方法__iter____getitem____getattr____call____new____init__
Posted 孤寒者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了33.Python面向对象类的专有方法__iter____getitem____getattr____call____new____init__相关的知识,希望对你有一定的参考价值。
目录:
每篇前言:
🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者
- 🔥🔥本文已收录于Python全栈系列专栏:《Python全栈基础教程》
- 🔥🔥热门专栏推荐:《Django框架从入门到实战》、《爬虫从入门到精通系列教程》、《爬虫高级》、《前端系列教程》、《tornado一条龙+一个完整版项目》。
- 📝📝本专栏面向广大程序猿,为的是大家都做到Python从入门到精通,同时穿插有很多很多习题,巩固学习。
- 🎉🎉订阅专栏后可私聊进一千多人Python全栈交流群(手把手教学,问题解答); 进群可领取Python全栈教程视频 + 多得数不过来的计算机书籍:基础、Web、爬虫、数据分析、可视化、机器学习、深度学习、人工智能、算法、面试题等。
- 🚀🚀加入我一起学习进步,一个人可以走的很快,一群人才能走的更远!
Python面向对象(六)
1.1 类的专有方法
__init__
: 构造函数,在生成对象时调用
__del__
: 析构函数,释放对象时使用
__repr__
: 打印,转换
__str__( self )
:用于将值转化为适于人阅读的形式
__setitem__
: 按照索引赋值
__getitem__
: 按照索引获取值
__len__
: 获得长度
__call__
: 函数调用
__add__
: 加运算
__sub__
: 减运算
__mul__
: 乘运算
__truediv__
: 除运算
__mod__
: 求余运算
__pow__
: 乘方
基础重写方法:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
import math
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%s, %s)' % (self.a, self.b)
def __repr__(self):
return self.__str__()
def __add__(self, other):
return Vector(self.a + other.a, self.b + other.b)
def __sub__(self, other):
return Vector(self.a - other.a, self.b - other.b)
def __mul__(self, other):
return Vector(self.a * other.a, self.b * other.b)
def __truediv__(self, other):
return Vector(self.a / other.a, self.b / other.b)
def __mod__(self, other):
return Vector(self.a % other.a, self.b % other.b)
def __pow__(self, other):
return Vector(self.a ** other.a, self.b ** other.b)
v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)
print(v1 - v2)
print(v1 * v2)
print(v1 / v2)
print(v1 % v2)
print(v1 ** v2)
sorted_key = lambda v: math.sqrt(v.a ** 2 + v.b ** 2)
l = sorted([Vector(2, 10), Vector(3.5, 10), Vector(5, 8), Vector(4, 3)], key=sorted_key)
print(l)
1.1.1 __iter__
- 如果一个类想被用于循环for…in,类似list或tuple那样,就必须实现一个方法__iter__(),该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的 next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
- 我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
for n in Fib():
print(n, end=",")
1.1.2 __getitem__
- 要表现得像list那样按照下标取出元素,需要实现方法:
__getitem__()
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
- 现在,就可以按下标访问数列的任意一项了。
- 对于切片方法[5:10],将传入slice对象,所以要做判断:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Fib(object):
def __getitem__(self, n):
if isinstance(n, int):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice):
start = n.start
stop = n.stop
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
- 这个例子没有对step参数和负数作处理,所以,要正确实现一个
__getitem__()
还是有很多工作要做的。
1.1.3 __getattr__
- 正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。
- 要避免这个错误,除了可以加上一个相应属性外,Python还有另一个机制,那就是写一个
__getattr__()
方法,动态返回一个属性。修改如下:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Student(object):
def __init__(self):
self.name = 'Michael'
def __getattr__(self, attr):
if attr=='score':
return 99
- 当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, ‘score’)来尝试获得属性。
- 返回函数也完全可以:
class Student(object):
def __getattr__(self, attr):
if attr=='age':
return lambda: 25
-
注意,只有在没有找到属性的情况下,才调用
__getattr__
,已有的属性不会在__getattr__
中查找。 -
链式调用示例:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Chain(object):
def __init__(self, path=''):
self._path = path
def __getattr__(self, path):
if path == 'users':
return lambda user: Chain('%s/users/%s' % (self._path, user))
return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
print(Chain().status.user.timeline.list)
print(Chain().status.users('xiaoxiaoming').repos)
1.1.4 __call__实例方法
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
s = Student('Michael')
s()
__call__()
还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。- 如果你把对象看成函数,那么函数本身其实也可以在运行期动态创建出来,因为类的实例都是运行期创建出来的,这么一来,我们就模糊了对象和函数的界限。
- 通过callable()函数可以判断一个对象是否是“可调用”对象:
>>> callable(Student())
True
>>> callable(max)
True
>>> callable([1, 2, 3])
False
>>> callable(None)
False
>>> callable('string')
False
1.1.5 __new__和__init__方法
__new__
和__init__
的作用:
__new__
至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供。__new__
必须要有返回值,返回实例化出来的实例。__init__
有一个参数self,就是这个__new__
返回的实例,__init__
在__new__
的基础上可以完成一些其它初始化的动作,__init__
不需要返回值。
实战讲解:
# -*- coding: utf-8 -*-
"""
__author__ = 小小明-代码实体
"""
class A(object):
def __init__(self):
print("__init__内部:", self, id(self))
def __new__(cls):
print("__new__内部:", cls, id(cls))
obj = object.__new__(cls)
print("__new__方法返回值:", obj, id(obj))
return obj
a = A()
print("主程序:", a, id(a))
print("-----------")
b = A()
print("主程序:", b, id(b))
- 可以看出,每次创建对象,都会先调用__new__方法,构建出对象,然后调用__init__方法,并将刚才创建的对象传入。
拓展:Linux中文本模式下怎么运行我们的python文件?
知识点补给站:
关于虚拟环境有篇文章有详细的介绍——《如何管理你下载的一大堆Python包【❤️win环境及linux环境下创建虚拟环境详解❤️】》
以上是关于33.Python面向对象类的专有方法__iter____getitem____getattr____call____new____init__的主要内容,如果未能解决你的问题,请参考以下文章
33.Python面向对象类的专有方法__iter____getitem____getattr____call____new____init__