python-setattr,getattr,getattribute
2014-10-06 14:55
423 查看
集合了网上几个帖子,做了测试,整理到一起,供大家参考。
原文地址:
http://www.2cto.com/kf/201209/154470.html
http://blog.sina.com.cn/s/blog_4be6d8870100dtnw.html
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820042500060e2921830a4adf94fb31bcea8d6f5c000
1.关于getattr( 如果在类中定义__getattr__方法, 该方法会在搜寻属性失败时调用, lookup attribute成功不会调用该方法)
不重写getattr
>>> class A():
pass
>>> a=A()
>>> a.foo
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
a.foo
AttributeError: A instance has no attribute 'foo'
重写getattr
>>> class A(object):
def __getattr__(self, name):
return "I pretend I have an attribute called '%s'"
4000
% name
>>> a=A()
>>> a.foo
"I pretend I have an attribute called 'foo'"
2.getattr和getattribute
2.1
>>> 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
>>> t=TestClass()
>>> t.a
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
首先调用了'__getattribute__'方法,因为该方法在属性访问时一定会被调用
接着发现属性a尚未定义, 应当抛出AttributeError异常, 但是发现TestClass中定义了'__getattr__'方法, 该方法类似AttributeError的异常处理方法,
所以python内部机制调用'__getattr__'方法
2.2
>>> t.a=1
>>>
>>> t.a
in function '__getattribute__'
1
因为'a'已经定义, 故而不再调用'__getattr__'方法, 但'__getattribute__'仍然执行
2.3
>>> t.__getattr__('a')
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
'__getattr__'同样是'tc'的属性, 同样也会调用'__getattribute__'
注意, 属性'a'并不是不存在, 只不过'__getattr__'方法这样输出而已!
2.4
>>> t.__getattribute__('a')
in function '__getattribute__'
in function '__getattribute__'
1
该方法只需要了解'__getattribute__'本身也是'tc'的属性,
就一目了然了
2.5
__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
>>> t=TestClass()
>>> t.a
in function '__getattribute__'
in function '__getattribute__'
in function '__getattribute__'
in function '__getattribute__'
.............................
.............................
根据5测试,
我们知道在访问self.__dict__时, 会调用'__getattribute__', 这样就出现了循环嵌套调用
因此显然不能够在'__getattribute__'方法中调用self的任何属性方法, 那么既然连'__dict__'都不能够访问, 该怎样得到attr_name对应的值呢?
解决方法是使用super函数显示调用父类的'__getattribute__'方法, 这里一个问题: object的__getattribute__是如何实现的?
2.6
使用'__getattribute__'存在无限循环的风险,
但是如果需要在一个较低层次控制属性的访问, 可以使用它
>>>
import random
>>> 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)
>>> t=TestClass('barry',25)
>>> t.students
['barry', 25]
>>> t.__dict__
{'students': ['barry', 25]}
>>>
>>> t.attr_name
Traceback (most recent call last):
File "<pyshell#103>", line 1, in <module>
t.attr_name
File "<pyshell#95>", line 12, in __getattribute__
return super(TestClass,self).__getattribute__(attr_name)
AttributeError: 'TestClass' object has no attribute 'attr_name'
>>> t.random_student
'barry'
该例子中,
使用'__getattribute__'方法添加了一个TestClass本不存在的属性'random_student'
通过该属性, 可以随机的访问students中的某一个student
3.
类属性
为在类定义时直接指定的属性(不是在__init__方法中)
class Test:
class_attribute1="attr-value"
实例属性
>>> class test():
pass
>>> t=test()
>>> setattr(t,name,'barry')
Traceback (most recent call last):
File "<pyshell#112>", line 1, in <module>
setattr(t,name,'barry')
NameError: name 'name' is not defined
>>> setattr(t,'name','barry')
>>> t.__dict__
{'name': 'barry'}
>>> t.name
'barry'
>>> t.age=25
>>> setattr(t,num,2012)
Traceback (most recent call last):
File "<pyshell#120>", line 1, in <module>
setattr(t,num,2012)
NameError: name 'num' is not defined
属性的访问顺序
"instance.attr_name"访问实例属性时, 首先在instance.__dict__中查找, 如果找到返回对应值,否则在
instance.__class__.__dict__中查找, 也就是在类属性中查找, 如果找到, 返回对应值, 否则产生attributeError异常
>>> class test():
classdata=1
pass
>>> t=test()
>>> t.name='barry'
>>> t.age=25
>>> t.__dict__
{'age': 25, 'name': 'barry'}
>>> test.__dict__
{'classdata': 1, '__module__': '__main__', '__doc__': None}
>>>
>>> t.__class__dict__
Traceback (most recent call last):
File "<pyshell#140>", line 1, in <module>
t.__class__dict__
AttributeError: test instance has no attribute '__class__dict__'
>>> t.__class__.__dict__ ###就是test.__dict__
{'classdata': 1, '__module__': '__main__', '__doc__': None}
>>> t.classdata #实例没有classdata,就去类属性中去找
1
>>> test.classdata
1
>>> test.classdata+=1 #类属性加1
>>> test.classdata
2
>>> t.classdata #实例没有classdata,就去类属性中去找,已经加1,就变成了2
2
4.setattr
通过重写__setattr__控制属性的添加
该方法在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
>>> t=Test()
>>> t.key=25
>>> t.name='barry' #只有key属性能添加
>>> t.__dict__ #只有key属性能添加,所以只有key属性
{'key': 25}
5.重写__call__方法
作用:实现达到()调用的效果
>>> class test():
def __call__(self,key):
return self.__dict__[key]
>>> t=test()
>>> t.name='barry'
>>> t
<__main__.test instance at 0x01CD6940>
>>> t.name
'barry'
>>> t('name')
'barry'
6.
_变量名
有些时候,你会看到以一个下划线开头的实例变量名,比如
__变量名
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线
__变量名__
在Python中,变量名类似
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问
但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把
总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。
原文地址:
http://www.2cto.com/kf/201209/154470.html
http://blog.sina.com.cn/s/blog_4be6d8870100dtnw.html
http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820042500060e2921830a4adf94fb31bcea8d6f5c000
1.关于getattr( 如果在类中定义__getattr__方法, 该方法会在搜寻属性失败时调用, lookup attribute成功不会调用该方法)
不重写getattr
>>> class A():
pass
>>> a=A()
>>> a.foo
Traceback (most recent call last):
File "<pyshell#32>", line 1, in <module>
a.foo
AttributeError: A instance has no attribute 'foo'
重写getattr
>>> class A(object):
def __getattr__(self, name):
return "I pretend I have an attribute called '%s'"
4000
% name
>>> a=A()
>>> a.foo
"I pretend I have an attribute called 'foo'"
2.getattr和getattribute
2.1
>>> 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
>>> t=TestClass()
>>> t.a
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
首先调用了'__getattribute__'方法,因为该方法在属性访问时一定会被调用
接着发现属性a尚未定义, 应当抛出AttributeError异常, 但是发现TestClass中定义了'__getattr__'方法, 该方法类似AttributeError的异常处理方法,
所以python内部机制调用'__getattr__'方法
2.2
>>> t.a=1
>>>
>>> t.a
in function '__getattribute__'
1
因为'a'已经定义, 故而不再调用'__getattr__'方法, 但'__getattribute__'仍然执行
2.3
>>> t.__getattr__('a')
in function '__getattribute__'
attribute 'a' is not defined!(in function TestClass.__getattr__)
'not defined!'
'__getattr__'同样是'tc'的属性, 同样也会调用'__getattribute__'
注意, 属性'a'并不是不存在, 只不过'__getattr__'方法这样输出而已!
2.4
>>> t.__getattribute__('a')
in function '__getattribute__'
in function '__getattribute__'
1
该方法只需要了解'__getattribute__'本身也是'tc'的属性,
就一目了然了
2.5
__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
>>> t=TestClass()
>>> t.a
in function '__getattribute__'
in function '__getattribute__'
in function '__getattribute__'
in function '__getattribute__'
.............................
.............................
根据5测试,
我们知道在访问self.__dict__时, 会调用'__getattribute__', 这样就出现了循环嵌套调用
因此显然不能够在'__getattribute__'方法中调用self的任何属性方法, 那么既然连'__dict__'都不能够访问, 该怎样得到attr_name对应的值呢?
解决方法是使用super函数显示调用父类的'__getattribute__'方法, 这里一个问题: object的__getattribute__是如何实现的?
2.6
使用'__getattribute__'存在无限循环的风险,
但是如果需要在一个较低层次控制属性的访问, 可以使用它
>>>
import random
>>> 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)
>>> t=TestClass('barry',25)
>>> t.students
['barry', 25]
>>> t.__dict__
{'students': ['barry', 25]}
>>>
>>> t.attr_name
Traceback (most recent call last):
File "<pyshell#103>", line 1, in <module>
t.attr_name
File "<pyshell#95>", line 12, in __getattribute__
return super(TestClass,self).__getattribute__(attr_name)
AttributeError: 'TestClass' object has no attribute 'attr_name'
>>> t.random_student
'barry'
该例子中,
使用'__getattribute__'方法添加了一个TestClass本不存在的属性'random_student'
通过该属性, 可以随机的访问students中的某一个student
3.
类属性
为在类定义时直接指定的属性(不是在__init__方法中)
class Test:
class_attribute1="attr-value"
实例属性
>>> class test():
pass
>>> t=test()
>>> setattr(t,name,'barry')
Traceback (most recent call last):
File "<pyshell#112>", line 1, in <module>
setattr(t,name,'barry')
NameError: name 'name' is not defined
>>> setattr(t,'name','barry')
>>> t.__dict__
{'name': 'barry'}
>>> t.name
'barry'
>>> t.age=25
>>> setattr(t,num,2012)
Traceback (most recent call last):
File "<pyshell#120>", line 1, in <module>
setattr(t,num,2012)
NameError: name 'num' is not defined
属性的访问顺序
"instance.attr_name"访问实例属性时, 首先在instance.__dict__中查找, 如果找到返回对应值,否则在
instance.__class__.__dict__中查找, 也就是在类属性中查找, 如果找到, 返回对应值, 否则产生attributeError异常
>>> class test():
classdata=1
pass
>>> t=test()
>>> t.name='barry'
>>> t.age=25
>>> t.__dict__
{'age': 25, 'name': 'barry'}
>>> test.__dict__
{'classdata': 1, '__module__': '__main__', '__doc__': None}
>>>
>>> t.__class__dict__
Traceback (most recent call last):
File "<pyshell#140>", line 1, in <module>
t.__class__dict__
AttributeError: test instance has no attribute '__class__dict__'
>>> t.__class__.__dict__ ###就是test.__dict__
{'classdata': 1, '__module__': '__main__', '__doc__': None}
>>> t.classdata #实例没有classdata,就去类属性中去找
1
>>> test.classdata
1
>>> test.classdata+=1 #类属性加1
>>> test.classdata
2
>>> t.classdata #实例没有classdata,就去类属性中去找,已经加1,就变成了2
2
4.setattr
通过重写__setattr__控制属性的添加
该方法在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
>>> t=Test()
>>> t.key=25
>>> t.name='barry' #只有key属性能添加
>>> t.__dict__ #只有key属性能添加,所以只有key属性
{'key': 25}
5.重写__call__方法
作用:实现达到()调用的效果
>>> class test():
def __call__(self,key):
return self.__dict__[key]
>>> t=test()
>>> t.name='barry'
>>> t
<__main__.test instance at 0x01CD6940>
>>> t.name
'barry'
>>> t('name')
'barry'
6.
_变量名
有些时候,你会看到以一个下划线开头的实例变量名,比如
_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
__变量名
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线
__,在Python中,实例的变量名如果以
__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:
__变量名__
在Python中,变量名类似
__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用
__name__、
__score__这样的变量名。
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问
__name是因为Python解释器对外把
__name变量改成了
_Student__name,所以,仍然可以通过
_Student__name来访问
__name变量:
>>> bart._Student__name 'Bart Simpson'
但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把
__name改成不同的变量名。
总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。
相关文章推荐
- python 中__setattr__, __getattr__,__getattribute__, __call__使用方法
- Python __getattr__ __getattribute__ __setattr__
- python魔法方法:__getattr__,__setattr__,__getattribute__
- python __setattr__、__getattr__、__getattribute__全面详解
- python中__getattr__,__setattr__,__getattribute__的区别
- python __setattr__, __getattr__, __delattr__,__getattribute__
- python魔法方法:__getattr__,__setattr__,__getattribute__
- python中__get__, __getattr__和__getattribute__区别说明
- python中__get__,__getattr__,__getattribute__的区别
- Python __new__, __init__, __metaclass__, __call__, __del__, __getattr__, __getattribute__
- Python的getattr(),setattr(),delattr(),hasattr()
- python 内建函数setattr() getattr()
- python __get__ __getattr__ __getattribute__
- python 学习笔记—— __setattr__ __getattr__ __str__
- __getattribute__()、__getattr__()、__setattr__()、__delattr__()
- 怎么使用Python的getattr(),setattr(),delattr(),hasattr()
- python __setattr__ , __getattr__
- python中__getattribute__与__getattr__调用时的区别
- Python的getattr(),setattr(),delattr(),hasattr()
- Python的getattr(),setattr(),delattr(),hasattr()