python3魔法方法_python:类3——魔法方法

一、魔法方法特点

被双上下滑线包围

魔法方法是面向对象的Python的一切,如果你不知道魔法方法,说明你还没能意识到面向对象的Python的强大(不是说Python脚本)

通过对制定方法的重写,完全可以让python根据个人的用途去实现!

二、魔法方法

1、构造相关

__init__(self [,...])构造方法

不写时,会默认存在一个无参的,写了会覆盖

必须返回None,不能写 return,否则返回TypeError;因此不要对init做返回;

1127982-20170508153521457-270113204.png

__new__(cls[, ...])

对象实例化时调用的第一个方法,在init之前,它有个很大的不同第一个参数不是self,而是这个类cls,返回一个对象,cls后边的参数会原封不动的传给__init__()方法

平时极少重写,当继承一个不可变类型又需要修改的时候,需要重写new

class CapStr(str):             #继承str类是不可变得

def __new__(cls, string):       #重写new,第一个传入class,叫其他名字也无所谓,只是为了区分

string = string.upper()      #全部变大写

return str.__new__(cls, string) 变完大写后,把它作为参数去调用基类的new方法

a = CapStr('I love Money')          #得到的a为大写

__del__(self)析构

delete缩写,当没有任何变量引用这个变量后,垃圾回收机制会自动销毁时调用它

并非执行del x 就立马是调用x.__del__();

1127982-20170508163253332-1352877744.png

2、表现类

__str__ 和print()对应

__repr__

>>> classA():

... def __str__(self):    #给print()用

... return "hahaha"...

>>> a =A()

>>>a

<__main__.A object at 0x7f85993317f0>

>>> print(a)

hahaha

打印时,返回字符串,需要return 字符串,不可以是别的类型!

__str__ = __repr__

>>> classA():

... def __repr__(self):    #给obj对象用

... return "hahaha"...

>>> a =A()

>>>a

hahaha

>>> print(a)

hahaha

>>>

3、有关算数运算的魔法方法

在python2.2之前类和类型是分开的;类是属性和方法的封装;类型是像整型、浮点型、字符串等这些;但Python2.2之后,对二者进行统一,做法是将int、float、string、list、tuple等这些bif统统转化为工厂函数

1127982-20170508165427488-2101976309.png

int('123')在以前是调用int函数,把参数转化为整型;现在是用参数实例化一个int对象。并且对象可以做加法!

调用__add__(),因此可以重写,但重写没有多大意义吧

1127982-20170508170058363-1694264713.png

下边写法会进入无线递归:

1127982-20170508170826754-2107682449.png

改进:

1127982-20170508170745426-519421970.png

推荐第一种写法

1127982-20170508171114551-812051808.png

上表中的魔法方法加上r,就是反运算符:a + b,如果a对象的add方法没有实现或者不支持相应的操作的时候,那么python就会自动找到对象b的__radd__(self, other)方法

1127982-20170508183754176-1116289482.png

1为什么没有__add__()方法??

在减法中,为了实现目的,可以修改为 def __radd__(self, other):  return int.__sub__(other, self)

一元操作符

__neg__(self) 定义正号的行为:+x

__pos__(self) 定义符号的行为:-x

__abs__(self) 定义当被abs()调用时的行为

__invert__(self) 定义按位取反的行为:~x

4、属性访问

点;bif;

__getattr__(self, name)

定义当用户试图获取一个不存在的属性时的行为

__getattribute__(self, name)

定义当该类的属性被访问时的行为

__setattr__(self, name, value)

定义当一个属性被设置时的行为

__delattr__(self, name)

定义当一个属性被删除时的行为

>>> classC:

...def __getattribute__(self, name):

...print("getattribute")

...return super().__getattribute__(name)

...def __getattr__(self, name):

...print("getattr")

...def __setattr__(self, name, value):

...print("setattr")

... super().__setattr__(name, value)

...def __delattr__(self, name):

...print("delattr")

... super().__delattr__(name)

...>>> c =C()>>>c.x

getattribute

getattr>>> c.x = 1setattr>>>c.x

getattribute1

>>> delc.x

delattr

定义一个矩形类,且修改__setattr__()方法,如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,宽和高等于边长。

1 classRextangle():2 def __init__(self, width=0, height=0):3 self.width =width4 self.height =height5

6 def __setattr__(self, name, value):7 if name == 'square':8 self.width =value9 self.height =value10 else:11第一种 self.width =value    #报错,无限递归12 self.height =value    #报错,无限递归

第二种    self.name = value     #报错,无限递归

第三种    super().__setattr__(name, value)  #正确(推荐)第四种self.__dict__[name] = value     #正确13 defgetArea(self):14 return self.width * self.height

r = Rectangle(4, 5)    初始化是,有self.width\self.height赋值,回去调用被改写了的__setattr__()方法

r.getArea()        返回20

r.square = 10

r.width r.height   返回10

r.getArea()        返回100

r.__dict__         返回{'width':10, 'height':10}  因此会有“第四种”

5、描述符

描述符就是将某种特殊类型的类的实例指派给另一个类的属性。

__get__(self, instance, owner)   用于访问属性时调用,它返回属性值

__set__(self, instance, value)   将在属性分配操作中调用,不返回任何内容

__delete__(self, instance) 控制删除操作,不返回任何内容

1 classMyDecriptor():2 def __get__(self, instance, owner):3 print("getting...", self, instance, owner)4

5 def __set__(self, instance, value):6 print("setting...", self, instance, value)7

8 def __delete__(self, instance):9 print("deleting...", self, instance)In [51]: classTest():

...: x=MyDecriptor()         #将类的实例指派给Test类的属性x,此时MyDecriptor()实例里的属性、方法就是x的描述符

...:

In [52]: test =Test()              #实例化Test类

In [53]: test.x                  #调用了描述符的__get__()

getting... <__main__.Test object at 0x7fa1602a4f98> In [54]: test                    #实例

Out[54]: <__main__.Test at 0x7fa1602a4f98>In [55]: Test                    #类

Out[55]: __main__.Test

In [56]: test.x = "X-man"             #调用__set__()setting... <__main__.Test object at 0x7fa1602a4f98> X-man

In [57]: deltest.x                 #调用__delete__()

deleting... <__main__.Test object at 0x7fa1602a4f98>

利用以上原理可以轻松实现property()方法

1127982-20170508205035160-1545520211.png

1127982-20170508205107472-31579095.png

练习:

先定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性;要求两个属性会自动进行转换,也就是说你可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果

1127982-20170508210443535-257720194.png

6、定制容器

_len__()、__getitem__()、__setitem__()和__delitem__()

__iter__()——返回迭代器本身

__next__()——决定迭代器的规则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值