修改、查看私有屬性、名字重整
如下,Test類定義 一個私有屬性 __name? 實例化一個對象 a ,無法調用該屬性,
打印 a.__dict__( 可以檢查一個對象的所有屬性 )查看?,發現__name存在并且名字變為? _Test__name (無法調用的原因,名字被改變)
改變規則:私有屬性前添加類名,再在類名前添加一個下劃線 ( 名字重整 )
我們驗證一下,打印修改后的屬性,如下
?
這里有個疑問,既然無法直接打印,那我們為什么可以直接修改?
修改測試一下,打印輸出,此時__name 并不是私有屬性了,此時的 __name 只是添加了一個屬性,可以直接調用
這里就沒有什么私有公有之說了,所謂的公有私有,是指類中的屬性,實例對象無法直接調用
另外補充一下 __dict__屬性,Test類也是一個對象,查看其屬性:每個魔法屬性對應值或函數
?
?
魔法屬性、方法
無論人或事物往往都有不按套路出牌的情況,Python的類屬性也是如此。存在一些具有特殊含義的屬性
如上圖,對應的魔法屬性:
?
1. __doc__ :表示類的描述信息,help()方法也可以輸出類的描述信息
class Test():
"""
This is a description of a class
"""
pass
print(Test.__doc__)
print("*" * 15)
print(help(Test))
?
2. __module__? 和 __class__ :__module__表示當前操作在哪個模塊,__class__表示當前操作的對象的類是什么
# -*- coding:utf-8 -*-
# test.py
class Person(object):
def __init__(self):
self.name = 'laowang'
from test import Person
# main.py
obj = Person()
print(obj.__module__) # 輸出創建該對象的對應模塊 test
print(obj.__class__) # 輸出創建該對象的對應模塊中的類 test.Person
?
3. __init__ :初始化方法(不建議稱其為構造方法,可以說__init__ 和 __new__ 方法一起完成了構造方法的功能),通過類創建對象時,自動觸發執行
class Person:
def __init__(self, name):
self.name = name
self.age = 18
obj = Person('laowang') # 自動執行類中的 __init__ 方法
?
4. __del__:當對象在內存中被釋放時,自動觸發執行
注:此方法無需定義,因為python是一門高級語言,程序員在使用時,無需關系內存的分配和釋放,因為此工作都是交給Python的解釋器來執行,所以,__del__的調用是有解釋器在進行垃圾回收時自動觸發執行的。
class Foo:
def __del__(self):
pass
?
5. __call__:對象后面加括號,觸發執行? (用于裝飾器)
注:__init__方法的執行是由創建對象觸發的,即 對象 = 類名() ; 而對于__call__ 方法執行是由對象后加括號觸發的,即
對象()? 或 類()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 執行 __init__
obj() # 執行 __call__
?
6. __dict__ :?類或對象中的所有屬性? ? ? ? ?
類的實例屬性屬于對象;類中的類屬性和方法等屬于類,即:
class Province(object):
country = 'China'
def __init__(self, name, count):
self.name = name
self.count = count
def func(self, *args, **kwargs):
print('func')
# 獲取類的屬性,即:類屬性、方法、
print(Province.__dict__)
# 輸出:{'__dict__':
, '__module__': '__main__', 'country': 'China', '__doc__': None, '__weakref__':
, 'func':
, '__init__':
}
obj1 = Province('山東', 10000)
print(obj1.__dict__)
# 獲取 對象obj1 的屬性
# 輸出:{'count': 10000, 'name': '山東'}
obj2 = Province('山西', 20000)
print(obj2.__dict__)
# 獲取 對象obj1 的屬性
# 輸出:{'count': 20000, 'name': '山西'}
?
7.?__str__:如果一個類中定義了__str__方法,那么在打印 對象 時,默認輸出該方法的返回值
class Foo:
def __str__(self):
return 'laowang'
obj = Foo()
print(obj)
# 輸出:laowang
?
8.?__getitem__、__setitem__、__delitem__ :用于索引操作,如字典。以上分別表示獲取、設置、刪除數據
# -*- coding: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'] = 'laowang' # 自動觸發執行 __setitem__
del obj['k1'] # 自動觸發執行 __delitem__
9.?__getitem__、__setitem__、__delitem__ :該三個方法用于分片操作,如:列表
# -*- coding:utf-8 -*-
class Foo(object):
def __getslice__(self, i, j):
print('__getslice__', i, j)
def __setslice__(self, i, j, sequence):
print('__setslice__', i, j)
def __delslice__(self, i, j):
print('__delslice__', i, j)
obj = Foo()
obj[-1:1] # 自動觸發執行 __getslice__
obj[0:1] = [11,22,33,44] # 自動觸發執行 __setslice__
del obj[0:2] # 自動觸發執行 __delslice__
?
?
With、上下文管理器
對于系統資源如文件、數據庫連接、socket 而言,應用程序打開這些資源并執行完業務邏輯之后,必須做的一件事就是要關閉(斷開)該資源。
比如 Python 程序打開一個文件,往文件中寫內容,寫完之后,就要關閉該文件,否則會出現什么情況呢?極端情況下會出現 "Too many open files" 的錯誤,因為系統允許你打開的最大文件數量是有限的。
同樣,對于數據庫,如果連接數過多而沒有及時關閉的話,就可能會出現 "Can not connect to MySQL server Too many connections",因為數據庫連接是一種非常昂貴的資源,不可能無限制的被創建。
普通版:
def m1():
f = open("output.txt", "w")
f.write("python之禪")
f.close()
這樣寫有一個潛在的問題,如果在調用 write 的過程中,出現了異常進而導致后續代碼無法繼續執行,close 方法無法被正常調用,因此資源就會一直被該程序占用者釋放。
?
進階版:
def m2():
f = open("output.txt", "w")
try:
f.write("python之禪")
except IOError: # except 未捕獲到對應異常,依然會崩
print("oops error")
finally:
f.close()
改良版本的程序是對可能發生異常的代碼處進行 try 捕獲,使用 try/finally 語句,該語句表示如果在 try 代碼塊中程序出現了異常,后續代碼就不再執行,而直接跳轉到 except 代碼塊。而無論如何,finally 塊的代碼最終都會被執行。因此,只要把 close 放在 finally 代碼中,文件就一定會關閉。
?
高級版:
def m3():
with open("output.txt", "r") as f:
f.write("Python之禪")
一種更加簡潔、優雅的方式就是用 with 關鍵字。 open 方法的返回值賦值給變量 f,當離開 with 代碼塊的時候,系統會自動調用 f.close() 方法, with 的作用和使用 try/finally 語句是一樣的。那么它的實現原理是什么?在講 with 的原理前要涉及到另外一個概念,就是 上下文管理器(Context Manager) 。
?
上下文(context)
上下文在不同的地方表示不同的含義,要感性理解。context其實說白了,和文章的上下文是一個意思,通俗一點,理解為環境
?
上下文管理器
任何實現了 __enter__() 和 __exit__() 方法的對象都可稱之為上下文管理器 ,上下文管理器對象可以使用 with 關鍵字。顯然,文件(file)對象也實現了上下文管理器。
那么文件對象是如何實現這兩個方法的呢?我們可以模擬實現一個自己的文件類,讓該類實現 __enter__() 和 __exit__() 方法。
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("entering")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, *args):
print("will exit")
self.f.close()
__enter__() 方法返回資源對象,這里就是你將要打開的那個文件對象,__exit__() 方法處理一些清除工作。
因為 File 類實現了上下文管理器,現在就可以使用 with 語句了。
with File('out.txt', 'w') as f:
# 實例化File對象,執行__init__方法,filename屬性對應out.txt,w對應mode屬性
# with判斷其是否是一個上下文管理器(實現對應的方法),然后自動調用 __enter__()方法
# __enter__()方法返回值是什么,對應的 f 就是什么,而當結束或者出現異常時,會自動調用 __exit__()
# 方法
print("writing")
f.write('hello, python')
這樣,你就無需顯示地調用 close 方法了,由系統自動去調用,哪怕中間遇到異常 close 方法也會被調用。
?
實現上下文管理器的另外方式(了解)
Python 還提供了一個 contextmanager 的裝飾器,更進一步簡化了上下文管理器的實現方式。通過 yield 將函數分割成兩部分,yield 之前的語句在 __enter__ 方法中執行,yield 之后的語句在 __exit__ 方法中執行。緊跟在 yield 后面的值是函數的返回值。
from contextlib import contextmanager
@contextmanager
def my_open(path, mode):
f = open(path, mode)
yield f
f.close()
調用
with my_open('out.txt', 'w') as f:
f.write("hello , the simplest context manager")
?
?
總結
Python 提供了? with 語法用于簡化資源操作的后續清除操作,是 try/finally 的替代方法,實現原理建立在上下文管理器之上。 此外,Python 還提供了一個 contextmanager 裝飾器,更進一步簡化上下管理器的實現方式。
?
?
?
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
