面向對象學習(四)
阿新 • • 發佈:2019-03-05
obj 其它 ... lin module 函數的調用 解釋器 特殊成員 沒有
運算符重寫
#encoding=utf-8
class Vector(object):
def __init__(self,a,b):
self.a = a
self.b = b
def __str__(self):
return "Vector(%d,%d)" %(self.a,self.b)
def __add__(self,other):
return Vector(self.a + other.a,self.b + other.b)
x = Vector(3,7)
y = Vector(1,-10)
print(x + y)
print(str(x))
類的特殊成員
1.__doc__
類的描述信息
#encoding=utf-8
class Vector(object):
"""類的描述信息"""
def __init__(self):
pass
v = Vector()
print(v.__doc__)
2. __module__ 和 __class__
? __module__ 表示當前操作的對象在那個模塊
? __class__ 表示當前操作的對象的類是什麽
3.__del__
析構方法,當對象在內存中被釋放時,自動觸發執行。
註:此方法一般無須定義,因為Python是一門高級語言,程序員在使用時無需關心內存的分配和釋放,因為此工作都是交給Python解釋器來執行,所以,析構函數的調用是由解釋器在進行垃圾回收時自動觸發執行的。
>>> class P():
... def __del__(self):
... print("del exe")
...
>>> p = P()
>>> del p
del exe
4. __call__
對象後面加括號,觸發執行。
註:構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於
__call__ 方法的執行是由對象後加括號觸發的,即:對象() 或者 類()()
#encoding=utf-8
class Foo(object):
def __init__(self):
pass
def __call__(self,*args,**kwargs):
print("__call__")
obj = Foo()
obj()#會調用實例的__call__方法
5. __dict__
類或對象中的所有成員
6. __str__
如果一個類中定義了__str__方法,那麽在打印 對象 時,默認輸出該方法的返回值。
>>> class Foo(object):
... def __str__(self):
... return "__str__被調用"
...
>>> obj = Foo()
>>> print(obj)
__str__被調用
7. __getitem__ 、__setitem__ 、__delitem__
用於索引操作,如字典。以上分別表示獲取、設置、刪除數據
#encoding=utf-8
class Foo(object):
def __getitem__(self,key):
print("__getitem__",key)
def __setitem__(self,key,value):
print("__setitem__",key,value)
def __delitem__(self,key):
print("__delitem__",key)
obj = Foo()
result = obj["k1"]#自動調用 __getitem__
obj[‘k2‘] = ‘kkkk‘#自動調用 __setitem__
del obj["k1"]#自動調用 __delitem__
8. __getslice__、__setslice__、__delslice__ 在python 2.7可以使用,在3.x已經被去掉了,需要使用__getitem__、__setitem__、__delitem__和__getslice__來實現
#encoding=utf-8
class Foo(object):
def __init__(self,name,age):
self.name = name
self.age = age
self.li = [1,2,3,4,5,6,7]
def __getitem__(self,item):
if isinstance(item,slice):
return self.li[item]
elif isinstance(item,int):
return self.li[item]
def __setitem__(self,key,value):
print(key,value)
self.li[key] =value
def __delitem__(self,key):
print(key)
del self.li[key]
a = Foo("alex",18)
print(a[3:5])#自動調用__getitem__
a[0] = 100#自動調用__setitem__
print(a[0])#自動調用__getitem__
del a[0]#自動調用__delitem__
print(a[0])#自動調用__getitem__
9.__iter__
用於叠代器,之所以列表、字典、元組可以進行for循環,是因為類型內
部定義了 __iter__
#encoding=utf-8
class Foo(object):
def __init__(self,sq):
self.sq = sq
def __iter__(self):
return iter(self.sq)
obj = Foo([1,2,3,4,5])
for i in obj:
print(i)
10.__slot__
限制實例可以使用的屬性名稱
#encoding=utf-8
class Student(object):
__slots__ =("name","age")# 用tuple定義允許綁定的屬性名稱
s = Student()
s.name = "hhh"
s.age = 25
s.score = 99
11. __new__
__new__() 方法是在類準備將自身實例化時調用。
__new__() 方法始終都是類的靜態方法,即使沒有被加上靜態方法裝飾器。
#encoding=utf-8
class A(object):
def __init__(self):
print("init")
def __new__(cls,*args,**kwargs):
print("new %s" %cls)
return object.__new__(cls,*args,**kwargs)
A()
結果分析:
首先調用__new__()方法實例化類,產生類的實例對象;
然後實例對象調用__init__()方法;
繼承自object的新式類才有__new__。
__new__至少要有一個參數cls,代表要實例化的類,此參數在實例化時由Python解釋器自動提供。
__new__必須要有返回值,返回實例化出來的實例,這點在自己實現__new__時要特別註意,可以return父類__new__出來的實例,或者直接是object的__new__出來的實例。
__init__有一個參數self,就是這個__new__返回的實例,__init__在__new__的基礎上可以完成一些其它初始化的動作,__init__不需要返回值。若__new__沒有正確返回 當前類 cls的實例,那__init__是不會被調用的,即使是父類的實例也不行。
__new__ 、 __init__區別
__new__() 類實例化時候調用,產生類的實例
__init__() 類實例對象產生後調用,用來初始化對象的數據
單例
#encoding=utf-8
class Singleton(object):
def __new__(cls,*args,**kwargs):
if not hasattr(cls,"_instance"):
orig = super(Singleton,cls)
cls._instance = orig.__new__(cls,*args,**kwargs)
return cls._instance
class MyClass(Singleton):
a = 1
one = MyClass()
two = MyClass()#one 和 two 完全相同
two.a = 3
print(one.a)
print(id(one))
print(id(two))
print(one == two)
print(one is two)
python對象銷毀(垃圾回收)
同Java語言一樣,Python使用了引用計數這一簡單技術來追蹤內存中的對象。在Python內部記錄著所有使用中的對象各有多少引用。一個內部跟蹤變量,稱為一個引用計數器。當對象被創建時,就創建了一個引用計數,當這個對象不再需要時,也就是說,這個對象的引用計數變為0 時,它被垃圾回收。但是回收不是"立即"的,由解釋器在適當的時機,將垃圾對象占用的內存空間回收
>>> import sys
>>> print(sys.getrefcount(8787))
3
>>> a = 8787
>>> print(sys.getrefcount(a))
2
>>> b = a
>>> print(sys.getrefcount(a))
3
>>> c = a
>>> print(sys.getrefcount(a))
4
>>> d = c
>>> print(sys.getrefcount(a))
5
>>> [1,2].append(a)
>>> print(sys.getrefcount(a))
5
>>> del d
>>> print(sys.getrefcount(a))
4
>>> del b
>>> print(sys.getrefcount(a))
3
>>> del a
>>> print(sys.getrefcount(a))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name ‘a‘ is not defined
垃圾回收
垃圾回收機制不僅針對引用計數為0的對象,同樣也可以處理循環引用的情況。循環引用指的是,兩個對象相互引用,但是沒有其他變量引用他們。這種情況下,僅使用引用計數是不夠的。Python 的垃圾收集器實際上是一個引用計數器和一個循環垃圾收集器。作為引用計數的補充,垃圾收集器也會留心被分配的總量很大(及未通過引用計數銷毀的那些)的對象。在這種情況下,解釋器會暫停下來,試圖清理所有未引用的循環。析構函數 __del__ ,__del__在對象銷毀的時候被調用,當對象不再被使用時,__del__方法運行:
#encoding=utf-8
class Point(object):
def __init__(self,x=0,y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print(class_name,"銷毀")
pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1),id(pt2),id(pt3))
del pt1
print(pt2)
print(pt3)
del pt2
print(pt3)
del pt3
print(pt3)
循環引用的對象被銷毀
#encoding=utf-8
class LeakTest(object):
def __init__(self):
self.a = None
self.b = None
print("object = %d born here" %id(self))
A = LeakTest()
B = LeakTest()
A.a = B
B.b = A
import sys
print(sys.getrefcount(A))
print(sys.getrefcount(B))
del A
try:
print(sys.getrefcount(A))
except Exception as e:
print(e)
del B
try:
print(sys.getrefcount(B))
except Exception as e:
print(e)
面向對象學習(四)