特殊方法

有的名称前后都有两个下划线,如__future__,由这些名字组成的集合所包含的方法称为特殊方法。

构造方法

构造方法是一个特殊方法。当一个对象被创建后,会立即调用构造方法。
创建构造方法:

class FooBar:def __init__(self):self.somevar = 42f = FooBar()
print f.somevar #42

也可以在构造方法中传入参数:

class FooBar:def __init__(self,value=42):self.somevar = value

子类重写父类的方法

如果一个方法在B类的一个实例中被调用(或一个属性被访问),但在B类中没有找到,那么就会去超类A中去找:

class A:def hello(self):print "Hello,I'm A."class B(A):passif __name__ == '__main__':a = A()b = B()a.hello() #Hello,I'm A.b.hello() #Hello,I'm A.

也可重写一些父类的方法:

class A:def hello(self):print "Hello,I'm A."class B(A):def hello(self):print "Hello,I'm B."if __name__ == '__main__':a = A()b = B()a.hello() #Hello,I'm A.b.hello() #Hello,I'm B.

如果一个类的构造方法被重写,那么就需要调用超类的构造方法。

# -*- coding: utf-8 -*
class Bird:def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print 'Aaaah...'self.hungry = Falseelse:print 'No,thanks!'if __name__ == '__main__':b = Bird()b.eat() #Aaaah...b.eat() #No,thanks!

这个类定义了所有鸟类都具有的基本能力——吃。

class Bird:def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print 'Aaaah...'self.hungry = Falseelse:print 'No,thanks!'class SongBird(Bird):def __init__(self):self.sound = 'Squawk!'def sing(self):print self.soundif __name__ == '__main__':sb = SongBird()sb.sing()# Squawk!

我们增加了一个子类,为它添加唱歌的行为。它继承了eat方法:

Traceback (most recent call last):File "D:/workspace/python/LearnPython/SpecialMethod/Bird.py", line 22, in <module>sb.eat()File "D:/workspace/python/LearnPython/SpecialMethod/Bird.py", line 7, in eatif self.hungry:
AttributeError: SongBird instance has no attribute 'hungry'

但是如果调用会报错。异常说SongBird没有hungry特性(attribute)。
为了达到预期的效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保进行基本的初始化。

可以通过调用超类构造方法的未绑定版本或使用super函数。

调用未绑定的超类构造方法

class Bird:def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print 'Aaah...'self.hungry = Falseelse:print 'No,thanks!'class SongBird(Bird):def __init__(self):Bird.__init__(self) # 调用父类构造方法self.sound = 'Squawk!'def sing(self):print self.soundsb = SongBird()
sb.sing() #Squawk!
sb.eat() #Aaah...
sb.eat() #No,thanks!

调用一个实例的方法时,该方法的self参数会自动绑定到实例上,这称为绑定方法。

如果直接调用的方法,如Bird.__inint__,那么就没有实例会被绑定,就要提供需要的self参数,这样的方法称为未绑定方法。

使用super函数

在Python3.0中推荐使用super函数。

__metaclass__=type # super函数只在新式类中起作用
class Bird:def __init__(self):self.hungry = Truedef eat(self):if self.hungry:print 'Aaaah...'self.hungry = Falseelse:print 'No,thanks!'class SongBird(Bird):def __init__(self):super(SongBird,self).__init__() # 注意super括号里面是逗号self.sound = 'Squawk!'def sing(self):print self.soundif __name__ == '__main__':sb = SongBird()sb.sing()# Squawk!sb.eat()sb.eat()

成员访问

可以创建行为类似序列或映射的对象。

基本的序列和映射规则

序列和映射是对象的集合。为了实现它们的基本行为(规则),如果对象是不可变的,需要两个魔法方法;可变的则需要四个。

  • __len__(selft):返回集合中所含元素的数量
  • __getitem__(self,key):返回与所给定键(序列:索引;映射:key)对应的值
  • __setitem__(self,key,value):存储key和相关的value
  • __delitem__(self,key):在使用del时,同时删除key和value

我们来应用下这些规则:

# -*- coding: utf-8 -*class ArithmeticSequence:def __init__(self, start=0, step=1):"""初始化算术序列:param start: 序列中的第一个值:param step: 两个相邻值之间的差值_changed : 修改的值的字典"""self._start = startself._step = stepself._changed = {}def __getitem__(self, key):"""从算术序列中返回一项(key,value):param key::return:"""self.checkIndex(key)try:return self._changed[key]  # 修改了则返回except KeyError:return self._start + key * self._step  # 计算值def __setitem__(self, key, value):"""修改算术序列中的一个项:param key::param value:"""self.checkIndex(key)self._changed[key] = valuedef checkIndex(self, key):if not isinstance(key, (int, long)): raise TypeErrorif key < 0: raise IndexErrorif __name__ == '__main__':s = ArithmeticSequence(1,2)print s[4] # 需要实现__getitem__s[4] = 2 #__setitem__print s[4],s[5]del s[4] # 报错:ArithmeticSequence instance has no attribute '__delitem__'

这些魔法方法挺有用的,尤其是你想实现自己的集合类时。

子类化列表,字典和字符串

如果希望实现一个和内建列表行为相似的序列,可以继承list来实现。

当继承一个内建类型时,也就间接地继承了object。因此该类就自动成为新式类,意味着可以使用super函数这样的特性了

# -*- coding: utf-8 -*class CounterList(list):def __init__(self,*args):super(CounterList,self).__init__(*args)self.counter = 0 #增加counter特性def __getitem__(self, index):self.counter += 1return super(CounterList,self).__getitem__(index)if __name__ == '__main__':cl = CounterList(range(10))print cl #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]cl.reverse()print cl #[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]del cl[3:6]print cl #[9, 8, 7, 3, 2, 1, 0]print cl[4] + cl[2] #9 这里调用了两次getitemprint cl.counter #2

CounterList在很多方面和列表一样,但它有一个counter特性,每次访问时都会自增。

属性

如果在访问给定特性时徐必须要采取一些行动,那么像这样的封装状态变量(特性)就很重要,如下面的例子:

class Rectangle:def __init__(self):self.width = 0self.height = 0def setSize(self,size): # 访问器方法self.width,self.height = sizedef getSize(self):  # 访问器方法return self.width,self.heightif __name__ == '__main__':r = Rectangle()r.width = 10r.height = 5print r.getSize() #(10, 5)r.setSize((150,100)) print r.width #150

上面的例子中,getSizesetSize是一个名为size的假想特性的访问器方法。size是由widthheight构成的元组。这种方式有缺陷,当使用这个类时,不应该要考虑它是怎么实现的(这里是通过元组)。

Python能隐藏访问器方法,让所有特性(attribute)看起来一样。这些通过访问器定义的特性被称为属性(property)。

python中的类成员变量称为特性,作为一Java开发人员有点不习惯啊

property函数

使用property函数可以创建属性。

# -*- coding: utf-8 -*
__metaclass__ = type #property函数只在新式类中使用,不加会最后的r.width打印10class Rectangle:def __init__(self):self.width = 0self.height = 0def setSize(self, size):  # 访问器方法self.width, self.height = size  # 元组的赋值def getSize(self):  # 访问器方法return self.width, self.heightsize = property(getSize, setSize)if __name__ == '__main__':r = Rectangle()r.width = 10r.height = 5print r.size  # (10, 5)r.size = 150, 100print r.width  # 150

property函数创建了一个属性,其中访问器函数被用作参数(先是取值,然后是赋值),这个属性命名为size。

property()函数中的两个函数分别对应的是获取属性的方法、设置属性的方法,这样一来,外部的对象就可以通过访问size的方式,来达到获取、设置的目的。

当需要更改上例中的getSize、setSize函数的名称时,如果这些方法是作为接口让用户调用的,那么对用户而言就要修改自己调用的方法名,很麻烦,使用了proprty()后,用户就不需担心这种问题了。

静态方法和类成员方法

静态方法和类成员方法分别在创建时装入Staticmethod类型和Classmethod类型的对象中。静态方法的定义没有self参数,能被类本身直接调用。类方法在定义时需要名为cls的参数,类成员方法可以直接用类的具体对象调用。

__metaclass__ = typeclass MyClass:@staticmethoddef smeth():print 'This is a static method'@classmethoddef cmeth(cls):print 'This is a class method of',clsMyClass.smeth() #This is a static method
MyClass.cmeth() #This is a class method of <class '__main__.MyClass'>

上面的代码中没有实例化类。

__getattr____setattr__等方法

拦截对象的所有特性访问时可能的。为了在访问特性的时候可以执行代码,必须使用一些魔法方法。

  • __getattribute__(self,name):当特性name被访问时自动被调用(新式类)
  • __getattr__(self,name):当特性name被访问且对象没有相应的特性时被自动调用
  • __setattr__(self,name,value):当试图给特性name赋值时会被自动调用
  • __delattr__(self,name):当试图删特性name时被自动调用
class Rectangle:def __init__(self):self.width = 0self.height = 0def __setattr__(self, name, value):if name == 'size':self.width,self.height = valueelse:self.__dict__[name] = value #__dict__中是所有实例的属性def __getattr__(self, name):if name == 'size':return self.width,self.heightelse:raise AttributeErrorif __name__ == '__main__':r = Rectangle()r.size = 10,5print r.size  # (10, 5)r.width = 100r.height = 50print r.size #(100, 50)

迭代器

这里只讨论一个特殊方法——__iter__

迭代器规则

只要对象实现了__iter__方法就可以进行迭代。该方法会返回一个迭代器,可以用在for循环中。

使用迭代器实现的斐波那契数列:

class Fibs:def __init__(self):self.a = 0self.b = 1def next(self): #实现了next方法的对象是迭代器self.a,self.b = self.b,self.a + self.breturn self.adef __iter__(self): #实现了__iter__方法的对象是可迭代的return self

每次访问next的时候生成下一个值:

fibs = Fibs()
for f in fibs:if f > 1000:print f #1597break

从迭代器得到序列

迭代器和可迭代对象还能转换为序列,比如使用list构造方法显示地将迭代器转换为列表:

class TestIterator:value = 0def next(self):self.value += 1if self.value>10 : raise StopIteration #用于结束迭代return self.valuedef __iter__(self):return selfti = TestIterator()
print list(ti) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

生成器

生成器是一种用普通的函数语法定义的迭代器。

创建生成器

创建生成器和创建函数类似,任何包含yield(ES6中也有这个关键字)语句的函数称为生成器。以一个例子来讲解。
首先创建一个列表的列表:

nested = [[1,2,3],[4,5],[6]]

然后写一个生成器:

def flatten(nested):for sublist in nested:for element in sublist:yield element  # 每产生一个值,函数就会被冻结

每次访问到yield语句时,产生一个值,并且函数被冻结,等待被重新唤醒。函数被重新唤醒后就从停止的那点开始执行。

下面在生成器上迭代来使用所有的值:

for num in flatten(nested):print num

输出:

1
2
3
4
5
6

也可以通过list函数来访问:

print list(flatten(nested)) #[1, 2, 3, 4, 5, 6]

生成器推导式返回的是生成器,并且不会立刻进行循环:

>>>g = ((i+2)**2 for i in range(2,27))
>>>g.next()
16
>>>g.next()
25

递归生成器

如果想要处理任意层的嵌套,应该使用递归。

def flatten(nested):try:for sublist in nested: #可迭代的情况for element in flatten(sublist):yield elementexcept TypeError: # 和不可迭代的情况yield nestedprint list(flatten([[[1],2],3,4,[5,[6,7,[8,9]]]])) #[1, 2, 3, 4, 5, 6, 7, 8, 9]

这样做有一个问题:如果nested是一个类似于字符串的对象,那么会导致无穷递归。因为一个字符串的第一个元素是另一个长度为1的字符串,而长度为1的字符串的第一个元素就是字符串本身。
我试了一下,会抛出异常RuntimeError: maximum recursion depth exceeded

def flatten(nested):try:#不要迭代类似字符串的对象try: nested + ''except TypeError: pass #nested + ''产生的异常被忽略,直接到for语句else: raise TypeErrorfor sublist in nested: #可迭代的情况for element in flatten(sublist):yield elementexcept TypeError: # 和不可迭代的情况yield nestedprint list(flatten('123')) #['123']

如果表达式nested + ''引发了一个TypeError说明它不是类似字符串的序列,可以被迭代;否则如果没有引发TypeError,那else子句会引发一个自己的TypeError,直接返回这个类似字符串序列。这是检查一个对象是不是类似于字符串的最简单、最快速的方法。

通用生成器

生成器由两部分组成:生成器函数和生成器的迭代器。
生成器的函数是用def语句定义的,包含yield的部分,
生成器的迭代器是这个函数返回的部分。

>>>def simple_geneartor():yield 1>>>simple_geneartor
<function simple_geneartor at 0x03003770>
>>>simple_geneartor()
<generator object simple_geneartor at 0x02FEA7D8>

生成器方法

生成器的新特性(send())是在开始运行后为生成器提供值的能力。

有两个注意的地方:

  • 外部作用域访问该方法,需要和传递一个参数(作为值)
  • 在内部挂起生成器,yield现在作为表达式而不是语句使用,使用send()方法只有在生成器挂起后才有意义
>>> def repeater(value):
...     while True:
...             new = (yield value)
...             if new is not None: value = new
...
>>> r = repeater(42)
>>> r.next()
42
>>> r.send("Hello")
'Hello'
>>>

生成器还有两个方法throw()用于在yield表达式中引发一个异常;close()方法用于停止生成器。

Python中的特殊方法、属性和迭代器相关推荐

  1. Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法

    Day09新手小白学python 第九节 Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法 目录 Day09新手小白学python 前言 一.面向对象介绍 二 ...

  2. python深度讲解_《深度剖析CPython解释器》21. Python类机制的深度解析(第五部分): 全方位介绍Python中的魔法方法,一网打尽...

    楔子 下面我们来看一下Python中的魔法方法,我们知道Python将操作符都抽象成了一个魔法方法(magic method),实例对象进行操作时,实际上会调用魔法方法.也正因为如此,numpy才得以 ...

  3. 获取Python中的所有对象属性?

    本文翻译自:Get all object attributes in Python? Is there a way to get all attributes/methods/fields/etc. ...

  4. python使用方法-在Python中使用next()方法操作文件的教程

    next()方法当一个文件被用作迭代器,典型例子是在一个循环中被使用,next()方法被反复调用.此方法返回下一个输入行,或引发StopIteration异常EOF时被命中. 与其它文件的方法,如Re ...

  5. python中函数和方法的区别

    本篇内容主要介绍从几个维度来介绍下python中函数和方法的区别: 首先,从分类的角度来分析. (1)函数的分类: 内置函数:python内嵌的一些函数. 匿名函数:一行代码实现一个函数功能. 递归函 ...

  6. python脚本怎么使用_在Python中使用next()方法操作文件的教程

    next()方法当一个文件被用作迭代器,典型例子是在一个循环中被使用,next()方法被反复调用.此方法返回下一个输入行,或引发StopIteration异常EOF时被命中. 与其它文件的方法,如Re ...

  7. Python 中的特殊方法(定制类):__str__、__cmp__、__len__、数学运算、类型转换、@property运用、__slots__和__call__函数

    Python中的特殊方法 Python的特殊方法定义在 class中,不需要直接进行显示调用,Python的某些操作符或者函数会自动调用对应的特殊方法.这些方法如:__str__().__len__( ...

  8. python方法_详细解读Python中的__init__()方法

    __init__()方法意义重大的原因有两个.第一个原因是在对象生命周期中初始化是最重要的一步:每个对象必须正确初始化后才能正常工作.第二个原因是__init__()参数值可以有多种形式. 因为有很多 ...

  9. python中的魔方方法

    python中的魔方方法 魔法方法 含义 基本的魔法方法 new(cls[, -]) 1. new 是在一个对象实例化的时候所调用的第一个方法 2. 它的第一个参数是这个类,其他的参数是用来直接传递给 ...

  10. python 中的魔术方法 getitem setitem

    python 中的魔术方法 getitem setitem https://docs.python.org/3/reference/datamodel.html?highlight=iter#obje ...

最新文章

  1. 填空题C语言,c语言填空题试卷.doc
  2. 3、构建bass服务及model
  3. 三目运算符对比三个_Javascript之if条件语句和三目运算符
  4. css3自适应布局单位vw,vh
  5. php表格怎么合并单元格格式化,table标签的结构与合并单元格的实现方法
  6. 经典面试题(28):以下代码将输出的结果是什么?
  7. Linq to Xml (1) 创建和查询包含命名空间的XML文档
  8. mac下hive-2.2.0-src版本的编译
  9. 用unity制作能量护盾(3)
  10. python图例重复显示_python – 具有两个标记的多行的自定义图例,用于相同的文本...
  11. Ubuntu下pdf乱码和rar解压后无效文件编码解决方案
  12. 标准模板库 STL—— set 列传
  13. 主流强化学习算法论文综述:DQN、DDPG、TRPO、A3C、PPO、SAC、TD3
  14. 思科ASA防火墙端口映射
  15. 【转】用万兆网卡测试超五类网线传输速度,颠覆你的认知
  16. 办理加拿大普通学生签证 20180717
  17. 基于微信小程序的兼职发布接单系统
  18. LOJ3124 CTS2019 氪金手游 概率、容斥、树形DP
  19. 金融风控-贷款违约预测项目记录
  20. Grafana常用定制修改

热门文章

  1. 三层结构中的数据层设计
  2. python获取小程序手机号并绑定
  3. 【转】Odoo开发之:工作流 workflow
  4. 20155207第十章课下测试补交
  5. XAMPP浏览器输入localhost跳转localhost/dashboard/
  6. java中int算法的有趣现象
  7. codeforces 733D
  8. The Willpower Instinct(自控力,意志力)
  9. 一个高性能RPC框架的连接管理
  10. Uva 10306 e-Coins