python学习笔记(方法、属性、迭代器)

准备工作

为了确保类是新型类,应该把 _metaclass_=type 入到你的模块的最开始

class NewStyle(object):
more_code_here
class OldStyle:
more_code_here

在这个两个类中NewType是新类,OldType是属于旧类,如果前面加上 _metaclass_=type ,那么两个类都属于新类。

构造方法

构造方法与其的方法不一样,当一个对象被创建会立即调用构造方法。创建一个python的构造方法很简答,只要把init方法,从简单的init方法,转换成魔法版本的_init_方法就可以了。

class FooBar:

def __init__(self):

self.somevar = 42

>>> f =FooBar()

>>> f.somevar

42

重写一个一般方法和特殊的构造方法

每一个类都可能拥有一个或多个超类(父类),它们从超类那里继承行为方法。

class A:

def hello(self):

print ‘hello . I am A.‘

class B(A):
 

pass

>>> a = A()

>>> b = B()

>>>a.hello()

hello . I am A.

因为B类没有hello方法,B类继承了A类,所以会调用A 类的hello方法。

在子类中增加功能功能的最基本的方式就是增加方法。但是也可以重写一些超类的方法来自定义继承的行为。如下:

class A:
def hello(self):
print "Hello,I‘m A."
class B(A):
def hello(self):
print ‘Hello,I\‘m B.‘

>>> b=B()
>>> b.hello()
Hello,I‘m B.
>>>

重写是继承机制中的一个重要内容,对一于构造方法尤其重要。看下面的例子:

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

----------------------

>>> b=Bird()
>>> b.eat()
Aaaah...
>>> b.eat()
No,thanks!
>>>

这个类中定义了鸟有吃的能力, 当它吃过一次后再次就会不饿了,通过上面的执行结果可以清晰的看到。

那么用SongBird类来继承Bird 类,并且给它添加歌唱的方法:

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
self.sound=‘Squawk!‘
def sing(self):
print self.sound

-----------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()

Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
sb.eat()
File "F:/python/myDemo/_init_.py", line 5, in eat
if self.hungry:
AttributeError: SongBird instance has no attribute ‘hungry‘
>>>

异常很清楚地说明了错误:SongBird没有hungry特性。原因是这样的:在SongBird中,构造方法被重写,但新的构造方法没有任何关于初始化hungry特性的代码。为了达到预期的效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保进行基本的初始化。

两种方法实现:

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

class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound=‘Squawk!‘
def sing(self):
print self.sound

--------------------------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No,thanks!
>>>

在SongBird类中添加了一行代码Bird.__init__(self) 。 在调用一个实例的方法时,该方法的self参数会被自动绑定到实例上(这称为绑定方法)。但如果直接调用类的方法,那么就没有实例会被绑定。这样就可以自由地提供需要的self参数(这样的方法称为未绑定方法)。

通过将当前的实例作为self参数提供给未绑定方法,SongBird就能够使用其超类构造方法的所有实现,也就是说属性hungry能被设置。

使用super函数

__metaclass__=type
class Bird:
def __init__(self):
self.hungry=True
def eat(self):
if self.hungry:
print ‘Aaaah...‘
self.hungry=False
else:
print ‘No,thanks!‘

class SongBird(Bird):
def __init__(self):
super(SongBird,self).__init__()
self.sound=‘Squawk!‘
def sing(self):
print self.sound

----------

>>> sb=SongBird()
>>> sb.sing()
Squawk!
>>> sb.eat()
Aaaah...
>>> sb.eat()
No,thanks!
>>>

基本的映射和序列规则

序列和映射是对象的集合。

__len(self)__:

返回集合中所含项目的数量。对序列来说,这就是元素的个数,对映射来说,这就是键~值对的数量

__getitem__(self,key):

返回与所给键对应的值

__setitem__(self,key,value):

按一定方法存储与key相关的value

__delitem__(self,key):

对一部分对象使用del语句时被调用,同时必须删除和元素相关的键

def checkIndex(key):
‘‘‘
所给的键是能接受的索引吗?
为了能被接受,键应该是一个非负的整数,如果它不是一个整数,会引发TypeError,如果它是负数,
则会引发IndexError(因为序列是无限长的)
‘‘‘
if not isinstance(key,(int,long)):
raise TypeError
if key <0:
raise IndexError

class ArithmeticSequence:
def __init__(self,start=0,step=1):
‘‘‘
初始化算术序列
‘‘‘
self.start=start #保存开始值
self.step=step #保存步长值
self.changed={} #没有项被修改
def __getitem__(self,key):
checkIndex(key)
try:
return self.changed[key]
except KeyError:
return self.start+key*self.step

def __setitem__(self,key,value):
checkIndex(key)
self.changed[key]=value

------------------------------

>>> s=ArithmeticSequence(1,2)
>>> s[4]
9
>>> s[4]=2
>>> s[4]
2
>>> s[5]
11
>>> s[6]
13
>>> s[‘four‘]

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
s[‘four‘]
File "F:/python/myDemo/_init_.py", line 21, in __getitem__
checkIndex(key)
File "F:/python/myDemo/_init_.py", line 8, in checkIndex
raise TypeError
TypeError
>>> s[-42]

Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
s[-42]
File "F:/python/myDemo/_init_.py", line 21, in __getitem__
checkIndex(key)
File "F:/python/myDemo/_init_.py", line 10, in checkIndex
raise IndexError
IndexError
>>>

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

class CounterList(list):
def __init__(self,*args):
super(CounterList,self).__init__(*args)
self.counter=0
def __getitem__(self,index):
self.counter+=1
return super(CounterList,self).__getitem__(index)

-------------------------

>>> cl=CounterList(range(10))
>>> cl
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> cl.reverse()
>>> cl
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del cl[3:6]
>>> cl
[9, 8, 7, 3, 2, 1, 0]
>>> cl.counter
0
>>> cl[4]+cl[2]
9
>>> cl[4]
2
>>> cl[2]
7
>>> cl.counter
4
>>>

属性

访问器是一个简单的方法,它能够使用getHeight 、setHeight 之样的名字来得到或者重绑定一些特性。如果在访问给定的特性时必须要采取一些行动,那么像这样的封装状态变量就很重要。如下:

class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height=size
def getSize(self):
return self.width,self.height

----------------

>>> r=Rectangle()
>>> r.width=10
>>> r.height=5
>>> r.getSize()
(10, 5)
>>> r.setSize((150,100))

>>> r.width
150

在上面的例子中,getSize和setSize方法一个名为size的假想特性的访问器方法,size是由width 和height构成的元组。

property函数

__metaclass__=type
class Rectangle:
def __init__(self):
self.width=0
self.height=0
def setSize(self,size):
self.width,self.height=size
def getSize(self):
return self.width,self.height
size=property(getSize,setSize)

----------------------

>>> r=Rectangle()
>>> r.width=10
>>> r.height=5
>>> r.size
(10, 5)
>>> r.size=150,100
>>> r.width
150
>>>

在这个新版的Retangle 中,property 函数创建了一个属性,其中访问器函数被用作参数(先取值,然后是赋值),这个属性命为size 。这样一来就不再需要担心是怎么实现的了,可以用同样的方式处理width、height 和size。

静态方法和类成员方法

静态方法定义没有self参数,且能够被类本身直接调用

类方法在定义时需要名为cls的类似于self的参数,类成员方法可以被类的具体对象调用。但cls参数是自动绑定到类的

__metaclass__=type
class MyClass:
def smeth():
print ‘This is a static method‘
smeth=staticmethod(smeth)

def cmeth(cls):
print ‘This is a class method of‘,cls
cmeth=classmethod(cmeth)

手动包装和替换方法的技术看起来有些单调,为此引入了一个叫装饰器的新语法,使用@操作符

__metaclass__=type
class MyClass:
@staticmethod
def smeth():
print ‘This is a static method‘

@classmethod
def cmeth(cls):
print ‘This is a class method of‘,cls

-------------------

>>> MyClass.smeth()
This is a static method
>>> MyClass.cmeth()
This is a class method of <class ‘__main__.MyClass‘>
>>>

__getattr__、__setattr__和它的朋友们

__getattr__(self,name):

当特性name被访问且对象没有相应的特性时被自动调用

__setattr__(self,name,value):

当试图给特性name赋值时被自动调用

__delattr__(self,name):

当试图删除特性name时被自动调用

class Rectangle:
def __init__(self):
self.width=0
self.height=0
def __setattr_(self,name,value):
if name==‘size‘:
self.width,self.height=value
else:
self.__dict__[name]=value
def __getattr__(self,name):
if name==‘size‘:
return self.width,self.height
else:
raise AttributeError

迭代器

本节进行迭代器的讨论。只讨论一个特殊方法---- __iter__  ,这个方法是迭代器规则的基础

迭代器规则

迭代的意思是重复做一些事很多次---就像在循环中做的那样。__iter__ 方法返回一个迭代器,所谓迭代器就是具有next方法的对象,在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用,但迭代器没有值可以返回,就会引发一个StopIteration异常。

这里是一个婓波那契数例,使用迭代器如下:

class Fibs:
def __init__(self):
self.a=0
self.b=1
def next(self):
self.a,self.b=self.b,self.a+self.b
return self.a
def __iter__(self):
return self

----------------

fibs=Fibs()

>>> for f in fibs:
if f>1000:
print f
break

1597
>>>

从迭代器得到序列

除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下,能使用迭代器替换。

>>> class TestIterator:
value=0
def next(self):
self.value +=1
if self.value >10: raise StopIteration
return self.value
def __iter__(self):
return self

>>> ti=TestIterator()
>>> list(ti)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>

生成器

创建生成器

def flatten(nested):
for sublist in nested:
for element in sublist:
yield element

>>> nested=[[1,2],[3,4],[5]]
>>> for num in flatten(nested):
print num

1
2
3
4
5
>>> list(flatten(nested))
[1, 2, 3, 4, 5]
>>>

递归生成器

上面创建的生成器只能处理两层嵌套,为了处理嵌套使用了两个for循环,如果要处理任意层的嵌套呢?例如,可以每层嵌套需要增加一个for循环,但不知道有几层嵌套,所以必须把解决方案变得更灵活,现在可以用递归来解决

def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

-------------------

>>> list(flatten([[[1],2],3,4,[5,[6,7]],8]))
[1, 2, 3, 4, 5, 6, 7, 8]
>>>

当flatten被调用时有两种情况:基本情况和需要递归的情况

在基本的情况中,函数被告知展开一个元素,这种情部下,for循环会引发一个TypeError 异常,生成会产生一个元素。

如果展开的是一个列表,那么就需要特殊情况处理。程序必须遍历所有的子列表,并对它们调用flatten。

上面的做法有一个问题:如果aa 是一个类似于字符串的对象(字符串、Unicode、UserString等),那么它就是一个序列,不会引发TypeError,但是你不想对这样的对象进行迭代。

为了处理这种情况,则必须在生成器的开始处添加一个检查语句。试着将传入的对象和一个字符串拼接,看看会不会出现TypeError,这是检查一个对象是不是类似于字符串最简单快速的方法。

def flatten(nested):
try:
try:nested+‘‘
except TypeError:pass
else: raise TypeError
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

--------------------

>>> list(flatten([‘foo‘,[‘bar‘,[‘baz‘]]]))
[‘foo‘, ‘bar‘, ‘baz‘]
>>>

如果nested+’’ 引发了一个TypError ,它就会被忽略。如果没有引发TypeError,那么内层try语句就会引发一个它自己的TypeError异常。

生成器方法

def repeater(value):
while True:
new=(yield value)
if new is not None: value=new

---------------------

>>> r=repeater(42)
>>> r.next()
42
>>> r.send(‘Hello,world!‘)
‘Hello,world!‘
>>>

生成器的另两个方法:

throw方法(使用异常类型调用,还有可选的值以及回溯对象)用于在生成器内引发一个异常(在yield表达式中)

close 方法(调用时不用参数)用于停止生成器。

时间: 2024-10-01 16:46:24

python学习笔记(方法、属性、迭代器)的相关文章

Python学习笔记四(迭代器、生成器、内置函数)

一.迭代器 1.迭代器定义 迭代是一个重复的过程,每次重复一次迭代,并且每次迭代的结果都是下一次迭代的初始值. l = ["aaa","bbb","ccc"] count = 0 while count< len(l): #每次重复完成后count都是下一次的初始值 print(l[count]) count+=1 需要迭代器的原因:对于序列类型str.list.tuple可以依赖索引迭代取值,对于dict.set.文件需要提供不依赖索引取

python学习笔记&#9758;方法

方法: 类的功能有一个更通俗的名字叫方法.在python中,方法定义在类定义中,但只能被实例调用.也就是说,调用一个方法的最终途径必须是这样的:(1)定义类(和方法);(2)创建一个实例:(3)最后一步,用这个实例调用方法. 例如" class mydatawithmethod(object): #定义类 def printFoo: #定义方法 print 'you invoked printFoo()!'

Python学习笔记8(迭代器、生成器、装饰器)

1.列表生成式 要想学习生成器和迭代器,首先得了解另外一个概念,列表生成式. 想要生成一个0~9的列表的时候,首先想到的就是range(0,10) >>>a = range(0,10) >>>print(a) #3.0输出结果 range(0,10) #2.0输出结果 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 在3.0的版本呢当中range只是用来生成一个迭代器了,但是在2.0的版本里可以使用range来快速生成list. 但是想要生成一个[1*1,

Python学习笔记7-高级迭代器

将任何字符串作为python表达式求值: eval()方法: eval(source[, globals[, locals]]) -> value Evaluate the source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals mus

python学习笔记之函数总结--高阶函数以及装饰器

python学习笔记之函数总结--高阶函数以及装饰器 Python特点: 1.不是纯函数式编程(允许变量存在): 2.支持高阶函数(可以传入函数作为变量): 3.支持闭包(可以返回函数): 4.有限度的支持匿名函数: 高阶函数: 1.变量可以指向函数: 2.函数的参数可以接收变量: 3.一个函数可以接收另一个函数作为参数: 下面我将示例一些函数的写法以及使用,并说明python中函数的特性: 1.基本的高阶函数示例: #!/usr/bin/env python def func():      

python &nbsp; 学习笔记 (核心)

python    学习笔记 (核心) Python解释器从头到尾一行接一行执行脚本 # -*- coding: UTF-8 -*-    //字符编码 不区分单引号和双引号,x='hello',x[0],x[-1]指最后一个字符,x[2:4]取子串, '''hello''' #hello三引号会保留文本输入时的换行符制表符等不需要转义,用于多行原样输入保存 'hello'+'world' #字符串拼接,'hello'*2 #字符串重复 help(fun) #帮助,help(module.met

OpenCV之Python学习笔记

OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书<OpenCV Computer Vision with Python>,于是就看一遍,顺便把自己掌握的东西整合一下,写成学习笔记了.更需要的朋友参考. 阅读须知: 本文不是纯粹的译文,只是比较贴近原文的笔记:         请设法购买到出版社出版的书,支持正版. 从书名就能看出来本书是介绍在Pytho

Python学习笔记--未经排版

Python 学习笔记 Python中如何做到Print() 不换行 答:Print("输出内容",end='不换行的分隔内容'),其中end=后面为2个单引号 注:在Python 2.x中,Print "输出内容", 即在输出内容后加一逗号 Python中 is 和 == 的区别 答:Python中的对象包含三要素:id.type.value 其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值 is判断的是a对象是否就是b对象,是通过id来

Python学习笔记_Python对象

Python学习笔记_Python对象 Python对象 标准类型 其他内建类型 类型对象和type类型对象 Python的Null对象None 标准类型操作符 对象值的比较 对象身份比较 布尔类型 标准类型的内建函数 typeObj cmpobj1 obj2 strobj reprobj typeobj isinstanceobj 标准类型的分类 存储模型 更新模型 访问模型 不支持的类型 Python学习笔记_Python对象 首先来理解一个通俗的含义,什么是对象?其实对象无论在什么语言里面

python 学习笔记 14 -- 常用的时间模块之datetime

书接上文,前面我们讲到<常用的时间模块之time>,这次我们学习datetime -- 日期和时间值管理模块 使用apihelper 查看datetime 模块,我们可以看到简单的几项: date       ---  日期对象,结构为date(year, month, day) time       ---  时间值对象,结构为 time([hour[, minute[, second[, microsecond[, tzinfo]]]]]).时间对象所有的参数都是可选的.tzinfo 可以