__gititem__
魔术实现self[key]访问,序列对象,key接受整数为索引,或者切片,对于set和dict,key为hashable。key存在时引发异常。为避免key不存在引发异常,可以通过__missing__魔术解决
__setitem__
魔术实现self[key]=value对象添加,
根据如上两种魔术方法,可知此实例的魔术方法都是操作实例容器的,具体代码如下:
dicta = {"a":1,"b":2,"c":3}
class B:
def __init__(self,dictobj):
self.d = dictobj
def __getitem__(self, item):
return self.d.get(item)
def __setitem__(self, key, value):
self.d[key]=value
b = B(dicta)
#通过索引访问实例容器时,就会调用类属性__getitem__魔术
print(b["a"])
#通过索引访问设置实例容器的值
b["d"] = 4
print(b.d)
#######################
#运行结果
1
{'d': 4, 'b': 2, 'c': 3, 'a': 1}
如下魔法主要是对实例属性的操作,和对实例容器操作的概念完全不同
__getattr__
魔术一个类的属性会按照继承关系找,如果找不到,就会执行__getattr__()
方法,如果没有这个方法,就会抛出AttributeError异常表示找不到属性。
查找属性顺序为:
instance.__dict__ --> instance.__class__.__dict__ -->继承的祖先类(直到object)的__dict__-->找不到-->调用__getattr__()
class Base:
n = 0
class Point(Base):
"""doc"""
z = 6
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print(self.x,self.y)
def __getattr__(self, item):
return "missing {}".format(item)
p1 = Point(4,5)
print(p1.x)
print(p1.z)
print(p1.n)
print(p1.t)
########################
#运行结果如下:
4
6
0
missing t
__setattr__
魔术只要是给实例添加属性就要调用__setattr__
魔术,如在初始化时self.x=x时,或者其他方法中slef.x = x,通常都会调用此魔术,正常情况下__setattr__
函数内容如下:
class A:
def __setattr__(self,key,vaule):
self.__dict__[key] = value
如果遇到__setattr__
的函数内容为其他语句时,当个self.x=x 属性增加属性时,就会按照此函数给添加内容
在__setattr__
函数体中仅仅为打印语句,预计无法将属性添加至实例字典中
class Base:
n = 0
class Point(Base):
"""doc"""
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print(self.x,self.y)
def __getattr__(self, item):
print(4,item,"``````````````")
print(5,type(item))
def __setattr__(self, key, value):
#预计实例属性字典为空
print(10,key,type(key))
print(11,value,type(value))
p1 = Point(4,5)
print(1,p1.x,p1.y)
print(2,p1.n)
print(3,p1.__dict__)
##############################
#运行结果如下:属性字典为空
10 x <class 'str'>
11 4 <class 'int'>
10 y <class 'str'>
11 5 <class 'int'>
4 x ``````````````
5 <class 'str'>
4 y ``````````````
5 <class 'str'>
1 None None
2 0
#如下实例字典为空
3 {}
在__setattr__
魔术中有给实例字典添加属性,预计正常给实例添加属性
class Base:
n = 0
class Point(Base):
"""doc"""
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print(self.x,self.y)
def __getattr__(self, item):
print(4,item,"``````````````")
print(5,type(item))
def __setattr__(self, key, value):
print(10,key,type(key))
print(11,value,type(value))
self.__dict__[key] = value
p1 = Point(4,5)
print(1,p1.x,p1.y)
print(2,p1.n)
print(3,p1.__dict__)
#########################################
#运行结果如下:预计正常添加实例属性
10 x <class 'str'>
11 4 <class 'int'>
10 y <class 'str'>
11 5 <class 'int'>
1 4 5
2 0
#如下实例字典正常
3 {'x': 4, 'y': 5}
__delattr__
删除属性魔术在删除实例的属性时会调用此方法
若对一个类对象的属性进行增加或删除时,通常采用内建函数
内建函数getattr(object, name, default=None),通常在一个对象上获取某一属性,如下:
class Point(Base):
"""doc"""
def __init__(self,x,y):
self.x = x
self.y = y
def show(self):
print("test")
p1 = Point(4,5)
getattr(p1,"show")()
###############################
#运行如下:
test
给实例对象或者类对象增加某属性,若对实例增加属性时,任然调用的是__setattr
魔术,如下:
class Point(Base):
"""doc"""
def __init__(self,x,y):
self.x = x
self.y = y
def __getattr__(self, item):
print(4,item,"``````````````")
print(5,type(item))
def __setattr__(self, key, value):
print(10,key,type(key))
print(11,value,type(value))
# self.__dict__[key] = value
p1 = Point(4,5)
setattr(p1,"a",123)
print(p1.__dict__)
################################
#运行结果如下:
10 x <class 'str'>
11 4 <class 'int'>
10 y <class 'str'>
11 5 <class 'int'>
10 a <class 'str'>
11 123 <class 'int'>
{}
如何访问一个字典的一个值就像访问一个类属性一样?,而且禁止修改属性
d = {"a":1,"b":2,"c":3}
class AttrDict:
def __init__(self,d:dict):
self.__dict__.update(d if isinstance(d,dict) else {})
def __setattr__(self, key, value):
raise NotImplementedError
def __repr__(self):
return "" .format(self.__dict__)
ad = AttrDict(d)
print(ad.__dict__)
print(ad.a)
print(ad.b)
print(ad.c)