kmeans python interation flag_Python自学笔记-第六章面向对象编程(下)

3.魔法方法

Python的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切。他们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一切都是自动发生的。

总之,Python 的魔术方法非常强大。

下面将列举这些魔法方法,并有针对性的对部分重点方法进行阐述。

3.1.基本的魔法方法

b042e9e08bc1e02e16396fc076c0fc4d.png

3.1.1.__new__和__init__

__new__方法是真正的类构造方法,用于产生实例化对象(空属性)。重写__new__方法可以控制对象的产生过程。

__init__方法是初始化方法,负责对实例化对象进行属性值初始化,此方法必须返回None,__new__方法必须返回一个对象。重写__init__方法可以控制对象的初始化过程。

使用__new__创建单例模式

class Person(object):

__instance = None

__init_flag = False

def __new__(cls, name):

if cls.__instance == None:

cls.__instance = object.__new__(cls)

return cls.__instance

else:

# 返回上一次创建的对象的引用

return cls.__instance

def __init__(self,name):

if Person.__init_flag == False:

self.name = name

Person.__init_flag = True

aP = Person('小明')

print(id(aP))

print(aP.name)

运行结果:

140005334645616

小明

bP = Person('小王')

print(id(bP))

print(bP.name)

运行结果:

140005334645616

小明

3.1.2.__str__和__repr__

两者的目的都是为了显式的显示对象的一些必要信息,方便查看和调试。__str__被print默认调用,__repr__被控制台输出时默认调用。即,使用__str__控制用户展示,使用__repr__控制调试展示。

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

p = Person('小明', 26)

print(p)

运行结果:

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

def __str__(self):

return f'{self.__class__}, {self.name}, {self.age}'

p = Person('小明', 26)

print(p)

运行结果:

, 小明, 26

3.1.3.__call__

__call__方法提供给对象可以被执行的能力,就像函数那样,而本质上,函数就是对象,函数就是一个拥有__call__方法的对象。拥有__call__方法的对象,使用callable可以得到True的结果,可以使用()执行,执行时,可以传入参数,也可以返回值。所以我们可以使用__call__方法来实现实例化对象作为装饰器:

对象变为可调用的

class Person(object):

def __init__(self, name):

self.name = name

def __call__(self, friend):

print('My name is %s...' % self.name)

print('My friend is %s...' % friend)

p = Person('小明')

p('小王')

运行结果:

My name is 小明...

My friend is 小王...

实例对象版本装饰器

class Checker:

def __init__(self, require_num):

self.require_num = require_num

def __call__(self, func):

self.func = func

def inner(*args, **kw):

if len(args) != self.require_num:

print('函数参数个数不符合预定义,无法执行函数')

return None

return self.func(*args, **kw)

return inner

@Checker(2)

def show(*args):

print('show函数成功执行!')

show(1)

运行结果:

函数参数个数不符合预定义,无法执行函数

3.1.4.__del__

__del__用于当对象的引用计数为0时自动调用。

__del__一般出现在两个地方:1、手工使用del减少对象引用计数至0,被垃圾回收处理时调用。2、程序结束时调用。

__del__一般用于需要声明在对象被删除前需要处理的资源回收操作

手工调用del 可以将对象引用计数减一,如果减到0,将会触发垃圾回收

class Person:

def __del__(self):

print('调用对象的del方法,此方法将会回收此对象内存地址')

p = Person() # 调用对象的__del__方法回收此对象内存地址

del p

print('下面还有程序其他代码')

运行结果:

调用对象的del方法,此方法将会回收此对象内存地址

下面还有程序其他代码

程序直接结束,也会调用对象的__del__方法回收地址

3.2.属性相关

921f13ae7e5c17ee5b363513e144da3f.png

相关使用说明,已经在描述符章节进行了阐述,这里再次总结下:

当使用obj.x = y的时候触发对象的setattr方法,当del obj.x的时候触发对象的delattr方法。

当尝试访问对象的一个不存在的属性时,会触发getattr方法,getattr方法是属性查找中优先级最低的。

如果定义了__getattr__,而没有任何代码(即只有pass),则所有不存在的属性值都是None而不会报错,可以使用super().__getattr__()方法来处理

__getatrribute__是一个属性访问截断器,即,在你访问属性时,这个方法会把你的访问行为截断,并优先执行此方法中的代码,此方法应该是属性查找顺序中优先级最高的。

属性查找顺序:实例的getattribute-->实例对象字典-->实例所在类字典-->实例所在类的父类(MRO顺序)字典-->实例所在类的getattr-->报错

3.3.比较操作符

469f38d5ab9bf116d01f5a223102d430.png

class Car():

def __init__(self,carname,oilcp100km, price):

self.carname,self.oilcp100km,self.price = carname,oilcp100km, price

def __lt__(self,other):

print("execute __lt__")

return self.price

car1,car2 = Car('爱丽舍',8,10),Car('凯美瑞',7,27)

car1>car2

运行结果:

execute __lt__

False

3.4.算数运算符

fc64987b3abcb4f2fe7ab2e5080473f4.png

3.5.反运算

ec8e5e0d08639e4844c1127aa8b89f9e.png

3.6.增量赋值运算

91d4f4825dc509ad193fde6c285cacce.png

3.7.一元操作符

2980f83a56dbacf75c9629db8cc5b926.png

3.8.类型转换

d0a8253a0d27feaba8002d957ff3b7b6.png

3.9.上下文管理(with 语句)

cc208a9746e8e78baf074643482417b6.png

这两个方法的重写可以让我们对一个对象使用with方法来处理工作前的准备,以及工作之后的清扫行为。

class MySQL:

def connect(self):

print('启动数据库连接,申请系统资源')

def execute(self):

print('执行sql命令,操作数据')

def finish(self):

print('数据库连接关闭,清理系统资源')

def __enter__(self): # with的时候触发,并赋给as变量

self.connect()

return self

def __exit__(self, exc_type, exc_val, exc_tb): # 离开with语句块时触发

self.finish()

with MySQL() as mysql:

mysql.execute()

运行结果:

启动数据库连接,申请系统资源

执行sql命令,操作数据

数据库连接关闭,清理系统资源

3.10.容器类型

14ccb56ac060a2b5e7be8c157665ad83.png

3.10.1.__iter__和__next__

这2个方法用于将一个对象模拟成序列。内置类型如列表、元组都可以被迭代,文件对象也可以被迭代获取每一行内容。重写这两个方法就可以实现自定义的迭代对象。

定义一个指定范围的自然数类,并可以提供迭代,使用for循环则不提示StopInteration错误

class Num:

def __init__(self, max_num):

self.max_num = max_num

self.count = 0

def __iter__(self):

return self

def __next__(self):

if self.count < self.max_num:

self.count += 1

return self.count

else:

raise StopIteration('已经到达临界')

num = Num(10)

for i in num:

print(i) # 循环打印1---10

运行结果:

1

2

3

4

5

6

7

8

9

10

使用next()方法依次迭代,最后提示StopInteration错误

num = Num(2)

print(next(num))

print(next(num))

print(next(num))

运行结果:

1

2

---------------------------------------------------------------------------

StopIteration Traceback (most recent call last)

in

2 print(next(num))

3 print(next(num))

----> 4 print(next(num))

in __next__(self)

13 return self.count

14 else:

---> 15 raise StopIteration('已经到达临界')

16

17 num = Num(10)

StopIteration: 已经到达临界

3.10.2.__getitem__、__setitem__和__delitem__

重写此系列方法可以模拟对象成列表或者是字典,即可以使用key-value的类型。

class PersonManager:

def __init__(self):

self.li = []

self.dic = {}

def __getitem__(self, item):

if isinstance(item, int):

# 通过下标得到对象

return self.dic[self.li[item]]

elif isinstance(item, slice):

# 通过切片得到一串对象

start = item.start

stop = item.stop

return [ self.dic[p] for p in self.li[start:stop]]

else:

# 给定的key类型错误

raise TypeError('你输入的key类型错误!')

def __setitem__(self,key,value):

self.li.append(key)

self.dic[key]=value

class Person:

def __init__(self, name):

self.name = name

def __str__(self):

return f'人员: {self.name}'

__repr__ = __str__

pm = PersonManager()

pm[0]= Person('小明')

pm[1]= Person('大白')

pm[2]= Person('小红')

pm[3]= Person('胖虎')

print(pm[0])

print(pm[0:3])

运行结果:

人员: 小明

[人员: 小明, 人员: 大白, 人员: 小红]

更多文章,请关注:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值