1. 程式人生 > >python cookbook學習筆記十六:類和物件(1)

python cookbook學習筆記十六:類和物件(1)

我們經常會對列印一個物件來得到物件的某些資訊。
class pair:

    def __init__(self,x,y):

        self.x=x

        self.y=y
if __name__=='__main__':

    p=pair(3,4)

    print p
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
<__main__.pair instance at 0x01723B20>
得到的這個結果。Instance at 0x01723B20.這是物件在記憶體中的地址。這個對我們來說沒啥作用,如何才能體現出物件的具體資訊呢。有兩種方法。__repr__
__str__.程式碼修改如下
class pair:

    def __init__(self,x,y):

        self.x=x

        self.y=y

    def __repr__(self):

        return 'Pair({self.x},{self.y})'.format(self=self)

    def __str__(self):

        return '({self.x},{self.y})'.format(self=self)
那麼__repr____str__的區別在哪裡呢。看下下面的呼叫,命令列直接呼叫類例項的時候,是__repr__
在起作用,如果是print 例項的時候則是__str__在起作用
>>>ret= pair(3,4)
>>>ret
>>>Pair(3,4)
>>>print ret
>>>(3,4)
讓物件支援上下文協議。
說到上下文協議首先先介紹下with的用法。我們經常開啟檔案進行資料讀取或者是更新。如下面的程式碼
f=open(r'E:\py_prj\test.txt','rb')

for line in f:

    print line
如果這時忘記了寫f.close()或者說寫了f.close()但是由於讀取檔案的中途出現錯誤。導致f.close()
未執行。這個時候該怎麼辦呢。我們通常想到的是try…except語句。程式碼如下。不管是執行成功還是失敗。最後finally中都會執行f.close()將檔案關閉
try:

    f=open(r'E:\py_prj\test.txt','rb')

    for line in f:

        print line

except:

    print 'error'

finally:

    f.close()
try..except…finally倒是能規避掉異常帶來的失誤。但是程式碼稍顯多了點。有沒有可以簡化的方法呢。With就是滿足這個需求的。程式碼如下。
with open(r'E:\py_prj\test.txt','rb') as f:

    for line in f:

        print line
看上去貌似with也沒有進行異常保護呢,如果出現前面的問題,會是什麼樣的結果呢。先來看下with的說明文件
while this might look like magic, the way Python handles with is more clever than magic. The basic idea is that the statement after with has to evaluate an object that responds to an __enter__() as well as an __exit__() function.
After the statement that follows with is evaluated, the __enter__() function on the resulting object is called. The value returned by this function is assigned to the variable following as. After every statement in the block is evaluated, the __exit__() function is called.
從上面的描述來看,with的使用和__enter__以及__exit__有關係。我們來自己測試一把,在類中運用with語句
class sample:

    def __enter__(self):

        print 'enter'

    def __exit__(self,type,value,trace):

        print 'exit'if __name__=='__main__':

    s=sample()

    with s as test:

        print 'test sample'
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
enter
test sample
exit
從上面的執行順序可以看到當執行到with s as test的時候,進入了__enter__,並列印enter。然後執行with中的具體語句列印test sample。在將with下面的語句執行完後就開始執行__exit__。這樣的with的執行順序就清楚了。在__exit__中有三個引數,typevalue,trace。這是幹什麼用的呢。這是儲存異常的一些訊息。通過這3個引數可以得到執行失敗的一些資訊
關於__slots__
我們在類中定義的屬性都是儲存在一個字典中的。如果要檢視類中的屬性,直接檢視__dict__就可以了
class date_try(object):

    def __init__(self):

        self.year=2017

        self.month=6

        self.day=12

if __name__=='__main__':

    d=date_try()print d.__dict__
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
{'month': 6, 'day': 12, 'year': 2017}
通過執行__dict__可以檢視到全部的屬性。如果我們中途還想繫結屬性呢。
d=date_try()

d.hour=22  #在這裡綁定了hour

print d.__dict__
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
{'month': 6, 'day': 12, 'hour': 22, 'year': 2017}
可以看到hour也加入到了__dict__中去了
有一種場景,如果我們有很多個類,但是每個類中都是固定的幾個屬性。如果都用dict來儲存,就太浪費記憶體了,原因在流暢的python的學習筆記中介紹給,dict由於採用hash索引的方法,雖然查詢速度快,但是很佔記憶體。既然類中的屬性固定。那麼我們是否可以限定屬性呢而且不用dict儲存呢。這裡就要用到__slots__
class date_try(object):

    __slots__=('year','month','day')

    def __init__(self):

        self.year=2017

        self.month=6

        self.day=12





if __name__=='__main__':

    d=date_try()

    print d.__dict__
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
Traceback (most recent call last):
  File "E:/py_prj/python_cookbook/chapter8.py", line 32, in <module>
    print d.__dict__
AttributeError: 'date_try' object has no attribute '__dict__'
這個時候如果去檢視__dict__就會報錯,證明屬性沒有儲存在__dict__中。這樣只會給屬性單獨分配空間而不會用到dict。那如果我想增加屬性呢
d=date_try()

d.hour=22
E:\python2.7.11\python.exe E:/py_prj/python_cookbook/chapter8.py
Traceback (most recent call last):
  File "E:/py_prj/python_cookbook/chapter8.py", line 32, in <module>
    d.hour=22
AttributeError: 'date_try' object has no attribute 'hour'
是沒法新增的。由於定義了__slots__,因此這個類中的屬性就只能用__slots__中的屬性名。除此之外的無法新增
如果有很多類且類的屬性都固定,那麼用__slots__的確可以達到節省記憶體的效果。但是缺點也顯而易見,屬性全部固定。無法新增。