item系列

__getitem__(self, item)            对象通过 object[key] 触发
__setitem__(self, key, value) 对象通过 object[key] = value 触发
__delitem__(self, key) 对象通过 del object[key] 触发
class Func:
def __getitem__(self, item):
# object[item] 触发
return self.__dict__[item] def __setitem__(self, key, value):
# object[key] = value 触发
self.__dict__[key] = value def __delitem__(self, key):
# del object[key] 触发
print('delitem: 删除key')
del self.__dict__[key] def __delattr__(self, item):
# del object.item 触发
print('delattr: 删除key')
del self.__dict__[item] f = Func()
f['name'] = 'hkey' # __setitem__
f['age'] = 20 # __setitem__
print(f.name) # 对象属性原本的调用方式
print(f['name']) # __getitem__
del f['name'] # __delitem__
print('------')
del f.age # __delattr__

item系列实例

要注意反射的 __delattr__ 和 __delitem__ 使用不同的方式触发不同的特殊方法。

class Fib:
def __getitem__(self, item):
if isinstance(item, int):
a, b = 1, 1
for x in range(item):
a, b = b, a+b
return a
if isinstance(item, slice):
start = item.start
stop = item.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a+b
return L f = Fib()
print(f[9])
print(f[:10]) 执行结果:
55
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

实例:通过item系列像列表一样获取类中斐波那契数列

__str__ 和 __repr__

当直接打印一个对象的时候,显示的是一段内存地址。

In [1]: class Person:
...: def __init__(self, name):
...: self.name = name In [2]: p = Person('hkey') In [3]: p
Out[3]: <__main__.Person at 0x2be9f5c9128> In [4]: print(p)
<__main__.Person object at 0x000002BE9F5C9128>

为了便于更好的理解,我们定义一个__str__方法

In [1]: class Person:
...: def __init__(self, name):
...: self.name = name
...: def __str__(self):
...: return "hello %s." % self.name In [2]: p = Person('hkey') In [3]: p
Out[3]: <__main__.Person at 0x2858bd468d0> In [4]: print(p)
hello hkey.

定义了__str__方法,直接输出对象还是打印的内存地址,并没有走__str__方法中定义的格式,用print输出信息却调用了__str__方法定义的内容

In [1]: class Person:
...: def __init__(self, name):
...: self.name = name
...: def __repr__(self):
...: return "hello %s." % self.name In [2]: p = Person('hkey') In [3]: p
Out[3]: hello hkey. In [4]: print(p)
hello hkey.

定义了__repr__方法,不管是直接打印对象还是通过print打印对象,都是走的__repr__中定义的格式。

总结:

__repr__ 和 __str__ 这两个方法都是用于显示的,__str__是面向用户的,而__repr__是面向程序员
    
    使用print打印操作会首先尝试__str__和str内置函数,它通常应该返回一个友好的提示
    当__str__不存在的时候,会去找__repr__是否定义,定义则打印__repr__中定义的内容
    
    当我们想在所有环境下都统一显示的话,可以添加__repr__方法。
    当我们想在不同的环境下支持不同的显示,就可以定义__repr__方法和__str__方法,终端交互使用__repr__,用户使用__str__方法

__new__

__new__ 是在新式类中出现的方法,它作用在构造函数之前,可以这么理解,在python中存在于类里面的构造方法__init__()负责将类实例化,而在__init__() 启动之前,__new__()决定是否要使用该__init__()方法,因为__new__()可以调用其他类的构造方法或者直接返回别的对象作为本类的实例。

具体参考:https://www.cnblogs.com/ifantastic/p/3175735.html

要记住的是:在实例化时,__new__() 先与 __init__() 方法执行.

通常来讲,新式类开始实例化时,__new__()方法会返回cls(cls代指当前类)的实例,然后该类的__init__()方法作为构造方法会接收这个实例(self)作为自己的一个参数,然后依次传入__new__()方法中接收的位置参数和命名参数。

In [1]: class Foo:
...: def __init__(self, *args, **kwargs):
...: print('in init function.')
...: def __new__(cls, *args, **kwargs): # 实例化时,首先执行__new__方法
...: print('in new function.')
...: return object.__new__(cls, *args, **kwargs) In [2]: f = Foo()
in new function.
in init function.

对于__new__ 和 __init__ 的个人理解如下:

首先,我们把一个类比一个生物,使用__new__方法是创建这个生物的本体(实例),当本体(实例)创建好,才能使用__init__来创建这个本体的属性

一个单例模式来印证上面的描述:

In [1]: class Foo:
...: def __init__(self, *args, **kwargs):
...: pass
...: def __new__(cls, *args, **kwargs):
...: if not hasattr(cls, '_instance'):
...: cls._instance = object.__new__(cls, *args, **kwargs)
...: return cls._instance In [2]: one = Foo() In [3]: two = Foo() In [4]: id(one)
Out[4]: 2173030026152 In [5]: id(two)
Out[5]: 2173030026152 In [6]: print(one == two)
True In [7]: print(one is two)
True

通过__new__方法,首先创建实例的本体,当第二次实例化时,通过if判断,这个本体已经存在,就直接返回,然后在调用__init__()方法附加属性值

python3 正常的使用格式:

class Foo(object):

    def __new__(cls, *args, **kwargs):
return object.__new__(cls) def __init__(self, name):
self.name = name f = Foo('hkey')
print(f.name)

__del__

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无需定义,因为python是一门高级语言,程序员在使用时无需关心内存和释放,因为此工作都是交给python解释器来执行的,所有,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

在 pycharm中当程序执行完,自动触发 __del__ 方法

class Foo:
def __init__(self, name):
self.name = name def __del__(self):
print('执行__del__.') f = Foo('hkey') # 执行结果:
执行__del__. __del__ 在类中适合做一些关闭文件句柄等操作。

__call__

当对象+()时候[object()] 触发

class Foo:
def __init__(self, name):
self.name = name def __call__(self, *args, **kwargs):
print('执行__call__.') f = Foo('hkey')
f() # 执行结果:
执行__call__.

__len__

使用 len(object) 触发

class Foo:
def __init__(self, name):
self.name = name def __len__(self):
return 10 # 注意返回结果必须是 int 类型 f = Foo('hkey')
print(len(f)) # 执行结果:
10

__hash__

调用 hash(object) 触发

class Foo:
def __init__(self):
self.a = 1
self.b = 5 def __hash__(self):
return hash(str(self.a) + str(self.b)) f = Foo()
print(hash(f)) # 执行结果:
2068706206124340336

__eq__

当两个对象进行比较时,触发

class Foo:
def __init__(self):
self.a = 1
self.b = 5 def __eq__(self, other):
if self.a == other.a and self.b == other.b:
return True
return False a = Foo()
b = Foo()
print(a == b) # 执行这个比较的时候,就调用了 __eq__ 方法 # 执行结果:
True

实例练习:纸牌

from collections import namedtuple

Card = namedtuple('Card', ['rank', 'suit'])

class FranchDeck:
ranks = [x for x in range(2, 11)] + list('JQKA')
suits = ['红桃', '黑桃', '方块', '梅花'] def __init__(self):
'''创建一副牌'''
self._card = [Card(rank, suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self):
'''统计牌数'''
return len(self._card) def __getitem__(self, item):
'''通过object[index]取牌'''
return self._card[item] def __setitem__(self, key, value):
'''调用 shuffle 的时候需要有__setitem__方法'''
self._card[key] = value f = FranchDeck()
print(f[:4]) # 按照顺序取牌
from random import shuffle
shuffle(f) # 随机排列
print(f[:4]) # 切片随机取4张 # 执行结果:
[Card(rank=2, suit='红桃'), Card(rank=2, suit='黑桃'), Card(rank=2, suit='方块'), Card(rank=2, suit='梅花')]
[Card(rank=7, suit='红桃'), Card(rank=3, suit='方块'), Card(rank='J', suit='红桃'), Card(rank=5, suit='黑桃')]

纸牌

[ python ] 类中的一些特殊方法的更多相关文章

  1. 孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘

    孤荷凌寒自学python第二十四天python类中隐藏的私有方法探秘 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 今天发现了python的类中隐藏着一些特殊的私有方法. 这些私有方法不管我 ...

  2. Python 简明教程 --- 20,Python 类中的属性与方法

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 与客户保持良好的关系可以使生产率加倍. -- Larry Bernstain 目录 类中的变量称为属 ...

  3. python类中__unicode__和__str__方法的妙用

    在python类中有个__str__的特殊方法,该方法可以使print打印出来的东西更美观,在类里就可以定义,如下代码: class Test: def __init__(self, name, jo ...

  4. 第8.18节 Python类中内置析构方法__del__

    一. 引言 基本上所有支持OOP设计的语言都支持析构方法(也称析构函数),析构方法都是在对象生命周期结束时调用,一般用来实施实例相关生命周期内访问数据的扫尾工作,包括关闭文件.释放内存.输出日志.清理 ...

  5. python 类中staticmethod,classmethod,普通方法

    1.staticmethod:静态方法和全局函数类似,但是通过类和对象调用. 2.classmethod:类方法和类相关的方法,第一个参数是class对象(不是实例对象).在python中class也 ...

  6. python类中的一些神奇方法

    __str__:用于在print(对象)时,直接打印__str__的返回值 class Animal: def __init__(self, name): self.name = name def _ ...

  7. python类中保存非绑定方法作为成员函数

    习惯了函数式,动不动传一个函数.但是直接把函数作为类方法保存,再调用时会报错. 举一个unittest时的例子 class MyTestCase(unittest.TestCase): @classm ...

  8. 第8章 Python类中常用的特殊变量和方法目录

    第8章 Python类中常用的特殊变量和方法 第8.1节 Python类的构造方法__init__深入剖析:语法释义 第8.2节 Python类的__init__方法深入剖析:构造方法案例详解 第8. ...

  9. 简述 Python 类中的 __init__、__new__、__call__ 方法

    任何事物都有一个从创建,被使用,再到消亡的过程,在程序语言面向对象编程模型中,对象也有相似的命运:创建.初始化.使用.垃圾回收,不同的阶段由不同的方法(角色)负责执行. 定义一个类时,大家用得最多的就 ...

随机推荐

  1. [NOI2006]网络收费

    题面在这里 description 一棵\(2^n\)个叶节点的满二叉树,每个节点代表一个用户,有一个预先的收费方案\(A\)或\(B\); 对于任两个用户 \(i,j(1≤i<j≤2^n)i, ...

  2. POJ2826:An Easy Problem?!——题解(配特殊情况图)

    http://poj.org/problem?id=2826 题目大意:给两条线,让它接竖直下的雨,问其能装多少横截面积的雨. ———————————————————————————— 水题,看题目即 ...

  3. 学习操作Mac OS 之 使用brew安装软件

    安装brew软件 安装方法:  在Mac中打开Termal:  输入命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercont ...

  4. poj2409:Let it Bead(置换群 polya定理)

    题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案. 学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展. burnside定理 ...

  5. 【逆序对相关/数学】【P1966】【NOIP2013D1T2】 火柴排队

    传送门 Description 涵涵有两盒火柴,每盒装有 $n$ 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为:$ \sum ...

  6. 《python核心编程》--读书笔记 第21章 数据库编程

    准备:今天拿笔记本装了mysql,这样就能在不同地方用其他电脑远程访问同一个数据库了. python安装MySQLdb模块:http://www.codegood.com/downloads. 21. ...

  7. 重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

    方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性.重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同.参数个数不同或者二者都不同)则视 ...

  8. Leetcode 200. 岛屿的个数(扩展)

    1.题目描述 给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量.一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的.你可以假设网格的四个边均被水包围. 示例 ...

  9. maven中net.sf.json报错的解决方法(转载)

    原文:http://www.cnblogs.com/winner-0715/p/5928514.html 今天在用maven添加net.sf.json的jar包的时候,代码如下: <depend ...

  10. liunx系统下安装mysql数据库5.7.13版本

    一:在/usr/local目录下解压安装包