__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. 深入理解计算机系统(4.1)------Y86指令集体系结构

    本章我们将进入处理器体系结构介绍的神秘海洋中,我们熟悉的手机,电脑等设备的核心硬件都离不开处理器.处理器可以称的上是人类创造的最复杂的系统之一,一块手指大小的硅片,可以容纳一个完整的高性能处理器.大的 ...

  2. JavaScript享元模式

    通过两个例子的对比来凸显享元模式的特点:享元模式是一个为了提高性能(空间复杂度)的设计模式,享元模式可以避免大量非常相似类的开销. 第一实例,没有使用享元模式,计算所花费的时间和空间使用程度. 要求为 ...

  3. IIS ApplicationPoolIdentity(配置IIS讀寫網站文件)

    原创地址:http://www.cnblogs.com/jfzhu/p/4067297.html 转载请注明出处 从IIS 7.5开始,Application Pool Identity的Built- ...

  4. 用Eclipse 创建一个 简单的 Maven JavaWeb 项目

    使用Maven 创建一个简单的 javaWeb 项目: 本篇属于 创建 JavaWeb 项目的第三篇: 建议阅读本篇之前 阅读 用 Eclipse 创建一个简单的web项目  ;本篇是这这篇文章的基础 ...

  5. MySQL锁类型以及子查询锁表问题、解锁

    MySQL中select * for update锁表的范围 MySQL中select * for update锁表的问题 由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主 ...

  6. NodeJs通过镜像下载相关NPM模块

    临时通过镜像使用一次:npm --registry https://registry.npm.taobao.org install  模块名[设置镜像源地址为淘宝] 持久使用的第一种方法: npm c ...

  7. JavaScript面向对象深入理解原型

    原型模式 function Person(){ } Person.prototype.name="Ewarm"; Person.prototype.age="29&quo ...

  8. C#设计模式之十组合模式(Composite)【结构型】

    一.引言   今天我们要讲[结构型]设计模式的第四个模式,该模式是[组合模式],英文名称是:Composite Pattern.当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达 ...

  9. Cloud9 on Docker镜像发送

    老外有做过几个cloud9的镜像,但是都有各种各样的问题. 小弟在此做了一个docker镜像,特此分享,希望各位大佬多提宝贵意见.谢谢. Cloud9 Online IDE Coding anywhe ...

  10. Pseudoforest(伪最大生成树)

    Pseudoforest Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total ...