Python面向对象-定制方法
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面向对象-定制方法的更多相关文章
- Python 面向对象 特殊方法(魔法方法)
Python 的特殊方法,两边带双下划线的方法. 比如:__init__(self, ...).__del__(self) 1.__init__(self,...) : 构造方法 __init__(s ...
- python面向对象魔术方法补充
一.描述符 在 面向对象 编程中 定义一个(没有定义方法)类:class person , 在这个类里面,有name,age, heigth, weight,等等属性, 这个类就可以看作一个对 per ...
- Python面向对象之方法
普通方法要执行类里面的方法是通过对象触发的 触发的时候把自己赋值给self 类方法 vim day7-7.py #!/usr/bin/python # -*- coding:utf-8 -*- cla ...
- python 面向对象 析构方法
实例化但从来没有调用他,就浪费了,就应该自动删除它 这个实例一直存在内存里 python有个垃圾自动回收机制 , 每段时间会自动刷新整个内存,把内存垃圾东西删除 析构函数: 在实例释放.销毁的时候 ...
- python面向对象-1方法、构造函数
类是指:描述一种事物的定义,是个抽象的概念 实例指:该种事物的一个具体的个体,是具体的东西 打个比方: “人”是一个类.“张三”是人类的一个具体例子 在编程时也是同样的道理,你先自己定义一个“类”,当 ...
- [Python]python面向对象 __new__方法及单例设计
__new__ 方法 使用 类名() 创建对象时,Python 的解释器 首先 会 调用 __new__ 方法为对象 分配空间 __new__ 是一个 由 object 基类提供的 内置的静态方法,主 ...
- Python面向对象 | 鸭子方法
鸭子类型 如果看起来像.叫声像而且走起路来像鸭子,那么它就是鸭子’.python程序员通常根据这种行为来编写程序.例如,如果想编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为像,但与 ...
- 用python面向对象的方法实现欧拉算法和龙格库塔算法
#!/bin/python3 # -*-coding:utf-8 -*- import math import numpy as np #定义一个欧拉算法的类,从而实现不同步长的引用 class Eu ...
- python面向对象--item方法
class Foo: def __getitem__(self, item): print("getitem") return self.__dict__[item] def __ ...
随机推荐
- Spring中常见的设计模式——原型模式
1.原型模式应用场景 当遇到大量耗费劳动力的 get,set赋值场景时,如下: public class SetGetParam { public void setParam(UserDto user ...
- springboot整合netty的多种方式
netty作为一个高性能的io框架,是非好用的一个技术框架, Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户. ...
- ehcache同步原理
最近研究ehcache同步时发现一个问题: 现有A.B两个服务器,由A服务器向B服务器同步信息,采用RMI方式手动方式进行同步 配置信息如下: <?xml version="1.0&q ...
- Linux常见的Shell命令
1.具体的shell命令用法可以通过help或man命令进入手册来查询其具体的用法.2.终端本质上对应着linux上的/dev/tty设备,linux的多用户登录就是通过不同的/dev/tty设备完成 ...
- kube-nginx 和 keepalived 部署安装
目录 简介 nginx 安装配置 下载编译nginx 配置Nginx文件,开启4层透明转发 配置Nginx启动文件 keepalived 安装配置 安装keeplive服务 配置keeplive服务 ...
- 行内元素(inline标签)设置了行高为什么不生效,还是表现为父盒子的行高?行内元素行高问题终极解释
最近在看张鑫旭大佬的<css世界>,读到5.2.4 内联元素 line-height 的“大值特性” ,产生了疑惑, 在开发中确实也遇到了同样的问题,深入探究后得出结果,先说结论吧,论证 ...
- C语言I作业11
C语言 博客作业11 问题 回答 C语言程序设计II 博客作业11 这个作业要求在哪里 作业要求 我在这个课程的目标是 理解和弄懂局部变量和全局变量,静态变量和动态变量 这个作业在哪个具体方面帮助我实 ...
- ASCII, Unicode, UTF-8
(本文参考:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html) 1. ASCII码 我们知道,在计算机内部,所有的 ...
- Python中的Tcp协议应用之TCP服务端-协程版(推荐)
利用gevent第三方库,实现协程. 通过协程实现一个服务端服务多个客户端需求. 使用协程的好处是协程比线程更加节省内存资源. gevent安装命令: pip3 install gevent 注意:在 ...
- git 使用详解(8)—— 分支HEAD、branch/checkout
有人把 Git 的分支模型称为"必杀技特性",而正是因为它,将 Git 从版本控制系统家族里区分出来.Git 有何特别之处呢?Git 的分支可谓是难以置信的轻量级,它的新建操作几乎 ...