Python 类的魔术方法
Python中类的魔术方法
Python提供的魔术方法
魔术方法这里按照不同的类别有如下分类:
| 魔法方法 | 含义 | 
| 基本的魔法方法 | |
| __new__(cls[, ...]) | 1. __new__ 是在一个对象实例化的时候所调用的第一个方法 2. 它的第一个参数是这个类,其他的参数是用来直接传递给 __init__ 方法 3. __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用 4. __new__ 主要是用于继承一个不可变的类型比如一个 tuple 或者 string | 
| __init__(self[, ...]) | 构造器,当一个实例被创建的时候调用的初始化方法 | 
| __del__(self) | 析构器,当一个实例被销毁的时候调用的方法 | 
| __call__(self[, args...]) | 允许一个类的实例像函数一样被调用:x(a, b) 调用 x.__call__(a, b) | 
| __len__(self) | 定义当被 len() 调用时的行为 | 
| __repr__(self) | 定义当被 repr() 调用或者直接执行对象时的行为 | 
| __str__(self) | 定义当被 str() 调用或者打印对象时的行为 | 
| __bytes__(self) | 定义当被 bytes() 调用时的行为 | 
| __hash__(self) | 定义当被 hash() 调用时的行为 | 
| __bool__(self) | 定义当被 bool() 调用时的行为,应该返回 True 或 False | 
| __format__(self, format_spec) | 定义当被 format() 调用时的行为 | 
| 有关属性 | |
| __getattr__(self, name) | 定义当用户试图获取一个不存在的属性时的行为 | 
| __getattribute__(self, name) | 定义当该类的属性被访问时的行为 | 
| __setattr__(self, name, value) | 定义当一个属性被设置时的行为 | 
| __delattr__(self, name) | 定义当一个属性被删除时的行为 | 
| __dir__(self) | 定义当 dir() 被调用时的行为 | 
| __get__(self, instance, owner) | 定义当描述符的值被取得时的行为 | 
| __set__(self, instance, value) | 定义当描述符的值被改变时的行为 | 
| __delete__(self, instance) | 定义当描述符的值被删除时的行为 | 
| 比较操作符 | |
| __lt__(self, other) | 定义小于号的行为:x < y 调用 x.__lt__(y) | 
| __le__(self, other) | 定义小于等于号的行为:x <= y 调用 x.__le__(y) | 
| __eq__(self, other) | 定义等于号的行为:x == y 调用 x.__eq__(y) | 
| __ne__(self, other) | 定义不等号的行为:x != y 调用 x.__ne__(y) | 
| __gt__(self, other) | 定义大于号的行为:x > y 调用 x.__gt__(y) | 
| __ge__(self, other) | 定义大于等于号的行为:x >= y 调用 x.__ge__(y) | 
| 算数运算符 | |
| __add__(self, other) | 定义加法的行为:+ | 
| __sub__(self, other) | 定义减法的行为:- | 
| __mul__(self, other) | 定义乘法的行为:* | 
| __truediv__(self, other) | 定义真除法的行为:/ | 
| __floordiv__(self, other) | 定义整数除法的行为:// | 
| __mod__(self, other) | 定义取模算法的行为:% | 
| __divmod__(self, other) | 定义当被 divmod() 调用时的行为 | 
| __pow__(self, other[, modulo]) | 定义当被 power() 调用或 ** 运算时的行为 | 
| __lshift__(self, other) | 定义按位左移位的行为:<< | 
| __rshift__(self, other) | 定义按位右移位的行为:>> | 
| __and__(self, other) | 定义按位与操作的行为:& | 
| __xor__(self, other) | 定义按位异或操作的行为:^ | 
| __or__(self, other) | 定义按位或操作的行为:| | 
| 反运算 | |
| __radd__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rsub__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rmul__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rtruediv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rfloordiv__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rdivmod__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rpow__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rlshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rrshift__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rand__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __rxor__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| __ror__(self, other) | (与上方相同,当左操作数不支持相应的操作时被调用) | 
| 增量赋值运算 | |
| __iadd__(self, other) | 定义赋值加法的行为:+= | 
| __isub__(self, other) | 定义赋值减法的行为:-= | 
| __imul__(self, other) | 定义赋值乘法的行为:*= | 
| __itruediv__(self, other) | 定义赋值真除法的行为:/= | 
| __ifloordiv__(self, other) | 定义赋值整数除法的行为://= | 
| __imod__(self, other) | 定义赋值取模算法的行为:%= | 
| __ipow__(self, other[, modulo]) | 定义赋值幂运算的行为:**= | 
| __ilshift__(self, other) | 定义赋值按位左移位的行为:<<= | 
| __irshift__(self, other) | 定义赋值按位右移位的行为:>>= | 
| __iand__(self, other) | 定义赋值按位与操作的行为:&= | 
| __ixor__(self, other) | 定义赋值按位异或操作的行为:^= | 
| __ior__(self, other) | 定义赋值按位或操作的行为:|= | 
| 一元操作符 | |
| __pos__(self) | 定义正号的行为:+x | 
| __neg__(self) | 定义负号的行为:-x | 
| __abs__(self) | 定义当被 abs() 调用时的行为 | 
| __invert__(self) | 定义按位求反的行为:~x | 
| 类型转换 | |
| __complex__(self) | 定义当被 complex() 调用时的行为(需要返回恰当的值) | 
| __int__(self) | 定义当被 int() 调用时的行为(需要返回恰当的值) | 
| __float__(self) | 定义当被 float() 调用时的行为(需要返回恰当的值) | 
| __round__(self[, n]) | 定义当被 round() 调用时的行为(需要返回恰当的值) | 
| __index__(self) | 1. 当对象是被应用在切片表达式中时,实现整形强制转换 2. 如果你定义了一个可能在切片时用到的定制的数值型,你应该定义 __index__ 3. 如果 __index__ 被定义,则 __int__ 也需要被定义,且返回相同的值 | 
| 上下文管理(with 语句) | |
| __enter__(self) | 1. 定义当使用 with 语句时的初始化行为 2. __enter__ 的返回值被 with 语句的目标或者 as 后的名字绑定 | 
| __exit__(self, exc_type, exc_value, traceback) | 1. 定义当一个代码块被执行或者终止后上下文管理器应该做什么 2. 一般被用来处理异常,清除工作或者做一些代码块执行完毕之后的日常工作 | 
| 容器类型 | |
| __len__(self) | 定义当被 len() 调用时的行为(返回容器中元素的个数) | 
| __getitem__(self, key) | 定义获取容器中指定元素的行为,相当于 self[key] | 
| __setitem__(self, key, value) | 定义设置容器中指定元素的行为,相当于 self[key] = value | 
| __delitem__(self, key) | 定义删除容器中指定元素的行为,相当于 del self[key] | 
| __iter__(self) | 定义当迭代容器中的元素的行为 | 
| __reversed__(self) | 定义当被 reversed() 调用时的行为 | 
| __contains__(self, item) | 定义当使用成员测试运算符(in 或 not in)时的行为 | 
Python的魔术方法举例
这里仅针对常用的魔术方法进行举例,便于理解及灵活运用,部分魔术方法已经在:这篇博客中举例说明
小技巧:如果在需要返回对象的魔术方法里面不知道如何返回,可以调用super函数来执行父类的相同方法。
注意:魔法方法必须要使用return进行返回。
基本的魔法方法
__repr__(self):直接执行对象时执行的方法
>>>
>>> class A:
def __repr__(self):
return '__repr__' >>> a = A()
>>> a
__repr__
__bool__(self):判断对象的bool值时执行的方法,返回值只能是bool类型
>>>
>>> class C:
def __bool__(self):
return False >>> c = C()
>>> bool(c)
False
>>>
属性相关的魔术方法
__getattr__(self,name):获取一个不存在的属性时执行的方法。
__setattr__(self,name,value):设置一个属性时执行的方法。
__delattr__(self,name):删除一个属性时执行的方法。
__getattribute__(self,name):当该类的属性被访问时执行的方法。
>>> class A:
def __getattr__(self,name):
print('__getattr__')
def __setattr__(self,name,value):
print('__setattr__')
super().__setattr__(name,value)
def __delattr__(self,name):
print('__delattr__')
return super().__delattr__(name)
def __getattribute__(self,name):
print('__getattribute__')
return super().__getattribute__(name) >>> a = A()
>>> a.name
__getattribute__
__getattr__
>>> a.name = 'daxin'
__setattr__
>>> a.name
__getattribute__
'daxin'
>>> del a.name
__delattr__
>>>
注意
1、__getattribute__,先于__getattr__访问
2、__getattr__,没有在父类中进行定义,所以不能继承
3、__setattr__,为设置属性,所以无需return
3、在__setattr__时,不能直接使用self.name = value ,会造成死循环,因为在执行self.name = value的时候又会调用本身,无限循环下去
小技巧
在__setattr__的时候,除了使用super的方式设置变量和值以外,还可以使用__dict__来设置。(但是建议使用super的方法)
>>> class A:
def __getattr__(self,name):
print('__getattr__')
def __setattr__(self,name,value):
print('__setattr__')
self.__dict__[name] = value
def __delattr__(self,name):
print('__delattr__')
return super().__delattr__(name)
def __getattribute__(self,name):
print('__getattribute__')
return super().__getattribute__(name) >>> a = A()
>>> a.name
__getattribute__
__getattr__
>>> a.name = 'daxin'
__setattr__
__getattribute__
>>> a.name
__getattribute__
'daxin'
>>>
属性相关之property
我们知道使用property可以把,类的某些方法当作属性进行访问,赋值,修改的,而Property内部也是通过类的魔术方法实现的。
下面的三个属性,主要用于在被当作其他的类的属性时使用的。
__set__(self,instance,value):当作一个描述符(属性)被赋值时执行的方法
__get__(self,instance,owner):当作一个描述符(属性)被获取时执行的方法
__delete__(self,instance):当作一个描述符(属性)被删除时执行的方法
# 当作一个描述符被访问的含义就是:
# 一个函数在实例化的时候调用了其他类的对象 >>>
>>> class A:
pass >>> class B:
def __init__(self):
self.name = A() # 把A类的对象在B实例化的时候当作描述符(属性)进行赋值 >>>
>>> class A:
def __get__(self,instance,owner):
print('__get__','self:',self,'instance:',instance,'owner:',owner) def __set__(self,instance,value):
print('__set__','self:',self,'instance:',instance,'value:',value) def __delete__(self,instance):
print('__delete__','self:',self,'instance:',instance) >>> class B:
name = A() >>>
>>> b = B()
>>> b.name
__get__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68> owner: <class '__main__.B'>
>>> b.name = 'abc'
__set__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68> value: abc
>>> del b.name
__delete__ self: <__main__.A object at 0x1134247f0> instance: <__main__.B object at 0x113411d68>
>>>
扩展
由于不知道魔术方法传递的参数都是什么东西,所以在上面的例子打印了一下:
- self:表示的是当前类(拥有__set__,__get__等方法的类本身)
- instance:表示的是调用此类的类的实例化对象
- owner:表示调用此类的类
- value:表示要设置的值
根据这三个方法,那么我们完全可以定义自己的property属性
class Myproperty:   # 定义自己的Property
    def __init__(self,mget=None,mset=None,mdel=None):   # 绑定三个修改方法
        self.mget = mget
        self.mset = mset
        self.mdel = mdel
    def __get__(self,instance,owner):
        return self.mget(instance)       
    def __set__(self,instance,value):
        return self.mset(instance,value)
    def __delete__(self,instance):
        return self.mdel(instance)
class A:
    def __init__(self):
        self._x = None
    def setX(self,value):
        self._x = value
    def getX(self):
        try:
            if self._x:
                return self._x
        except AttributeError as e:
            print('Attribute is not exist')
    def delX(self):
        del self._x
    name = Myproperty(getX,setX,delX)
>>> a = A()
>>> a.name
>>> a.name = 'daxin'
>>> a.name
'daxin'
>>> del a.name
>>> a.name
Attribute is not exist
>>>
PS:关于为什么在Myproperty中传递instance,那么请注意我们的setX,getX,默认有一个self参数,使用自定义Property的话,那么我们必须手动传递,在Myproperty类中instance表示对象自己,所以传递instance给setX/getX,其实等同于self。
运算符相关魔术方法
__add__:在执行加法时执行的方法
>>> class A(int):
def __add__(self,other):
print('__add__')
return super().__sub__(other) # 这里改写了 add方法,调用了父类的减法 >>> a = A(8)
>>> a + 6
__add__
2
>>>
__radd__:当左边的对象没有__add__方法时,执行右边对象的__radd__方法
>>> class A:
pass >>> class B(int): def __radd__(self,other):
return 'I am B,because right object not have __add__' >>>
>>> a = A()
>>> b = B(12)
>>> a + b
'I am B,because right object not have __add__'
>>>
容器类
在Python中,列表、元组、字典和集合等等,这些都可以称为容器。
__getitem__:获取容器中的元素,比如mylist[1]
__setitem__:设置容器中的元素,比如mylist[2] = 'hello'
__delitem__:删除容器中的某个元素,比如 del mylist[2]
# 定义一个不可变的列表类型
# 记录元素被访问的次数 class Mylist: def __init__(self,*args):
self.value = [ x for x in args ] # 列表生成式
self.count = {}.fromkeys(range(len(self.value)),0) # 定义字典用于按照索引统计访问次数 def __getitem__(self,key):
self.count[key] += 1
return self.value[key] def __repr__(self):
return str(self.value) __str__ = __repr__ >>> a = Mylist(1,2,3,45)
>>> a
[1, 2, 3,45]
>>> a.count
{0: 0, 1: 0, 2: 0, 3: 0}
>>> a[0]
1
>>> a.count
{0: 1, 1: 0, 2: 0, 3: 0}
>>> a[2]
3
>>> a.count
{0: 1, 1: 0, 2: 1, 3: 0}
>>> a[1] = 123
小练习
1、写一个矩形的类,那么这个类默认有长和宽两个参数,当传入一个叫square的属性时,值就等于边长,由于是正方形那么长和宽就等于边长。
class Rectangle(object):
    # init object
    def __init__(self,width,height):
        self.width = width
        self.height = height
    def getacreage(self):
        return self.width * self.height
    def __setattr__(self,name,value):
        if name == 'square':
            self.width = value
            self.height = value
        else:
            super().__setattr__(name,value)
2、完成如下要求:
- 定制一个计时器类
- start和stop方法代表启动和停止计时
- 假设计时器对象t1,定制t1对象直接执行和打印时的输出信息
- 当计时器未启动或已经停止计时,调用stop方法会给予温馨提示
- 两个计时器对象可以进行相加: t1 + t2
import time
class Mytimer():
    # 初始化
    def __init__(self):
        self.prompt = 'Timer is not start'    # 提示信息
        self.start_time = None
        self.stop_time = None
    # 启动定时器
    def start(self):
        if self.start_time:
            print('Please Use Stop() to stop Timer')   # 属性存在,表示已经启动计时
        else:
            self.start_time = time.time()
            print('The start of Timer')
    # 关闭定时器
    def stop(self):
        if self.start_time:
            self.stop_time = time.time()
            print('The stop of Timer')
            self._calc()
        else:
         print('Please Use Start() to start Timer')   # 没有执行start(),检测不到属性,进行提示
    # 计算耗时
    def _calc(self):
        self.prompt = 'Total time : '
        self.end_time = self.stop_time - self.start_time
        self.prompt += str('{:.2f}'.format(self.end_time))
        self.start_time = None
        self.stop_time = None
    # 直接执行对象时,打印提示信息
    def __repr__(self):
        return self.prompt
    # 打印对象和执行对象相同
    __str__ = __repr__
    # 计时器相加
    def __add__(self,other):
        self.prompt = 'All Time : '
        add_time = self.end_time + other.end_time
        self.prompt += str('{:.2f}'.format(add_time))
        return self.prompt
3、完成如下需求
- 定义一个温度类,然后定义两个描述符类用于描述摄氏度和华氏度两个属性。
- 两个属性会自定进行转换,也就是说可以给摄氏度这个属性赋值,然后打印的华氏度属性是自动转换后的结果。
class Celsius:
    def __init__(self,value = 37):
        self.value = value
    def __set__(self,instance,value):
        self.value = value
    def __get__(self,instance,owner):
        return self.value
class Fahrenheit:
    def __set__(self,instance,value):
         instance.cel = (float(value) - 32 )  / 1.8
    def __get__(self,instance,owner):
        return instance.cel * 1.8  + 32   # 通过instance实例访问,实例化后对象的cel属性
class Temperature:
    cel = Celsius()
    fah = Fahrenheit()
>>> a = Temperature()
>>> a.cel
37
>>> a.fah
98.60000000000001
>>> a.fah = 100
>>> a.cel
37.77777777777778
>>>
PS:由于instance表示的是实例化的对象本身(a),所以这里使用instance,指代a,来访问设置的cel属性,来进行换算。
Python 类的魔术方法的更多相关文章
- Python学习笔记之面向对象编程(三)Python类的魔术方法
		python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法.这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能 我主要把它们分为三个部分,下文也是分 ... 
- Python类之魔术方法
		一.什么是魔术方法? 在Python的方法,我们经常会遇见__XXX__(),这样的方法,我们一般称为"魔术方法",赶紧搬个小板凳,我们一起来看看魔术方法有啥神奇的地方,这些方法又 ... 
- python类,魔术方法等学习&&部分ssti常见操作知识点复习加深
		python类学习&&部分ssti常见操作知识点复习加深 在做ssti的模块注入的时候经常觉得自己python基础的薄弱,来学习一下,其实还是要多练习多背. 在python中所有类默认 ... 
- python 类属性与方法
		Python 类属性与方法 标签(空格分隔): Python Python的访问限制 Python支持面向对象,其对属性的权限控制通过属性名来实现,如果一个属性有双下划线开头(__),该属性就无法被外 ... 
- python类之魔法方法
		python类之魔法方法: class A(object): def __init__(self,x): self.x = x def __neg__(self): print('-v') def _ ... 
- day19-Python运维开发基础(类的魔术方法)
		1. __new__魔术方法 # ### __new__ 魔术方法 ''' 触发时机:实例化类生成对象的时候触发(触发时机在__init__之前) 功能:控制对象的创建过程 参数:至少一个cls接受当 ... 
- 第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解
		第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解 一. 引言 上两节介绍了构造方法的语法及参数,说明了构造方法是Python的类创建实例后首先执行的方法,并说明如果类 ... 
- Python中的魔术方法详解
		介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ... 
- python所有的魔术方法
		据说,Python 的对象天生拥有一些神奇的方法,它们总被双下划线所包围,他们是面向对象的 Python 的一切. 他们是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个, ... 
随机推荐
- vue实现未登录跳转到登录页面
			环境:vue 2.9.3; webpack;vue-router 目的:实现未登录跳转 例子:直接在url地址栏输入...../home,但是这个页面要求需要登陆之后才能进入,判断的值就通过登陆之后给 ... 
- Linux性能优化 第八章 实用工具:性能工具助手
			8.1性能工具助手 Linux有丰富的工具,这些工具组合来使用会更加强大.性能工具也一样,单独使用虽然也没有问题,但是和其他的工具组合起来就能显著提高有效性和易用性. 8.1.1 自动执行和记录命令 ... 
- Nginx80端口转发+域名——实现IP+端口隐藏
			一.目的1.相信大家会遇到这样的问题:当一台服务器部署多个tomcat应用时,当我们访问tomcat时,需要在浏览器中输入服务器IP+端口号,这看起来非常的low. 二. 环境 1台服务服务器 假如I ... 
- linux  web服务基础知识,dns
			#web服务基础知识c/s 客户端/服务器b/s 浏览器/服务器 nginx > web server 服务端浏览器 > web client 客户端 #dns解析 ... 
- Hive 2.1.1安装配置
			##前期工作 安装JDK 安装Hadoop 安装MySQL ##安装Hive ###下载Hive安装包 可以从 Apache 其中一个镜像站点中下载最新稳定版的 Hive, apache-hive-2 ... 
- 网易微专业 UI设计师
			网易云课堂的UI设计师微专业,需要的留言 
- 迭代器 -> 固定的思路. for循环
			一个数据类型中包含了__iter__函数表示这个数据是可迭代的 dir(数据): 返回这个数据可以执行的所有操作 判断迭代器和可迭代对象的方案(野路子) __iter__ 可迭代的 __iter__ ... 
- for循环案例
			for循环案例 今天给大家介绍点for循环的案例 1.大马驮2石粮食,中马驮1石粮食,两头小马驮一石粮食,要用100匹马,驮100石粮食,该如何调配? <!DOCTYPE html> &l ... 
- 一些被提问频率最高的12个php面试题,以及对应的常规回答。
			一些被提问频率最高的12个php面试题,以及对应的常规回答.1.问题:请用最简单的语言告诉我php是什么?回答:php全称:hypertext preprocessor,是一种用来开发动态网站的服务器 ... 
- <转载>ant使用指南详细入门教程 http://www.jb51.net/article/67041.htm
			这篇文章主要介绍了ant使用指南详细入门教程,本文详细的讲解了安装.验证安装.使用方法.使用实例.ant命令等内容,需要的朋友可以参考下 一.概述 ant 是一个将软件编译.测试.部署等步骤联系在一起 ... 
