__getitem__   在对实例或对象使用索引访问时调用,self[key]
__dir__     收集当前模块的信息,包括继承自其它基类(包括object类)的属性和方法
__new      定义如何创建实例
__init__      构造方法,实例创建时如何初始化
__del__      析构方法,对象在内存中被释放时,自动触发执行
__file__        当前文件在系统中的绝对路径
__hash__     hash值相同表示hash冲突,但并不代表对象值相同。列表不可hash,元组可hash。
          内建类型集合(set)的源码中就用到了"__hash__ = None",来表示set是不可hash类型。
          hash()等同于调用__hash__()方法
        isinstance(1,hashable) 是否可hash
__equal__    == 判断是否相等
      a == b 等价于
      a.__equal__(b)
__bool__      返回bool()布尔值,__bool__() --> __len__() 搜索顺序。
      如果没有__bool__(),则调用__len__()返回长度,非0就为真。
       如果__len__也没有定义,则所有实例都为真

可视化相关的魔术方法:
__repr__    重写表现形式,__str__ --> __repr__ --> object 查找顺序。至少有个__repr__
__str__      format(),print(),str()函数调用时使用的方法,如果没有__str__,则调用__repr__方法,所以这两个方法尽量写一样。
__bytes__      在对象使用bytes()函数时调用此方法
__ascii__

——————————————————————————————————————

运算符重载

容器
__len__     元素个数,必须大于等于0
        size有可能是容器的大小
__iter__     迭代容器时调用,返回一个新的迭代器对象
__contains__   in成员运算符 __contains__ --> __iter__顺序
__getitem__   返回self[key] 的值,不存在返回KeyError异常
__setitem__
__missing__   调用__getitem__时,key不存在时触发,以免抛异常

链式编程

深入学习综合症

__repr__ = __str__

——————————————————————————————————————————————

运算符重载,+= 举例:

class A:
def __init__(self,x):
self.x = x
def __repr__(self):
return str(self.x)
def __iadd__(self, other):
# return A(self.x + other.x) #生成新对象
self.x = self.x + other.x #就地修改
return self a1 = A(4)
a2 = A(10)
a3 = A(5)
print(id(a1),id(a2),id(a3))
a1 += a2
print(id(a1),a1)
~~~~~~
4362338144 4362338200 4362338256
4362338144 14 #对比可以看到前后的id(a1)内存地址一致,为就地修改

  上面例子是就地修改,下面这个例子是生成新对象,对比id(a1)内存地址。

class A:
def __init__(self,x):
self.x = x
def __repr__(self):
return str(self.x)
def __iadd__(self, other):
return A(self.x + other.x) #生成新对象
# self.x = self.x + other.x #就地修改
# return self a1 = A(4)
a2 = A(10)
a3 = A(5)
print(id(a1),id(a2),id(a3))
a1 += a2
print(id(a1),a1)
~~~~~~~~~~~~~~~~~~
4362338088 4362338144 4362338200
4362604616 14 #id(a1)值不等,生成的是新对象

  

练习:
设计二维坐标类Point,使其成为可hash类型,并比较2个坐标的实例是否相等。
class Point:
def __init__(self,x,y):
self.x = x
self.y = y
def __str__(self):
return '{},{}'.format(self.x,self.y)
def __eq__(self, other):
return (self.x == other.x) and (self.y == other.y)
def __iadd__(self, other):
return Point((self.x + other.x),(self.y + other.y)) p1 = Point(4,5)
p2 = Point(6,5) print(p1 == p2)
p1 += p2
print(p1)

  

练习:
购物车支持索引的方式检索商品:
class Color:
RED = 0
BLACK = 1
WHITE = 2
BLUE = 3 class Item:
def __init__(self,**kwargs):
self.spec = kwargs
def __repr__(self):
return str(sorted(self.spec.items()))
def __str__(self):
return str(sorted(self.spec.items()))
def __getitem__(self, item):
return self.spec.items()[item] class Cart:
def __init__(self):
self.items = []
def addItems(self,item):
self.items.append(item)
def getAllItems(self):
return self.items
def __add__(self, other): # +
pass
def __len__(self):
return len(self.getAllItems())
def __iter__(self):
return iter(self.items)
# for item in self.getAllItems():
# yield item
def __getitem__(self, index): #index
return self.items[index]
def __missing__(self, key): #只支持字典
print(key)
def __setitem__(self, key, value): #索引不可以超界
self.items[key] = value
return self.items mycart = Cart()
mycar = Item(mark='tesla',color=Color.WHITE,price='100w',speed='400km/h',year=2017)
myphone = Item(mark='Nokia',color=Color.BLACK,price=5000,memory='4G')
mymac = Item(mark='MacPro',color=Color.WHITE,price=19999,memory='16G',ssd='512G')
mycart.addItems(mycar)
mycart.addItems(myphone)
mycart.addItems(mymac)
for item in mycart.getAllItems():
# for item in mycart:
print(item.__dict__)
print(mycart.__len__())
print(mycart[2])

  

练习:斐波那契数列支持索引方式查找第n个数字。索引和调用两种方式:
class Fib:
"""0,1,1,2,3,5,8,13,21""" def __init__(self):
self.lst = [] def __call__(self, n, *args, **kwargs):
i = 0
prev, next = 0, 1
while True:
self.lst.append(prev)
if i == n:
return prev
prev, next = next, prev + next
i += 1 def __getitem__(self, item):
return self.__call__(item) f1 = Fib()
# print(f1(7))
# print(f1(8))
print(f1[8])

  

回顾下普通装饰器
import datetime
import time def timer(fn):
def wrapper(x, y):
start = datetime.datetime.now()
print('start:',start)
print(fn(x, y))
time.sleep(1)
stop = datetime.datetime.now()
# print('stop: ',stop)
return 'stop: {}'.format(stop) return wrapper @timer
def add(x, y):
return x + y num1 = add(3, 4)
print(num1)

  

上下文管理
类作为上下文,进入上下文时如果有定义__enter__方法,则做该方法的动作。
__enter__ 进去了帮我做某事,
__exit__ 离开时候帮忙
必须同时存在
import sys
sys.exit() 强制退出脚本
异常退出时处理
exc_type
exc_val
exc_tb traceback 类装饰器
两个装饰器同时装饰
with TimeIt() as f:
pass from functools import wrapås
@wraps(fn)
def self().... == wraps(fn)(self) 复制所有属性
类装饰是调用到__init__ 和__call__
--—————————————————————————————————————————————— ————————————————————————————————————————————————

  

用类做装饰器,调用的是__enter__和__exit__:
import datetime
import time class TimeIt:
def __init__(self, fn):
print('__init__...')
self.fn = fn def __enter__(self):
self.start = datetime.datetime.now()
print('Enter:', self.start)
return self def __call__(self, *args, **kwargs):
print('__call__....')
self.start = datetime.datetime.now()
print('Enter:', self.start)
print(self.fn(*args, **kwargs))
self.stop = datetime.datetime.now()
# print('Exit:', self.stop)
return 'Exit: {}'.format(self.stop) def __exit__(self, exc_type, exc_val, exc_tb):
self.stop = datetime.datetime.now()
print('Exit:', self.stop)
return self @TimeIt
def add(x, y):
time.sleep(1)
return x + y # with TimeIt(add) as foo:
# print(foo(3,4)) print(add(3, 4))

  

使用wraps的方式,拷贝所有属性:
import time
import datetime
from functools import wraps class TimeIt: def __init__(self, fn):
# self.__doc__ = fn.__doc__
print('init')
self._fn = fn
wraps(fn)(self)
#@wraps(fn) 等同于
#def self()...... def __enter__(self):
print('enter')
self.start = datetime.datetime.now()
return self def __call__(self, *args, **kwargs):
print('__call__')
start = datetime.datetime.now()
ret = self._fn(*args, **kwargs)
delta = (datetime.datetime.now() - start).total_seconds()
print("dec {} took {}".format(self._fn.__name__, delta))
return ret def __exit__(self, exc_type, exc_val, exc_tb):
print('exit')
delta = (datetime.datetime.now() - self.start).total_seconds()
print("context {} took {}".format(self._fn.__name__, delta))
return # def logger(fn):
# @wraps(fn)
# def wrapper(*args, **kwargs):
# start = datetime.datetime.now()
# ret = fn(*args, **kwargs)
# delta = (datetime.datetime.now() - start).total_seconds()
# print("dec {} took {}".format(fn.__name__, delta))
# return ret
# return wrapper @TimeIt
def add(x,y): # add = TimeIt(add)
"""This is a add function.~~~~~~~~~~~~~~~"""
time.sleep(2)
return x + y print(add(10,11)) print(add.__doc__)
print(add.__name__) print(add.__dict__)
# with TimeIt(add) as foo:
# print(foo(5, 16))

  

Python 面向对象(三) 魔术方法的更多相关文章

  1. Python - 面向对象编程 - 魔术方法(双下划线方法)

    什么是魔术方法 在Python中,所有以 __ 双下划线包起来的方法,都统称为 Magic Method 魔术方法,也叫双下划线方法 有哪些重要的魔术方法? __new__ https://www.c ...

  2. Python面向对象之魔术方法

    __str__ 改变对象的字符串显示.可以理解为使用print函数打印一个对象时,会自动调用对象的__str__方法 class Student: def __init__(self, name, a ...

  3. 十八、Python面向对象之魔术方法

    1.类的比较 class A(object): def __init__(self,value): self.value = value def __eq__(self,other): return ...

  4. Python 类的魔术方法

    Python中类的魔术方法 在Python中以两个下划线开头的方法,__init__.__str__.__doc__.__new__等,被称为"魔术方法"(Magic method ...

  5. Python面向对象三要素-继承(Inheritance)

    Python面向对象三要素-继承(Inheritance) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.继承概述 1>.基本概念 前面我们学习了Python的面向对象三 ...

  6. Python面向对象三要素-封装(Encapsulation)

    Python面向对象三要素-封装(Encapsulation) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.封装概述 将数据和操作组织到类中,即属性和方法 将数据隐藏起来,给 ...

  7. mac学习Python第一天:安装、软件说明、运行python的三种方法

    一.Python安装 从Python官网下载Python 3.x的安装程序,下载后双击运行并安装即可: Python有两个版本,一个是2.x版,一个是3.x版,这两个版本是不兼容的. MAC 系统一般 ...

  8. Python学习笔记之面向对象编程(三)Python类的魔术方法

    python类中有一些方法前后都有两个下划线,这类函数统称为魔术方法.这些方法有特殊的用途,有的不需要我们自己定义,有的则通过一些简单的定义可以实现比较神奇的功能 我主要把它们分为三个部分,下文也是分 ...

  9. Python中的魔术方法详解

    介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...

随机推荐

  1. SAP的 消息 弹出窗口(备忘)

    DATA: i_smesg TYPE tsmesg WITH HEADER LINE. i_smesg-msgty = 'E'. i_smesg-arbgb = '. i_smesg-txtnr = ...

  2. Java多线程——创建线程的两种方式

    创建线程方式一:继承Thread类. 步骤:1,定义一个类继承Thread类.2,覆盖Thread类中的run方法.3,直接创建Thread的子类对象创建线程.4,调用start方法开启线程并调用线程 ...

  3. Visual Studio 自定义项目模板

    经常我们需要新建一个项目,然后新建我们的View文件夹,ViewModel文件夹,Model文件夹,还有把我们的ViewModelBase放入我们的VIewModel,如果还用框架,还需要加上好多. ...

  4. webpack核心概念

    一.webpack四个核心概念 1.入口[Entry] webpack将创建所有应用程序 依赖关系图表.图表的起点被称之为 入口起点.入口起点告诉webpack从哪里开始,并遵循着依赖关系图表知道打包 ...

  5. C#方法中参数ref和out的解析

    一.C#方法中参数类型 有4种参数类型,有时候很难记住它们的不同特征,下图对它们做一个总结,使之更容易比较和对照. 二.C#方法中的参数 1.值参数 使用值参数,通过复制实参的值到形参的方式把数据传递 ...

  6. 使用element ui 日期选择器获取值后的格式问题

    一般情况下,我们需要给后台的时间格式是: "yyyy-MM-dd" 但是使用Element ui日期选择器获取的值是这样的: Fri Sep :: GMT+ (中国标准时间) 在官 ...

  7. 关于C#开发中那些编码问题

    最近一直在搞各种编码问题,略有心得,与大家分享一番. System.Text提供了Encoding的抽象类,这个类提供字符串编码的方法.常用的编码方式主要有ASCII,Unicode,UTF8(Uni ...

  8. 剑指offer--面试题3

    一 题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.完成一个函数,输入这样的数组和一整数,判断这个数组是否包含这个整数. 二 分析 如果这个二维数组是 ...

  9. Luck and Love(二维线段树)

    Luck and Love Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...

  10. 0_Simple__matrixMulCUBLAS

    使用CUDA的线性代数库cuBLAS来计算矩阵乘法.这里主要记录调用规则,关于乘法函数中详细的参数说明和调用规则见另一篇随笔. ▶ 源代码: #include <assert.h> #in ...