stackoverflow上面的相关讨论
http://stackoverflow.com/questions/2923579/python-class-attribute
http://stackoverflow.com/questions/1944625/what-is-the-relationship-between-getattr-and-getattr
1. 类属性
为在类定义时直接指定的属性(不是在__init__方法中)
class Test:
class_attribute1="attr-value"
在__init__方法中添加的属性, 在其他位置添加也是可以的, 实际是通过setattr内置函数(调用__setattr__)完成, 另外也可以直接修改__dict__属性手动添加
t=Test()
setattr(t,attr_name,attr_value) #等价于 t.attr_name=attr_value
t.__dict__[attr_name]=attr_value
class Test:
def __setattr__(self,name,value):
if name=="key":
self.__dict__[name]=value
instance.__class__.__dict__中查找, 也就是在类属性中查找, 如果找到, 返回对应值, 否则产生attributeError异常
class Test:
derived_val=1
def __init__(self):
pass
t1=Test()
print "t1.derived_val=",t1.derived_val #t1.derived_val= 1
print "Test.derived_val=",Test.derived_val #Test.derived_val=1
print "t1.__dict__=",t1.__dict__ #{}
print "Test.__dict__=",Test.__dict__ #Test.__dict__= {'derived_val': 1,...}
print "t1.__class__.__dict__=",t1.__class__.__dict__ #Test.__dict__= {'derived_val': 1,...}
Test.derived_val+=1 #类属性derived_val+1=2
t1.derived_val+=1 #t1并没有属性derived_val, 根据访问顺序, 将访问类属性derived_val, 结果为 t1.derived_val=Test.derived_val+1=3
print "t1.derived_val=",t1.derived_val #t1.derived_val=3
print "Test.derived_val=",Test.derived_val #Test.derived_val=2
print "t1.__dict__=",t1.__dict__ #t1.__dict__={'derived_val':3}
print "Test.__dict__=",Test.__dict__ #Test.__dict__= {'derived_val': 2, ...}
print "t1.__class__.__dict__=",t1.__class__.__dict__ #Test.__dict__= {'derived_val': 2, ...}
5. __getattr__和__getattribute__的区别
另请参考: http://stackoverflow.com/questions/4295678/understanding-the-difference-between-getattr-and-getattribute
如果在类中定义__getattr__方法, 该方法会在搜寻属性失败时调用, lookup attribute成功不会调用该方法
class A(object):
def __getattr__(self, name):
return "I pretend I have an attribute called '%s'" % name
a = A()
print a.foo # there's no attribute 'foo', but no AttributeError currs, prints "I pretend I have an attribute called 'foo'"
class TestClass(object):
def __init__(self):
pass
def __getattr__(self,attr_name):
print "attribute '%s' is not defined!(in function TestClass.__getattr__)" %attr_name
return "not defined!"
def __getattribute__(self,attr_name):
print "in function '__getattribute__'"
attr_val=super(TestClass,self).__getattribute__(attr_name)
return attr_val
#TestClass类定义了两个方法__getattr__ 和__getattribute__方法, 下面几个例子说明两者区别
tc=TestClass() #tc!
tc.a #a
tc.a=1 #add attribute 'a' to tc
tc.a #b
tc.__getattr__('a') #c
tc.__getattribute__('a') #d
a. 访问属性'a',得到结果为:
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
首先调用了'__getattribute__'方法,因为该方法在属性访问时一定会被调用
接着发现属性a尚未定义, 应当抛出AttributeError异常, 但是发现TestClass中定义了'__getattr__'方法, 该方法
类似AttributeError的异常处理方法, 所以python内部机制调用'__getattr__'方法
b. 这次访问属性'a', 得到结果为:
in function '__getattribute__'
1
因为'a'已经定义, 故而不再调用'__getattr__'方法, 但'__getattribute__'仍然执行
c. 显示的调用方法'__getattr__', 得到结果:
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
'__getattr__'同样是'tc'的属性, 同样也会调用'__getattribute__'
注意, 属性'a'并不是不存在, 只不过'__getattr__'方法这样输出而已!
d. 调用'_getattribute__', 得到结果:
in function '__getattribute__'
in function '__getattribute__'
1
该方法只需要了解'__getattribute__'本身也是'tc'的属性, 就一目了然了
************************************************************************************************************************************
6. __getattribute__方法的无限循环
class TestClass(object):
def __init__(self):
pass
def __getattribute__(self,attr_name):
print "in function '__getattribute__'"
attr_val=self.__dict__[attr_name]
return attr_val
7. 危险的__getattribute__的使用时机
使用'__getattribute__'存在无限循环的风险, 但是如果需要在一个较低层次控制属性的访问, 可以使用它
下面是一个例子
import random
#I think this is a good example to show the power you can get from overriding '__getattribute__'
class TestClass(object):
def __init__(self,stu1,*args): #at least one student!
self.students=[stu1]
self.students.extend(args)
def __getattribute__(self,attr_name):
if attr_name=="random_student":
students=super(TestClass,self).__getattribute__("students")
pos=random.randint(0,len(students)-1)
return students[pos]
else:
return super(TestClass,self).__getattribute__(attr_name)