python中getitem_python中dir,__dict__ , __setitem__(),__getitem__()

classTesta:pass

classTestb(object):pass

if __name__ == '__main__':print 'testb =',dir(Testb)print '\n'

print 'testa =',dir(Testa)

运行结果:

testb = ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']

testa = ['__doc__', '__module__']

classA(object):"""Class A."""a=0

b= 1

def __init__(self):

self.a= 2self.b= 3

deftest(self):print 'a normal func.'@staticmethoddefstatic_test(self):print 'a static func.'@classmethoddefclass_test(self):print 'a calss func.'obj=A()print A.__dict__

print obj.__dict__

运行结果:

{'a': 0, '__module__': '__main__', 'b': 1, 'class_test': , '__dict__': , '__init__': , 'test': , '__weakref__': , '__doc__': '\n Class A.\n ', 'static_test': }

{'a': 2, 'b': 3}

由此可见,类和实例分别拥有自己的__dict__

类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的

对象的__dict__中存储了一些self.xxx的一些东西

2、Python里什么没有__dict__属性

虽然说一切皆对象,但对象也有不同,就好比不是每个人的女朋友都是一个人一样,一些内置的数据类型是没有__dict__属性的,如下:

num = 3ll=[]

dd={}print num.__dict__

print ll.__dict__

print dd.__dict__

当我们运行这样的代码时,解释器就会告诉我们

Traceback (most recent call last):

File"f:\python\test.py", line 54, in

print num.__dict__AttributeError:'int' object has no attribute '__dict__'Traceback (most recent call last):

File"f:\python\test.py", line 55, in

print ll.__dict__AttributeError:'list' object has no attribute '__dict__'Traceback (most recent call last):

File"f:\python\test.py", line 56, in

print dd.__dict__AttributeError:'dict' object has no attribute '__dict__'

int, list, dict等这些常用的数据类型是没有__dict__属性的,其实这是可预料的,就算给了它们dict属性也没啥用,毕竟它们只是用来做数据容器的。

3、发生继承时候的__dict__属性

子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中。

classParent(object):

a=0

b= 1

def __init__(self):

self.a= 2self.b= 3

defp_test(self):pass

classChild(Parent):

a= 4b= 5

def __init__(self):

super(Child, self).__init__()#self.a = 6 #重写父类的成员变量

#self.b = 7

defc_test(self):pass

defp_test(self):passp=Parent()

c=Child()print Parent.__dict__

print Child.__dict__

print p.__dict__

print c.__dict__

运行结果:

{'a': 0, '__module__': '__main__', 'b': 1, '__dict__': ,'p_test': , '__weakref__': , '__doc__': None, '__init__': }

{'a': 4, 'c_test': , '__module__': '__main__', 'b': 5,'p_test': , '__doc__': None, '__init__': }

{'a': 2, 'b': 3}

{'a': 2, 'b': 3}

1)上段输出结果中,用红色字体标出的是类变量和函数,由结果可知,每个类的类变量、函数名都放在自己的__dict__中

2) 再来看一下实力变量的__dict__中,由蓝色字体标识,父类和子类对象的__dict__是公用的

classBorg(object):__shared_state = {} #子类和父类共享这个变量,导致输出的结果是一样的,具有迷惑性def __init__(self):

self.__dict__ = self.__shared_stateself.state= 'Init'

def __str__(self):returnself.stateclassYourBorg(Borg):pass

if __name__ == '__main__':

rm1=Borg()

rm2=Borg()

rm1.state= 'Idle'rm2.state= 'Running'

print('rm1: {0}'.format(rm1))print('rm2: {0}'.format(rm2))

输出结果:

rm1: Running

rm2: Running

上面这一段代码,乍看挺神奇的,Borg 的各个实例共享了state。实现起来也很巧妙,利用了__dict__。 我们知道,python中__dict__存储了该对象的一些属性。类和实例分别拥有自己的__dict__,且实例会共享类的__dict__。

这里有一个我一直以来都搞混的知识点,在__init__ 中声明的变量 ,以及在方法体之外声明的变量分别是在哪里。很简单的测试就能得到,在__init__中,self.xxx = xxx会把变量存在实例的__dict__中,仅会在该实例中能获取到,

而在方法体外声明的,会在class的__dict__中。

总结:

1) 内置的数据类型没有__dict__属性

2) 每个类有自己的__dict__属性,就算存着继承关系,父类的__dict__ 并不会影响子类的__dict__

3) 对象也有自己的__dict__属性, 存储self.xxx 信息,父子类对象公用__dict__

__xxxitem__:使用 [''] 的方式操作属性时被调用

__setitem__:每当属性被赋值的时候都会调用该方法,因此不能再该方法内赋值 self.name = value 会死循环

__getitem__:当访问属性时会调用该方法

__delitem__:当删除属性时调用该方法

python 运算符重载__getitem__和__setitem__

classIndexer:def __getitem__(self, index): #重载索引,对于实例的索引运算,会自动调用__getitem__

return index**2x=Indexer()print(x[3])classIndexer2:

data=[1,2,3,4,5]def __getitem__(self, index): #重载索引,对于实例的索引运算,会自动调用__getitem__

print '__getitem__'

returnself.data[index]def __setitem__(self, index, value): #重载索引赋值,对于实例的索引赋值,会自动调用__setitem__

print 'setitem:'self.data[index]=valuedef __index__(self):print '__index__'

return 255x=Indexer2()print(x[0])print x[::-1]print(x[1:])print(x[2:4])print(bin(x), bin(255))print(('a'*256)[x])

x[0]= 102

printx

exit(0)

运行结果:

9

__getitem__

1

__getitem__

[5, 4, 3, 2, 1]

__getitem__

[2, 3, 4, 5]

__getitem__

[3, 4]

__index__

('0b11111111', '0b11111111')

__index__

a

setitem:

python中 __setitem__(),__getitem__()

classPerson:#将对象当作字典操作,设置键值对时会触发该方法

def __setitem__(self, key, value):print(key,value)

self.__dict__[key]=value#将对象当作字典操作,根据键获取值时会触发该方法

def __getitem__(self, item):print(item)return self.__dict__.get(item)#将对象当作字典操作,删除指定的键值对时自动触发

def __delitem__(self, key):del self.__dict__[key]

xiaoming=Person()

xiaoming['name'] = '小宏'

print(xiaoming.__dict__)print(xiaoming['name'])del xiaoming['name']

运行结果:

('name', '\xe5\xb0\x8f\xe5\xae\x8f')

{'name': '\xe5\xb0\x8f\xe5\xae\x8f'}

name

小宏

__setitem__(self,key,value):

这个方法应该以与键相关联的方式存储值,以便之后能够使用__setitem__来获取。当然,这个对象可变时才需要实现这个方法。

classTag:def __init__(self):

self.change= {'python': 'This is python','php': 'PHP is a good language'}def __getitem__(self, item):print('调用getitem')returnself.change[item]def __setitem__(self, key, value):print('调用setitem')

self.change[key]=value

a=Tag()print(a['php'])

a['php'] = 'PHP is not a good language'a['ruby'] = 'Ruby is not a good language'

print(a['php'])print(a['ruby'])print a.__dict__exit(0)

运行结果:

调用getitem

PHP is a good language

调用setitem

调用setitem

调用getitem

PHP is not a good language

调用getitem

Ruby is not a good language

{'change': {'python': 'This is python', 'php': 'PHP is not a good language', 'ruby': 'Ruby is not a good language'}}

__delitem__和__delattr__

classFoo:def __init__(self,name):

self.name=namedef __getitem__(self, item):if item == 1:print('hahaha')#print(self.__dict__[item])

def __setitem__(self, key, value):

self.__dict__[key]=valuedef __delitem__(self, key):print('del obj[key]时,我执行')

self.__dict__.pop(key)def __delattr__(self, item):print('del obj.key时,我执行')

self.__dict__.pop(item)

f1= Foo('sb')#访问属性的方式变了#对象名.属性

f1=Foo('sb')

f1['age']=18 #给f1添加一个属性

del f1['age'] #删除属性#f1.name

print(f1['name'])

f1.__dict__['age'] = 18f1['age1']=19

del f1.age1 #删除属性

f1['name']='alex'

print(f1.__dict__)

exit(0)

输出结果:

delobj[key]时,我执行

Nonedelobj.key时,我执行

{'age': 18, 'name': 'alex'}

使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。而如果要保持Key的顺序,可以用OrderedDict

注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:

OrderedDict可以实现一个FIFO(先进先出)的dict,当容量超出限制时,先删除最早添加的Key:

from collections importOrderedDictclassLastUpdatedOrderedDict(OrderedDict):def __init__(self, capacity):

super(LastUpdatedOrderedDict, self).__init__()

self._capacity=capacitydef __setitem__(self, key, value):

containsKey= 1 if key in self else0if len(self) - containsKey >=self._capacity:

last= self.popitem(last=False)print 'remove:', lastifcontainsKey:delself[key]print 'set:', (key, value)else:print 'add:', (key, value)

OrderedDict.__setitem__(self, key, value)#test

d = LastUpdatedOrderedDict(capacity=3)

d['A'] = 100d['B'] = 200d['C'] = 300d['D'] = 400d['E'] = 500

print d

运行结果:

add: ('A', 100)

add: ('B', 200)

add: ('C', 300)

remove: ('A', 100)

add: ('D', 400)

remove: ('B', 200)

add: ('E', 500)

LastUpdatedOrderedDict([('C', 300), ('D', 400), ('E', 500)])

python中__len__

#coding=utf-8

classA:def __init__(self):

self.a= 1self.b= 2

deffun(self):pass

def __len__(self):return len(self.__dict__) #返回的是对象自身的长度

a=A()print(len(a)) #2

exit(0)

_hash__

classA:def __init__(self):

self.a= 1self.b= 2

def __hash__(self):return hash(str(self.a)+str(self.b))

a=A()print(hash(a)) #当在外部使用hash()这种方法实际上就是在内部调用 __hash__这个方法

exit(0)

_EQ__

#coding=utf-8

classA:def __init__(self):

self.a= 1self.b= 2

def __eq__(self,obj):if self.a == obj.a and self.b ==obj.b:returnTrue

a=A()

b=A()print(a==b) #在外部执行==实际上就是在内部调用 __eq__方法

exit(0)

__call__

对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

#coding=utf-8

classFoo:def __init__(self):pass

def __call__(self, *args, **kwargs):print('__call__')

obj= Foo() #执行 __init__

obj() #执行 __call__

exit(0)

python __setitem__ 和 __setattr__关于无限递归

对于__setattr__如果用如下的定义

def __setattr__(self,name,value):

self.name=value

它在出现类似self.a=b的赋值语句时会调用__setattr__并在函数中继续进行同样的赋值操作从而引起无限递归,也就是触发调用__setattr__的条件是遇到self.a=b这样的语句

但对于__setitem__

def __setitem__(self,key,value):

self.__dict__[key]=value

如果定义了一个实例s,要使用序列的方法__setitem__,自然s会成一个字典,而如果我使用s[a]=b的语句修改字典的键的值时为何不会再在__setitem__中继续将a和b作为key和value进行修改赋值从而出现无限递归?

触发调用__setitem__的条件应该是类似s[a]=b还是别的什么语句吗?

def __setitem__(self,key,value):

self[key]=value #以这种方式则会触发无限递归

def __setitem__(self,key,value):

self.__dict__[key]=value #这种则不会,它是以修改对象内置字典的键的值的方式来修改对象的属性值

参考自:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值