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

我们之前介绍了__slots__、__len__(),python中还有许多这样的特殊函数:

__str__

>>> class Student(object):
... def __init__(self,name):
... self.name = name
...
>>> print(Student('wc'))
<__main__.Student object at 0x035F3630>

上面我们定义了一个普通的Student类,打印出的是一堆<__main__.Student object at 0x035F3630> 。如何自定义打印的内容呢?比如我们关心的"WC"呢。这时__str__()派上用场了:

>>> class Student(object):
... def __init__(self,name):
... self.name = name
... def __str__(self):
... return '%s'%self.name
...
>>> print(Student('wc'))
wc

在看看我们直接调用变量会是什么情况:

>>> s = Student('wc')
>>> s
<__main__.Student object at 0x035F3AB0>

当我们直接调用变量的时候,怎么自定义打印的内容呢?使用__repr__()函数:

>>> class Student(object):
... def __init__(self,name):
... self.name = name
... def __str__(self):
... return '%s'%self.name
... def __repr__(self):
... return '%s'%self.name
...
>>> print(Student('wc'))
wc
>>> s = Student('wc')
>>> s
wc

一般来说,__str__和__repr__定义的内容是一样的,只是前者是给用户看的,后者给开发者看的。

__iter__

之前我们介绍过可迭代对象:如果我们想让一个类可以被for……in循环,就必须实现方法__iter__()方法。该方法返回一个迭代对象。下面写一个模仿输出斐波拉契数列的Fib类:

>>> class Fib(object):
... def __init__(self):
... self.a,self.b = 0,1
... def __iter__(self):
... return self
... def __next__(self):
... self.a,self.b = self.b,self.a+self.b
... if self.a > 1000:
... raise StopIteration()
... return self.a
...
>>> for i in Fib():
... print(i)
...
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987

__getitem__

尝试把Fib当做list使用,比如取第三个元素:

>>> Fib()[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Fib' object does not support indexing

不行!

要表现的像list那样按照按照角标去除元素,需要实现__getiten__():

>>> class Fib(object):
... def __getitem__(self,n):
... a,b = 1,1
... for i in range(n):
... a,b = b,a+b
... return a
...
>>> f = Fib()
>>> f[3]
3
>>> f[10]
89

再来试试Fib如何使用切片方法:

>>> class Fib(object):
... def __getitem__(self,n):
... if isinstance(n,int):
... a,b = 1,1
... for i in range(n):
... a,b = b,a+b
... return a
... if isinstance(n,slice):
... start = n.start
... stop = n.stop
... if start is None:
... start = 0
... a,b = 1,1
... L = []
... for i in range(stop):
... if i >= start:
... L.append(a)
... a,b = b,a+b
... return L
...
>>> f = Fib()
>>> f[0:3]
[1, 1, 2]
>>> f[:5]
[1, 1, 2, 3, 5]
>>> f[:6:2]
[1, 1, 2, 3, 5, 8]

但是,我们还没对负数做处理。要实现一个__getitem__()还有、还可以做很多事情。比如,如果把类看做是一个dict,可以使__getitem__()的参数为key的object。与之对应的是__setitem__()方法,可以把对象视作list或者dict来赋值;此外,还存在__delitem__()方法,用来删除某个元素。

通过上面的方法,我们可以自定义一个类,使其表现的像python自带的list、tuple、dict一样。由此,我们对于‘鸭子类型’的设计有了更深刻的理解。

__getattr__

当我们定义好一个类后,如果想调用类不存在的属性或者方法,我们可以给实例增加一个属性或者方法;其实,python还有另外一个机制,那就是写一个__getattr__()函数,动态返回一个属性。:

>>> class Student(object):
... def __init__(self):
... self.name = 'wc'
... def __getattr__(self,attr):
... if attr == 'score':
... return 88
...
>>> s = Student()
>>> s.name
'wc'
>>> s.score
88

当调用不存在的属性时,python的机制会调用__getattr__()方法来尝试的得到属性。同样的,也适用于返回函数:

>>> class Student(object):
... def __getattr__(self,attr):
... if attr == 'age':
... return lambda:20
...
>>> s = Student()
>>> s.age()
20

注意:只有在没有找到属性的情况下,才会调用__getdattr__()!

继续优化一下:当我们任意调用不存在的属性时,返回指定的错误:

>>> class Student(object):
... def __getattr__(self,attr):
... if attr == 'age':
... return lambda:20
... raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
...
>>> s = Student()
>>> s.haha
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getattr__
AttributeError: 'Student' object has no attribute 'haha'

这实际上把一个类的所有属性和方法调用全部动态化处理了。相当有用。

__call__

一个对象实例可以有自己的属性和方法。我们能不能直接在实例本身上调用呢?既然这么问,那答案是肯定的。任何类只要定义一个__call__()方法,就可以直接对实例进行调用:

>>> class Student(object):
... def __init__(self,name):
... self.name = name
... def __call__(self):
... print('你好:%s'% self.name)
...
>>> s = Student('wc')
>>> s()
你好:wc

对实例对象进行直接调用就好比对一个函数调用一样,既可以把对象看成函数,把函数看成对象。

如果你把对象看成函数,那么函数本身也可以在运行期间动态创建出来,因为类的实例都是在运行期间创建出来的。

那么怎么判断一个变量是对象还是函数呢?其实更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象:

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

更多的内置函数对象参见官网

Python面向对象-定制方法的更多相关文章

  1. Python 面向对象 特殊方法(魔法方法)

    Python 的特殊方法,两边带双下划线的方法. 比如:__init__(self, ...).__del__(self) 1.__init__(self,...) : 构造方法 __init__(s ...

  2. python面向对象魔术方法补充

    一.描述符 在 面向对象 编程中 定义一个(没有定义方法)类:class person , 在这个类里面,有name,age, heigth, weight,等等属性, 这个类就可以看作一个对 per ...

  3. Python面向对象之方法

    普通方法要执行类里面的方法是通过对象触发的 触发的时候把自己赋值给self 类方法 vim day7-7.py #!/usr/bin/python # -*- coding:utf-8 -*- cla ...

  4. python 面向对象 析构方法

    实例化但从来没有调用他,就浪费了,就应该自动删除它 这个实例一直存在内存里 python有个垃圾自动回收机制 , 每段时间会自动刷新整个内存,把内存垃圾东西删除   析构函数: 在实例释放.销毁的时候 ...

  5. python面向对象-1方法、构造函数

    类是指:描述一种事物的定义,是个抽象的概念 实例指:该种事物的一个具体的个体,是具体的东西 打个比方: “人”是一个类.“张三”是人类的一个具体例子 在编程时也是同样的道理,你先自己定义一个“类”,当 ...

  6. [Python]python面向对象 __new__方法及单例设计

    __new__ 方法 使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间 __new__ 是一个 由 object 基类提供的 内置的静态方法,主 ...

  7. Python面向对象 | 鸭子方法

    鸭子类型 如果看起来像.叫声像而且走起路来像鸭子,那么它就是鸭子’.python程序员通常根据这种行为来编写程序.例如,如果想编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为像,但与 ...

  8. 用python面向对象的方法实现欧拉算法和龙格库塔算法

    #!/bin/python3 # -*-coding:utf-8 -*- import math import numpy as np #定义一个欧拉算法的类,从而实现不同步长的引用 class Eu ...

  9. python面向对象--item方法

    class Foo: def __getitem__(self, item): print("getitem") return self.__dict__[item] def __ ...

随机推荐

  1. An end-to-end TextSpotter with Explicit Alignment and Attention

     An end-to-end TextSpotter with Explicit Alignment and Attention 论文下载:http://cn.arxiv.org/pdf/1803.0 ...

  2. 设计模式——代理模式(Proxy)

    定义 为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端和目标对象之间起到中介的作用.(结构型) 如果不知道代理模式,可能大家对代理服务器都不叫熟悉.代替服务器代替请求者去发一起对另一个 ...

  3. vi指令详解

    ★ vi的模式(命令模式.插入模式.ex模式) 1)命令模式: 在我们刚刚通过vi新建或打开一个已经存在的文件时,首先默认被读取的模式就是“命令模式”,命令模式的特征就是,在编辑器窗口左下角的位置上没 ...

  4. ES6之Set

    阮大神的es6看了一遍,但是对于Set和Map还是一知半解的,主要还是没怎么用吧,这里总结一下,以后再工作中也要多用用才行 怎么定义set呢?有什么用处? set是ES6中新增的类型,和数组类似,唯一 ...

  5. Chrome插件安装的3种方法,解决拖放不能安装的情况,并提供插件下载

    本文摘录于Chrome插件网站 方法一:拖放安装 下载插件的crx文件后,打开Chrome的扩展页面(chrome://extensions/或按Chrome菜单图标>更多工具>扩展程序) ...

  6. map.entrySet().iterator()

    1.首先创建一个HashMap, Map map= new HashMap(); 2.Iterator iter= map.entrySet().iterator(); 首先是map.entrySet ...

  7. Spring Boot中@ConditionalOnProperty使用详解

    在Spring Boot的自动配置中经常看到@ConditionalOnProperty注解的使用,本篇文章带大家来了解一下该注解的功能. Spring Boot中的使用 在Spring Boot的源 ...

  8. powerline字体安装

    安装命令 git clone https://github.com/powerline/fonts ./install.sh 了解powerline ->美化自己的命令行环境,增加漂亮的状态行, ...

  9. 以面向对象的思维,搭建Android与多ble蓝牙设备并发通讯小框架

    Android连接多蓝牙设备.蓝牙与多设备连接.蓝牙ble多设备并发操作.Android连接不了.Android ble开发框架.Android 连接蓝牙总结 前言 小白请绕道百度,本文适合有一定An ...

  10. 大型情感剧集Selenium:9_selenium配合Pillow完成浏览器局部截图

    网页截图 上次提到了selenium的四种截图方法,最终截图了整张网页.但很多时候,我们仅仅需要截图部分的内容.比如截取某个关键信息,或者现在已经不常见的截图验证码(现在都是各种按规则点击-).那么我 ...