__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. checkValidity-表达验证方法。

    调用该方法,可以显示对表单元素进行有效验证,返回值是boolean. 代码如下: <!DOCTYPE html> <html> <head> <meta ch ...

  2. 【解决方案】Django管理页面无法显示静态文件

    [问题描述]:Django管理界面无法获取页面的css样式文件.图片等静态文件.调试模式下看到静态url显示404. [问题原因]:跟踪源码可以发现,静态文件的url是由Django自带的app(dj ...

  3. javascript 之数据类型

    写在前面 国庆整理资料时,发现刚开始入门前端时学习JS 的资料,打算以一个基础入门博客记录下来,有不写不对的多多指教: 先推荐些书籍给需要的童鞋 <JavaScript 高级程序设计.pdf&g ...

  4. Java 7 JVM和垃圾收集

    ---恢复内容开始--- 写JAVA程序,一定要了解JVM(JAVA Virtual machine)一些基础知识和垃圾收集.如果对JVM已经很了解了,可以不用继续往下阅读了.本文只针对Java 7, ...

  5. 【计算机网络】 一个小白的DNS学习笔记

    参考书籍 <计算机网络-自顶向下>  作者 James F. Kurose   DNS的作用   DNS是因特网的目录服务 DNS是因特网的目录服务,它提供了主机名到IP地址映射的查询服务 ...

  6. ubuntu16.04 配置opensips服务器并编译pjsip测试

    一.版本相关 1) ubuntu版本: 16.04 2) opensips版本:2.1.2 3) pjsip版本 :2.5.5 4) ffmpeg版本:3.3.4 5) sdl版本:2.0 6) vs ...

  7. github 项目绑定自己的域名

    上周脑子发热申请了自己的一个域名.本想搞一个自己的网站,后来囊中羞涩,数据库,服务器..买不起了,只买个域名,发现啥也搞不成.后来突然想到了不行找个东西映射到这个域名上吧,就想到了github,之前也 ...

  8. Just a Hook(区间set)

    Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  9. css基础语法三

    []伪类选择器] 1.写法: 伪类选择器,在选择器后面,用:分隔,紧接伪类状态: eg : .a:link 2. 超链接的伪类状态: :link - 未访问状态 :visited - 已访问状态 :h ...

  10. CSS与JS中的相对路径引用

    javascript和css文件中采用相对路径,其基准路径是完全不同的. 1.javascript引用资源(比如图片)相对路径是以宿主路径(被引用的网页比如你在首页index.php引用了某js文件, ...