1.看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。__slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()函数。除此之外,Python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类。

1)__str__,定制对象自身打印的字符串

>>> class S(object):
def __init__(self,name):
self.name = name >>> print(S('SB'))
<__main__.S object at 0x0000000002E7F0F0>
>>> class S(object):
def __init__(self,name):
self.name = name
def __str__(self):
return 's object(name=%s)' % self.name >>> print(S('md'))
s object(name=md)

2)这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别是__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符串,也就是说,__repr__()是为调试服务的。

解决办法是再定义一个__repr__()。但是通常__str__()__repr__()代码都是一样的,所以,有个偷懒的写法:

<__main__.S object at 0x0000000002E7F0F0>
>>> class S(object):
def __init__(self,name):
self.name = name
def __str__(self):
return 's object(name=%s)' % self.name >>> print(S('md'))
s object(name=md)
>>> a = S('MJ')
>>> a
<__main__.S object at 0x0000000002C98390>
>>> class S(object):
def __init__(self,name):
self.name = name
def __str__(self):
return 's object(name=%s)' % self.name
__repr__ = __str__ >>> a = S('MJ')
>>> a
s object(name=MJ)

3)__iter__

如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

我们以斐波那契数列为例,写一个Fib类,可以作用于for循环:

class Fib(object):
def __init__(self):
self.a,self.b = 0,1#初始化两个计数器a,b def __iter__(self):
return self #实例本身就是迭代对象,返回自己 def __next__(self):
self.a,self.b = self.b,self.a+self.b #计算下一个值
if self.a > 10000: #循环推出条件
raise StopIteration()
return self.a #返回下一个值 >>> for n in Fib():
print(n) 1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765

4)__getitem__,要表现得像list那样按照下标取出元素,需要实现__getitem__()方法:

class Fib(object):
def __init__(self):
self.a,self.b = 0,1#初始化两个计数器a,b def __iter__(self):
return self #实例本身就是迭代对象,返回自己 def __next__(self):
self.a,self.b = self.b,self.a+self.b #计算下一个值
if self.a > 10000: #循环推出条件
raise StopIteration()
return self.a #返回下一个值 def __getitem__(self,n):
a,b = 1,1
for x in range(n):
a,b = b,a+b
return a >>> f = Fib() >>> f[0] 1
>>> f[2] 2
>>> f[3] 3
>>> f[4] 5
>>> f[8] 34
>>> f[100] 573147844013817084101

5)__getattr__,python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性。修改如下:当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值:

注意,只有在没有找到属性的情况下,才调用__getattr__,已有的属性,比如name,不会在__getattr__中查找。

此外,注意到任意调用如s.abc都会返回None,这是因为我们定义的__getattr__默认返回就是None。要让class只响应特定的几个属性,我们就要按照约定,抛出AttributeError的错误:

>>> class st(object):
def __init__(self):
self.name = 'MJ'
def __getattr__(self,attr):
if attr == 'score':
return 99 >>> s = st() >>> s.name 'MJ'
>>> s.score 99
>>> s.age >>> s.page

6)如果要写SDK,给每个URL对应的API都写一个方法,那得累死,而且,API一旦改动,SDK也要改。

利用完全动态的__getattr__,我们可以写出一个链式调用:

class Chain(object):
def __init__(self,path=''):
self._path = path def __getattr__(self,path):
return Chain('%s/%s' % (self._path,path)) def __str__(self):
return self._path __repr__ = __str__ >>> ch = Chain() >>> ch.status.user.timeline.list /status/user/timeline/list

7)__call__一个对象实例可以有自己的属性和方法,当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?在Python中,答案是肯定的。

任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例:

class tt(object):
def __init__(self,name):
self.name = name def __call__(self):
print("My name is %s " % self.name) >>> t() My name is mg

8)__call__()还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。

如果你把对象看成函数,那么函数本身其实也可以在运行期动态创建出来,因为类的实例都是运行期创建出来的,这么一来,我们就模糊了对象和函数的界限。

那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call__()的类实例:通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。

>>> callable(t)

True
>>> callable(max) True
>>> callable([1,2,3]) False
>>> callable(None) False
>>> callable('str') False

9)

Python的class允许定义许多定制方法,可以让我们非常方便地生成特定的类。

本节介绍的是最常用的几个定制方法,还有很多可定制的方法,请参考Python的官方文档

python-类的定制的更多相关文章

  1. 2015/9/28 Python基础(19):类的定制和私有性

    用特殊方法定制类前面我们讲了方法的两个重要方面:首先,方法必须在调用前被绑定(到它们相应类的某个实例中):其次,有两个特殊方法可以分别作为构造器和解构器的功能,分别名为__init__()和__del ...

  2. python 类知识点总结

    python 类知识点总结 面向对象思想: 1.设计的时候,一定要明确应用场景 2.由对象分析定义类的时候,找不到共同特征和技能不用强求 1.简述类.对象.实例化.实例这些名词的含义: 类:从一组对象 ...

  3. python类:magic魔术方法

    http://blog.csdn.net/pipisorry/article/details/50708812 魔术方法是面向对象Python语言中的一切.它们是你可以自定义并添加"魔法&q ...

  4. python类:描述器Descriptors和元类MetaClasses

    http://blog.csdn.net/pipisorry/article/details/50444769 描述器(Descriptors) 描述器决定了对象属性是如何被访问的.描述器的作用是定制 ...

  5. (转)python类:magic魔术方法

    原文:https://blog.csdn.net/pipisorry/article/details/50708812 版权声明:本文为博主皮皮http://blog.csdn.net/pipisor ...

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

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

  7. python类的相关知识第二部分

    类的继承.多态.封装 一.类的继承 1.应用场景: 类大部分功能相同,大类包含小类的情况 例如: 动物类 共性:都要吃喝拉撒.都有头有脚 特性: 猫类.走了很轻,叫声特别,喜欢白天睡觉 狗类.的叫声很 ...

  8. python 类的成员及继承

    1. @staticmethod 静态方法 静态方法不能访问实例变量和类变量,除了身处类里面,所以只能通过类调用以外,它其实和类没有什么关系.如果想要用它访问实例变量或类变量,需要把实例和类传递给函数 ...

  9. python 类(object)的内置函数

    python 类(object)的内置函数 # python 类(object)的内置函数 ### 首先 #### 以__双下划线开头的内置函数 __ #### __往往会在某些时候被自动调用,例如之 ...

  10. Python类中super()和__init__()的关系

    Python类中super()和__init__()的关系 1.单继承时super()和__init__()实现的功能是类似的 class Base(object): def __init__(sel ...

随机推荐

  1. Redis 学习目录

    Redis in .NET Core 入门 Redis实战 - 1.String和计数器 Redis实战 - 2.list.set和Sorted Set Redis实战 - 4.Key Redis实战 ...

  2. .Net 操作证书文件

    一..Net加签与验签.经过测试,发现使用同一套私钥和公钥,JAVA和.Net可以实现互通 1.1 私钥加签 公钥验签 public void Encode() { try { var path = ...

  3. webpack分片chunk加载原理

    首先,使用create-react-app快速创建一个demo npx create-react-app react-demo # npx命令需要npm5.2+ cd react-demo npm s ...

  4. Net Core Docker 容器部署,修改,保存

    运行镜像 [root@localhost opt]# docker run -itd -p : microsoft/dotnet:latest 查看运行的docker [root@localhost ...

  5. OpenCV函数学习:cvRound,cvFloor,cvCeil

    函数cvRound,cvFloor,cvCeil 都是用一种舍入的方法将输入浮点数转换成整数: cvRound 返回跟参数最接近的整数值: cvFloor 返回不大于参数的最大整数值: cvCeil ...

  6. HFS 轻量化 的文件服务器

    国外的工具 国内的工具

  7. dotnetcore Http服务器研究(一)

    自从dotnet core 诞生以来,发展非常强势.我们总有些需要写一个独立的http服务器的需求,我想是时候忘记httplistener 了. dotnet framework 时代建一个小的htt ...

  8. org.apache.http.client.ClientProtocolException: URI does not specify a valid host name

    问题截图: 原因:http:// 少了两个//

  9. Python序列化proto中repeated修饰的数据

    一.repeated修饰复合数据结构,即message时 1.使用message的add方法初始化新实例 2.分别对新实例中的每个元素赋值:或使用CopyFrom(a)拷贝a中的元素值 message ...

  10. banner | what is the "banner" ?

    banner/横幅   获取 banner(横幅) 信息属于信息搜集   因为在 banner 信息中,可以获取到软件开发商.软件名称.服务类型.版本号等   而版本号有时候就会存在公开的 CVE 问 ...