Python学习总结笔记(2)--类扩展小结
2016-11-16 19:46
429 查看
Python作为动态语言,灵活性之一就是支持类的动态扩展,可以动态给类对象或者实例添加属性或者方法。这一特性给Python语言带来了很大的灵活性。
上面定义了一个Person类,含有一个name的属性,但是我们可能需要给他添加Age、Sex等新的属性或者函数怎么办呢?可以这么来做:
运行结果:
动态添加了一个属性age。这是在实例中添加的,对其他实例是无效的,比如:
运行结果:
提示b中没有这样的属性。要想对类所有实例均有效,可以直接对类本身添加动态属性:
同样的,也可以动态添加方法(函数)。需要导入模块types. MethodType,如下:
类似的,如果要求对所有类的实例有效,就需要在类本身的对象上进行动态扩展:
需要注意一点的是,动态扩展不要涉及“私有变量”,比如:
运行结果:
提示找不到属性__name,那么读取公开的属性name呢:
运行结果:
虽然没有报错,但是只是打印出了获取的属性的信息,并没有获取其真实的值。
同样的给“私有变量”赋值也是无效的:
打印出来的name仍然是kk。所以采用动态扩展方式时,不要对类中原有的属性和方法进行操作(当然静态变量除外)。
如果试图添加其他的属性和方法,将会报错:
设置断点调试:
前面几个扩展一切正常,断点前进即报错:
(1) len
Python中很多对象都可以用len()来计算对象的“长度”,其实是在类里面实现了函数len。比如:
需要注意的是len函数的返回值必须是整数,否则将会报错:
运行结果:
(2)str
在类中实现str函数,就可以执行str()函数:
运行结果:
(3)iter
如果类的对象希望具有迭代的效果(for…in…),那么就需要实现iter,该方法返回一个迭代对象,结合next函数,可以循环取值。用著名的Fibonacci数列的实现为例:
(4)getitem
如果先实现索引访问,需要实现getitem:
上面是利用索引来访问,如果要支持切片功能,可以这样来实现:
当然上面的切片实现是单步的,如果step不为1,就得修正代码实现逻辑了。这里就不再赘述这一过程,只做下getitem的使用总结。
0x01 属性和方法扩展
举个例子:class Person(object): def __init__(self,name): self.__name=name @property def name(self): return self.__name
上面定义了一个Person类,含有一个name的属性,但是我们可能需要给他添加Age、Sex等新的属性或者函数怎么办呢?可以这么来做:
a=Person('Andy') #添加 a.age=18 print dir(a)
运行结果:
['_Person__name', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name'] Process finished with exit code 0
动态添加了一个属性age。这是在实例中添加的,对其他实例是无效的,比如:
b=Person('kk') print b.age
运行结果:
AttributeError: 'Person' object has no attribute 'age'
提示b中没有这样的属性。要想对类所有实例均有效,可以直接对类本身添加动态属性:
Person.age=18
b=Person('kk') print b.age
同样的,也可以动态添加方法(函数)。需要导入模块types. MethodType,如下:
from types import MethodType def eat(self): print 'eat' b=Person('kk') b.eat=MethodType(eat,b) b.eat()
类似的,如果要求对所有类的实例有效,就需要在类本身的对象上进行动态扩展:
Person.eat=MethodType(eat,Person) b=Person('kk') b.eat()
需要注意一点的是,动态扩展不要涉及“私有变量”,比如:
def getName(self): return self.__name Person.getName=MethodType(getName,Person) b=Person('kk') print b.getName()
运行结果:
AttributeError: type object 'Person' has no attribute '__name'
提示找不到属性__name,那么读取公开的属性name呢:
def getName(self): return self.name Person.getName=MethodType(getName,Person) b=Person('kk') name=b.getName() print name
运行结果:
<property object at 0x0128D540>
虽然没有报错,但是只是打印出了获取的属性的信息,并没有获取其真实的值。
同样的给“私有变量”赋值也是无效的:
def setName(self,name): self.__name=name Person.setName=MethodType(setName,Person) b=Person('kk') b.setName('kkb7') print b.name
打印出来的name仍然是kk。所以采用动态扩展方式时,不要对类中原有的属性和方法进行操作(当然静态变量除外)。
0x02 限制扩展
上面讲了类的扩展,如果我们需要显示随意扩展怎么办呢?比如,只能给Person扩展age和height。可以通过顶一个特殊的slots来实现。class Person(object): def __init__(self,name): self.__name=name __slots__=('__name','name','age','height','getAge') @property def name(self): return self.__name
如果试图添加其他的属性和方法,将会报错:
def getAge(self): return 18 def getHeight(self): return 182 b=Person('kk') #正常 b.age=18 b.height=182 b.getAge=MethodType(getAge,b) #异常 b.width=130 b.getHeight=MethodType(getHeight,b)
设置断点调试:
前面几个扩展一切正常,断点前进即报错:
AttributeError: 'Person' object has no attribute 'width'
0x03 类扩展
上面讲了slots可以用来限制类的属性和方法定义。类似*这样的变量在Python中非常特殊。还有一些变量可以用来扩展类的功能。下面就讲几个常见的变量(1) len
Python中很多对象都可以用len()来计算对象的“长度”,其实是在类里面实现了函数len。比如:
class Person(object): def __init__(self,name): self.__name=name __slots__=('__name','name','age','height','getAge') @property def name(self): return self.__name #定义__len__ def __len__(self): return len(self.__name) b=Person('kk') print 'b\'length is:',len(b) c=Person('kikay') print 'c\'length is:',len(c)
需要注意的是len函数的返回值必须是整数,否则将会报错:
class Person(object): def __init__(self,name): self.__name=name __slots__=('__name','name','age','height','getAge') @property def name(self): return self.__name #定义__len__ def __len__(self): return 'error' b=Person('kk') print 'b\'length is:',len(b)
运行结果:
TypeError: an integer is required
(2)str
在类中实现str函数,就可以执行str()函数:
class Person(object): def __init__(self,name): self.__name=name __slots__=('__name','name','age','height','getAge') @property def name(self): return self.__name #定义__len__ def __len__(self): return len(self.__name) #定义__str__ def __str__(self): return 'Person object (name:%s)'%self.__name b=Person('kk') print str(b)
运行结果:
Person object (name:kk)
(3)iter
如果类的对象希望具有迭代的效果(for…in…),那么就需要实现iter,该方法返回一个迭代对象,结合next函数,可以循环取值。用著名的Fibonacci数列的实现为例:
class Fibonacci(object): def __init__(self): self.__v1,self.__v2=0,1 def __iter__(self): return self #限制运行的值上限 __MaxVaue__=1000 def next(self): self.__v1,self.__v2=self.__v2,self.__v2+self.__v1 if self.__v1>=self.__MaxVaue__: #停止迭代 raise StopIteration() return self.__v1 f=Fibonacci() #迭代 for i in f: print i
(4)getitem
如果先实现索引访问,需要实现getitem:
class Fibonacci(object): def __init__(self): self.__v1,self.__v2=0,1 def __iter__(self): return self #限制运行的值上限 __MaxVaue__=1000 def next(self): self.__v1,self.__v2=self.__v2,self.__v2+self.__v1 if self.__v1>=self.__MaxVaue__: #停止迭代 raise StopIteration() return self.__v1 def __getitem__(self, item): if isinstance(item,int): temp1,temp2=1,1 for i in range(item): temp1,temp2=temp2,temp1+temp2 return temp1 else: raise TypeError('item must be integer') f=Fibonacci() print f[3]
上面是利用索引来访问,如果要支持切片功能,可以这样来实现:
class Fibonacci(object): def __init__(self): self.__v1,self.__v2=0,1 def __iter__(self): return self #限制运行的值上限 __MaxVaue__=1000 def next(self): self.__v1,self.__v2=self.__v2,self.__v2+self.__v1 if self.__v1>=self.__MaxVaue__: #停止迭代 raise StopIteration() return self.__v1 def __getitem__(self, item): if isinstance(item,int): temp1,temp2=1,1 for i in range(item): temp1,temp2=temp2,temp1+temp2 return temp1 elif isinstance(item,slice): L=[] temp1,temp2=1,1 start=item.start stop=item.stop if start is None: start=0 for i in range(start,stop): if i>=start: L.append(temp1) temp1,temp2=temp2,temp1+temp2 return L else: raise TypeError('item must be integer') f=Fibonacci() print f[3] print f[2:8]
当然上面的切片实现是单步的,如果step不为1,就得修正代码实现逻辑了。这里就不再赘述这一过程,只做下getitem的使用总结。
相关文章推荐
- python学习笔记:datetime使用小结
- python学习笔记18-重点和忘记知识点总结
- Python学习笔记--Python字符串连接方法总结
- php学习笔记4--php中GD2扩展库的学习总结
- Python学习笔记总结(三)类
- python学习笔记11-异常总结
- WCF学习笔记三:使用自定义行为扩展WCF总结
- Python学习笔记总结(四)异常处理
- python 学习笔记-山寨携程(列表,字符串,字典和流程控制总结)
- OSGi.NET 学习笔记 [模块可扩展支持][小结]
- python基础教程_学习笔记8:序列_练习与总结_1
- python 学习笔记 7 -- Python关键字总结
- Python学习笔记总结(一)对象和流程语句总结
- Python学习笔记总结(二):函数和模块
- Python学习笔记之数据类型总结
- python 学习笔记 7 -- Python关键字总结
- [简明python教程]学习笔记之总结篇
- 【Python爬虫学习笔记(1)】urllib2库相关知识点总结
- Python学习笔记总结(二)函数和模块