1. getattr、setattr、hasattr
getattr比較常用,與setattr和hasattr一起出現,他們也是最容易了解的,下面是他的用法:
class Profile():
name="xiaoxin"
def sex(self):
return "male"p=Profile()
hasattr(p, "name") # 判斷屬性是否存在
>>> True
hasattr(p, "age") # 判斷屬性是否存在
>>> False
getattr(p, "name") # 擷取屬性值
>>> xiaoxin
getattr(p, "sex")
>>> <bound method Profile.sex of <__main__.Profile object at 0x7f22608f9710>>
getattr(p, "age", 14) # 如果屬性不存在,則傳回預設值
>>> 14
setattr(p, "age", "26") # 為屬性指派,并沒有傳回值
hasattr(p, "age") # 屬性存在了
>>> True
2. __get__ 、 __set__、 __delete__
提起__get__, 就不能不說 __set__, __delete__ , 一個類,隻要其内部定義了方法 __get__, __set__, __delete__ 中的一個或多個,就可以稱其為描述符。如果同時定義了
__get__()
和
__set__()
,其被認為是一個資料描述符。隻定義
__get__()
的描述符被稱為非資料描述符。
描述符常被用來作類型檢查, 下面看它的具體用法:
class Integer:
def __init__(self, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
else:
return instance.__dict__[self.name]
def __set__(self, instance, value):
if not isinstance(value, int):
raise TypeError('excepted an int')
instance.__dict__[self.name] = value
def __delete__(self, instance):
del instance.__dict__[self.name]
class Point:
x = Integer('x')
y = Integer('y')
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(2, 3)
p.x
>> 2
p.y
>> 3
p = Point(2.5, 3)
>> TypeError: excepted an int
需要注意的是,對象屬性的通路順序:執行個體屬性>類屬性>父類屬性>__getattr__(),當Python解釋器發現執行個體對象的字典中,有與描述符同名的屬性時,描述符優先,會覆寫掉執行個體屬性。
3. __getattr__ 、__setattr__ 、__delattr__
從對象中讀取某個屬性時,首先需要從self.__dicts__中搜尋該屬性,如果__dict__中沒有該屬性, 再從__getattr__中拿到傳回值。當設定屬性時,則會觸發__setattr__方法,在這裡可以進行類型驗證(描述符隻會對定義的描述符屬性進行類型驗證, 而__setattr__會對所有屬性進行類型驗證)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __getattr__(self, item):
print(f'getattr {item}')
return None
def __setattr__(self, key, value):
print(f'setattr {key}:{value}')
if isinstance(value, int):
return object.__setattr__(self, key, value)
def __delattr__(self, item):
print(f"delattr {item}")
del self.__dict__[item]
p = Point(2, 3)
>>> setattr x:2
>>> setattr y:3
p.x
>>> 3
p.c
>>> getattr c
>>> None
p.c = 9
>>> setattr c:9
p.c
>>> 9
4. __getattribute__
無論調用屬性還是方法,都是先強制調用 __getattribute__ 方法,然後再傳回屬性的值或者是 函數(方法)的引用。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __getattribute__(self, item): # 在 __getattribute__ 方法裡面不要在出現self.**這種調用,因為每次調用類的屬性都會強制調用 __getattribute__ ,會造成遞歸調用
return 'i get you ' if item == 'x' else object.__getattribute__(self, item)
def __getattr__(self, item):
print(f'getattr {item}')
return None
p = Point(2, 3)
p.x
>>> i get you
p.y
>>> 3
p.c # 首先調用 __getattribute__ , 裡面實作了 查找__dict__裡面有沒有這個鍵,如果沒有再調用 __getattr__方法
>>> getattr c
>>> None
5. __getitem__、__setitem__、__delitem__
這三個方法主要用于對集合的操作
可變集合需要實作: __len__ __getitem__ __setitem__ __delitem__
不可變集合需要實作: __len__ __getitem__
__len__:傳回集合長度
__getitem__(self, item) 使用索引通路元素
__setitem__(self, key, value) 對索引指派,使用 self[key] = value 。
__delitem__(self, key) 删除索引值 del self[key]
__contains__ 實作in運算符,如果沒有實作這個方法python也會調用__getitem__來使in運算符可用
class TemTest:
def __init__(self,):
self.x = [i for i in range(10)]
def __len__(self):
return len(self.x)
def __getitem__(self, item):return self.x[item]
def __setitem__(self, key, value):
self.x[key] = value
def __delitem__(self, key):
del self.x[key]
def __contains__(self, item):
return item in self.x
def __repr__(self):
return '{}'.format(self.x)
test=TemTest() #執行個體化
print(len(test)) #傳回長度
print(test[0]) #列印下标0的值
print(test[:3]) #切片
test[3]=10 #将下标3的值替換為10
print(test)
del test[3] #删除下标3的值
print(test)
print(1 in test) #測試in運算符
print(3 in test)
10
0
[0, 1, 2]
[0, 1, 2, 10, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 4, 5, 6, 7, 8, 9]
True
False
參考博文:https://www.cnblogs.com/flashBoxer/p/9645939.html