您好,登錄后才能下訂單哦!
特殊屬性
__name__ 類、函數(shù)、方法等的名字
__module__ 類定義所在的模塊
__class__ 對象或類所屬的類
__bases__ 類的基類的元組,順序?yàn)樗麄冊诨惲斜碇谐霈F(xiàn)的順序
__doc__ 類、函數(shù)的文檔字符串,如果沒有定義則為None
__mro__ 類的面容,class.mro()返回的結(jié)果 保存在__mro__中
__dict__ 類或?qū)嵗膶傩裕蓪懙淖值?/span>
查看屬性
__dir__ 返回類或者對象的所有成員名稱列表。dir() 函數(shù)就是調(diào)用__dir__()。
使用實(shí)例調(diào)用時(shí),如果提供__dir__(),則返回其返回值,要求是可迭代對象
如果沒有提供__dir__(),則會(huì)從實(shí)例和類及祖先類中手機(jī)信息
如果dir([obj]) 參數(shù)obj包含方法 __dir__(),該方法將被調(diào)用。如果Obj 不包含 __dir__(),該方法將最大限度收集屬性信息
dir(obj) 對于不同類型的對象obj具有不同的行為:
1.如果對象是模塊對象,返回的列表包含模塊的屬性名和變量名
2.如果對象是類型或者類對象,返回的列表包含類的屬性名,及它的基類的屬性名
3.如果obj不寫 即dir(),返回列表包含內(nèi)容不同
- 在模塊中,返回模塊的屬性和變量名
- 在函數(shù)中,返回本地作用域的變量名
- 在方法中,返回本地作用域的變量名
dir()測試如下:
class Person:
def show(self):
a = 100
t = int(a)
print(dir())
def test(a=50, b=100):
print(dir())
Person().show()
test()
-----------------------------------------------
['a', 'self', 't']
['a', 'b']
魔術(shù)方法***
分類:
1.創(chuàng)建、初始化與銷毀
__new__ 、__init__ 與__del__
2.hash
3.bool
4.可視化
5.運(yùn)算符重載
6.容器和大小
7.可調(diào)用對象
8.上下文管理
9.反射
10.描述器
11.其它雜項(xiàng)
實(shí)例化
__new__方法很少使用,即使創(chuàng)了該方法,也會(huì)使用 return super().__new__(cls)基類obj 的 __new__方法來創(chuàng)建實(shí)例并返回
class A:
def __new__(cls, *args, **kwargs):
print(cls)
print(*args)
print(**kwargs)
return super().__new__(cls) # 返回cls的實(shí)例
# return 1
# return None
def __init__(self, name):
self.name = name
a = A("tom")
print(a)
--------------------------------------------
<class '__main__.A'>
tom
<__main__.A object at 0x00000281924C46A0>
hash
hash(x) x都一樣,求得hash應(yīng)該不變的,冪等性:一般來說,x不一樣,hash應(yīng)該不一樣.
不同的hash算法都有hash沖突的問題,即不同的x求得同樣的hash值
hash值相同就會(huì)去重嗎??
不是的
list 類為為什么不可hash ??
源碼中有一句 __hash__ = None, 也就是調(diào)用 __hash__() 相當(dāng)于 None(),一定報(bào)錯(cuò)
所有類都繼承object,而在這個(gè)類是具有 __hash__() 方法的,如果一個(gè)類不能被hash,就把__hash__設(shè)置為 = None
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
# def __eq__(self, other):
# return self.name == other.name
def __repr__(self):
return self.name
print(hash(A("tom")))
print((A('tom'), A('tom')))
print([A('tom'), A('tom')])
print('-------------------------')
s = {A('tom'), A('tom')} # set
print(s)
print({tuple('t'), tuple('t')})
print({('tom',), ('tom',)})
print({"tom", "tom"})
---------------------------------------------------------------
1
(tom, tom)
[tom, tom]
-------------------------
{tom, tom} # set 沒有去重
{('t',)}
{('tom',)}
{'tom'}
__hash__方法只是返回一個(gè)hash值作為set 的key,但是去重, 還需要__eq__ 來判斷兩個(gè)對象是否相等。
hash值相等,只是hash沖突,不能說明兩個(gè)對象是相等的。
因此,一般來說提供__hash__方法是為了作set或者dict的key,所以 去重,要同時(shí)提供__eq__方法
不可hash對象 isinstance(p1, collection.Hashable) 一定為False(import collections)
去重需要提供 __eq__方法
class A:
def __init__(self, name, age=18):
self.name = name
def __hash__(self):
return 1
def __eq__(self, other): # 提供了__eq__方法
return self.name == other.name
def __repr__(self):
return self.name
print(hash(A("tom")))
print((A('tom'), A('tom')))
print([A('tom'), A('tom')])
print('-------------------------')
s = {A('tom'), A('tom')}
print(s)
print({tuple('t'), tuple('t')})
print({('tom',), ('tom',)})
print({"tom", "tom"})
------------------------------------------------
1
(tom, tom)
[tom, tom]
-------------------------
{tom} #去重了
{('t',)}
{('tom',)}
{'tom'}
bool
可視化
注意:類型判斷要使用type或isinstance, 不能通過判斷print輸出是否帶引號來判斷輸出值的類型。
class A:
def __init__(self, name, age=18):
self.name = name
self.age = age
def __repr__(self):
return "repr:{},{}".format(self.name, self.age)
def __str__(self):
return "str:{},{}".format(self.name, self.age)
def __bytes__(self):
return "{} is {}".format(self.name, self.age).encode()
print(A('tom'))
print([A('tom')])
print([str(A('tom'))])
print(bytes(A('tom')))
print('str:a,1')
s = '1'
print(s)
s1 = 'a'
print(s1)
print([s1], (s,))
print({s, "a"})
-----------------------------------------------------------------
str:tom,18
[repr:tom,18]
['str:tom,18']
b'tom is 18'
str:a,1
1
a
['a'] ('1',)
{'1', 'a'}
運(yùn)算符重載
operator模塊提供以下的特殊方法,可以將類的實(shí)例使用下面的操作符來操作
實(shí)現(xiàn)A類的2 個(gè)實(shí)例相減
class A:
def __init__(self, name, age=18):
self.name = name
self.age = age
def __sub__(self, other):
return self.age - other.age
def __isub__(self, other):
# self.age -= other.age
# return self
# return self.__clas__(self.name, self - other)
return A(self.name, self - other)
tom = A('tom')
jerry = A('jerry',16)
print(tom - jerry)
print(jerry - tom, jerry.__sub__(tom))
print(id(tom))
tom -= jerry
print(tom.age, id(tom))
-------------------------------------------------------
2
-2 -2
1864834369800
2 1864834369800
__isub__方法定義,一般會(huì)in-place來修改自身
如果沒有定義 __isub__方法,則會(huì)調(diào)用__sub__
運(yùn)算符重載應(yīng)用場景
往往是用面向?qū)ο髮?shí)現(xiàn)的類,需要做大量的運(yùn)算,而運(yùn)算符時(shí)這種運(yùn)算在數(shù)學(xué)上最常見的表達(dá)方式,例如 對 - 進(jìn)行了運(yùn)算符重載,實(shí)現(xiàn)了類 的二元操作,重新定義為 tom - jerry
@functools.total_ordering裝飾器
__lt__, __le__,__eq__,__gt__,__ge__是比較大小必須實(shí)現(xiàn)的方法,但是全部寫完太麻煩了,,使用@functools.total_ordering裝飾器就可以大大簡化代碼
但是要求__eq__必須實(shí)現(xiàn),其他方法__lt__,__le__,__gt__,__ge__ 實(shí)現(xiàn)其中一個(gè)
__eq__ 等于 可以推斷 不等于
__gt__ 大于 可以推斷 小于
__ge__ 大于等于 可以推斷 小于 等于
也就是用3 個(gè)方法,就可以吧所有比較解決了,所以total_ordering可以不使用
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __hash__(self):
return hash((self.x, self.y))
def __eq__(self, other):
return self is other or (self.x == other.x and self.y == other.y)
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __iadd__(self, other):
self.x, self.y = self.x + other.x, self.y + other.y
return self
def __eq__(self, other): #判斷 == , !=
return self.x == other.x
def __gt__(self, other): # 判斷> , <
return self.x > other.x
def __ge__(self, other): # 判斷>= , <=
return self.x >= other.x
a = Point(3,2)
b = Point(1,3)
c = Point(3,1)
print(a + b)
print(a > b)
print(a > c)
print(a < b)
print(a < c)
print(a >= c)
print(a <= c)
-----------------------------------------------------------
<__main__.Point object at 0x000001F51ACA49E8>
True
False
False
False
True
True
容器相關(guān)方法
為什么空字典,空字符串,空元祖,空列表,空集合可以等效為False
因?yàn)?__bool__未定義時(shí),回調(diào)用 __len__ 結(jié)果為0 等下 False
class A(dict):
def __missing__(self, key):
print('Missingn key:', key)
return 0
a = A()
print(a['k'])
------------------------------
Missingn key: k
0
可調(diào)用對象
Python 中一切皆對象,函數(shù)也不例外
函數(shù)即對象,對象foo加上(), 就是調(diào)用此函數(shù)對象的__call__()方法
def foo():
print(foo.__module__, foo.__name__)
foo()
# 等價(jià)于
foo.__call__()
可調(diào)用對象: 定義一個(gè)類,并實(shí)例化的到其實(shí)例,將實(shí)例像函數(shù)一樣調(diào)用
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __call__(self, *args, **kwargs):
return "<Point {}:{}>".format(self.x, self.y)
p = Point(4, 5)
print(p)
print(p())
--------------------------------------------------------
<__main__.Point object at 0x000001F7E8E30A20>
<Point 4:5>
class Adder:
def __call__(self, *args):
ret = 0
for x in args:
ret += x
self.ret = ret
return ret
adder = Adder()
print(adder(4, 5, 6))
print(adder.ret) # 當(dāng)adder(4,5,6)不存在時(shí),__call__方法不會(huì)調(diào)用,Adder無adder.ert屬性,會(huì)拋異常
-------------------------------------------------------
<Point 4:5>
15
15
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。