核心编程
1.复习一下dir()和__dict__.
>>> class C(object):
pass
>>> c=C()
>>> dir(C)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> dir(c)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> c.__dict__
{}
>>> c.bar='rao'
>>> dir(c)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'bar']
>>> dir(C)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> c.__dict__
{'bar': 'rao'}
可以看出实例的dir(c)包括类的dir(C)加上实例自己的数据属性。
而实例的__dict__则仅仅是他的数据属性,(实例也没有方法属性)
内建类型中可以用dir(),不可以用__dict__
2.
实例仅有两个特殊属性(见表13.2)。对于任意对象I:
表13.2 特殊实例属性
I.__class__ 实例化I 的类
I.__dict__ I 的属性
从标准类型派生(标准类型分两种:可变类型,不可变类型)
可变类型(list的值改变了但是id没有变化,id(list)一直不变化):list,dict
不可变类型:string,int,tuple
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
#return super(RoundFloat,cls).__new__(cls,round(val,2))
tips:所有的__new()__方法都是类方法,我们要显式传入类作为第一个参数(cls),这类似于常见的方法如__init__()中需要的self
类、实例和其他对象的内建函数:
issubclass(sub,sup)
isinstance(obj1,obj2)
hasattr(), getattr(),setattr(), delattr()有两个参数,第一个是正在处理的对象,第二个就是属性名,是属性的字符串名字
对于每个定义的类都有一个名为__mro__的属性,她是一个元组,按照他们被搜索时的顺序,列出了被搜索的类。super()是用来解决多重继承的问
题的,而且只能作用于新式类上。super()用来调用父类非绑定的方法
vars()
vars()内建函数与dir()相似,只是给定的对象参数都必须有一个__dict__属性。vars()返回一
个字典,它包含了对象存储于其__dict__中的属性(键)及值。如果提供的对象没有这样一个属性,
则会引发一个TypeError 异常。如果没有提供对象作为vars()的一个参数,它将显示一个包含本地
名字空间的属性(键)及其值的字典,也就是,locals()。我们来看一下例子,使用类实例调用vars():
用特殊方法定制类:
class Time60(object):
def __init__(self,hr,min):
self.hr=hr
self.min=min
def __str__(self):
return '%d:%d'%(self.hr,self.min)
__repr__=__str__
def __add__(self,other):
hour=self.hr+other.hr
mins=self.min+other.min
if mins>60:
return self.__class__(hour+1,mins-60)
else:
return self.__class__(hour,mins)
def __sub__(self,other):
return self.__class__(abs(self.hr-other.hr),abs(self.min-other.min))
mon=Time60(10,30)
tue=Time60(11,55)
print mon-tue
随机序列迭代器:
要想自定义的类的实例可以迭代必须加载iter方法
def __iter__(self):
return self
from random import choice
class RandSeq(object):
def __init__(self,seq):
self.data=seq
def __iter__(self):
return self
def next(self):
return choice(self.data)
def __str__(self):
return str(self.data)
rand=RandSeq([1,2,3,4,5])
for eachItem in rand:
print eachItem
class AnyIter(object):
def __init__(self,data,safe=False):
self.safe=safe
self.iter=iter(data)
def __iter__(self):
return self
def next(self,howmany):
retval=[]
for eachItem in range(howmany):
try:
retval.append(self.iter.next())
except StopIteration:
if self.safe:
break
else:
raise
return retval
a=AnyIter(range(10))
i=iter(a)
for j in range(1,5):
print j,':',a.next(j)
,
question:这个例子中我不明白为什么要设置i=iter(a),然后调用print j,':',i.next(j),我发现直接调用我写的 print j,':',a.next(j)
也是生成同样的结果哎。。。
*多类型定制(NumStr)
class NumStr(object):
def __init__(self,num=0,str=''):
self.num=num
self.str=str
def __str__(self):
return "[%d::%r]"%(self.num,self.str)
__repr__ = __str__
def __add__(self,other):
return self.__class__(self.num+other.num,self.str+other.str)
def __mul__(self,num):
if isinstance(num,int):
return self.__class__(self.num*num,self.str*num)
else:
raise TypeError,'Illegal argument type for built-in operation'
def __nonzero__(self):
return self.num or len(self.str)
def __norm_cval(self,cmpres):
return cmp(cmpres,0)
def __cmp__(self,other):
return self.__norm_cval(cmp(self.num,other.num))+self.__norm_cval(cmp(self.str,other.str))
a=NumStr(2,'rao')
b=NumStr(3,'yuan')
print a>b
包装的定义:
授权是包装的一个特性,包装一个类型通常是对已经存在的类型的一些定制,实现授权的关键点就是覆盖__getattr__()方法,,在代码中包含一个
对getattr()内建函数的调用。特别地,调用getattr()以得到默认对象属性(数据属性或者方法)并返回它以便访问或调用。特殊方法__getattr__
()的工作方式是,当搜索一个属性时,任何局部对象首先被找到(定制的对象)。如果搜索失败了,则__getattr__()会被调用,然后调用getattr()
得到一个对象的默认行为。
下面是包装类的例子:
包装一般都是针对类型的,如果是自定义的类只需要派生就可以了。
_slots__类属性:
字典位于实例的“心脏”。__dict__属性跟踪所有实例属性。举例来说,你有一个实例inst.它有一个属性foo,那使用inst.foo 来访问它与使用
inst.__dict__['foo']来访问是一致的。
字典暂用内存空间比较大所以可以用_slots__属性来替代__dict__。__slots__是一个类变量,由一序列型对象组成,由所有合法标识构成的实例属
性的集合来表示。它可以是一个列表,元组或可迭代对象。也可以是标识实例能拥有的唯一的属性的简单字符串。任何试图创建一个其名不在
__slots__中的名字的实例属性,这种特性的主要目的是节约内存。其副作用是某种类型的"安全",它能防止用户随心所欲的动态增加实例属性。带
__slots__属性的类定义不会存在__dict__了(除非你在__slots__中增加'__dict__'元素)
特殊方法__getattribute__():
Python 类有一个名为__getattr__()的特殊方法,它仅当属性不能在实例的__dict__或它的类(类的__dict__),或者祖先类(其__dict__)中找到
时,才被调用。我们曾在实现授权中看到过使用__getattr__()。
描述符:
描述符是Python 新式类中的关键点之一
如你的对象有代理,并且这个代理有一个“get”属性(实际写法为__get__),当这个代理被调用时,你就可以访问这个对象了。
__get__(),__set__(),__delete__()特殊方法
class Person(object):
def addProperty(self, attribute):
# create local setter and getter with a particular attribute name
getter = lambda self: self._getProperty(attribute)
setter = lambda self, value: self._setProperty(attribute, value)
# construct property attribute and add it to the class
setattr(self.__class__, attribute, property(fget=getter, \
fset=setter, \
doc="Auto-generated method"))
def _setProperty(self, attribute, value):
print "Setting: %s = %s" %(attribute, value)
setattr(self, '_' + attribute, value.title())
def _getProperty(self, attribute):
print "Getting: %s" %attribute
return getattr(self, '_' + attribute)
关于描述符http://www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/讲的很通熟易懂,后续再看