23.python中的類屬性和實例屬性

来源:http://www.cnblogs.com/scolia/archive/2016/06/13/5582268.html
-Advertisement-
Play Games

在上篇的時候,我們知道了:屬性就是屬於一個對象的數據或者函數,我們可以通過句點(.)來訪問屬性,同時 python 還支持在運作中添加和修改屬性。 而數據變數,類似於: name = 'scolia' 這樣的形式,會稱其為欄位;而類裡面的函數,又稱為方法。而方法又分為實例方法,類方法和靜態方法,這些 ...


  在上篇的時候,我們知道了:屬性就是屬於一個對象的數據或者函數,我們可以通過句點(.)來訪問屬性,同時 python 還支持在運作中添加和修改屬性。

  而數據變數,類似於: name = 'scolia' 這樣的形式,會稱其為欄位;而類裡面的函數,又稱為方法。而方法又分為實例方法,類方法和靜態方法,這些我們以後在講。

  我們先來看看類裡面的普通欄位:

class Test(object):
    name = 'scolia'

a = Test()
print Test.name  # 通過類進行訪問
print a.name    # 通過實例進行訪問

 

  我們發現都是可以訪問的。

  但是,如果我們試圖修改這個屬性的話:

class Test(object):
    name = 'scolia'

a = Test()
Test.name = 'scolia good'   # 通過類進行修改
print Test.name
print a.name

 

  我們發現兩者都修改成功了。

  如果通過實例來修改屬性的話:

class Test(object):
    name = 'scolia'

a = Test()
a.name = 'scolia good'  # 通過實例進行修改
print Test.name
print a.name

 

  我們發現類的屬性沒有修改,而實例的屬性則修改成功了。這究竟是為什麼?

  其實這裡的情況非常類似於局部作用域和全局作用域。

  我在函數內訪問變數時,會先在函數內部查詢有沒有這個變數,如果沒有,就到外層中找。這裡的情況是我在實例中訪問一個屬性,但是我實例中沒有,我就試圖去創建我的類中尋找有沒有這個屬性。找到了,就有,沒找到,就拋出異常。而當我試圖用實例去修改一個在類中不可變的屬性的時候,我實際上並沒有修改,而是在我的實例中創建了這個屬性。而當我再次訪問這個屬性的時候,我實例中有,就不用去類中尋找了。

  如果用一張圖來表示的話:

  函數  dir()  就能查看對象的屬性:

class Test(object):
    name = 'scolia'

a = Test()
a.abc = 123
print dir(Test)
print dir(a)

 

  它返回一個列表,包含所有能找到的屬性的名字,這裡我們為實例 a 創建了 abc 屬性,這裡就能看到了。

  有些同學會有疑問,為什麼我才寫了幾個屬性,結果卻多出一堆我不認識的?

  因為我們這裡用的是新式類,新式類繼承於父類 object ,而這些我們沒有寫的屬性,都是在 object 中定義的。

  如果我們用經典類的話:

  為了方便演示,下麵都使用經典類,若沒有特殊說明,新舊兩式基本是一樣的。

  其中 __doc__ 是說明文檔,在類中的第一個沒有賦值的字元串就是說明文檔,一般在class的第二行寫,沒有就為 None。

   __module__ 表示這個類來自哪個模塊,我們在主文件中寫的類,其值應該為 ‘__main__’,在其他模塊中的類,其值就為模塊名。

class Test:
    """文檔字元串"""
    name = 'scolia'

print Test.__doc__
print Test.__module__

 

  文檔字元串不一定非要用三引號,只是一般習慣上用三引號表示註釋。實例也可以訪問,實際訪問的是創建它的類的文檔字元串,但是子類並不會繼承父類的文檔字元串,關於繼承的問題以後再講。

  除了這兩個特殊的屬性之外,還有幾個常用的,雖然沒有顯示出來,但也是可以用的。

 __dict__ 

class Test:
    """文檔字元串"""
    name = 'scolia'

a = Test()
a.name = 'good'
print Test.__dict__
print a.__dict__

 

  這個屬性就是將對象內的屬性和值用字典的方式顯示出來。這裡可以明顯的看出來,實例創建了一個同名的屬性。

  我們也可以使用  vars()  函數,傳給函數一個對象,其結果也是一樣的。

 __class__ 

class Test:
    pass

a = Test()
print a.__class__

 

  這個屬性只有實例中有,它表示創建這個實例的類是哪個,這裡顯示是 __main__ 模塊,也就是主文件中的 Test 這個類創建的。

  但是其返回值並不是字元串,而是創建實例的類對象,但新舊式類返回有點不同:

經典類:

新式類:

  因為返回的是創建實例的類對象,也就是說我們也要用這個返回的類對象再進行實例化。

b = a.__class__()
print b

 

  這裡用的是新式類為例,實際上新舊式類都能這樣做。下麵是舊式類的:

 

  但是,這並不意味不能通過實例來修改類中的屬性。我們知道對於不可修改類型的‘修改’,其實就是重新賦值。這個也和函數中的局部作用域和全局作用域類似,我在函數內部嘗試‘修改’一個不可變類型其實就是創建新的同名變數。但我卻可以訪問全局某個可修改的對象來修改它。

  看代碼:

class Test:
    list1 = []

a = Test()
a.list1.append(123)     # 同通過實例修改類中的列表
print Test.list1
print a.list1

  我通過實例訪問到了一個對象,這個對象是可修改的,所以我可以修改這個對象。這相當於直接操作那個對象。

  但是,等號這樣的顯式賦值行為還是創建新的對象:

a.list1 = [123]   # 顯式的創建一個新對象

 

  這可能有點繞,需要對變數的賦值、可修改對象與不可修改對象的瞭解,可以參考我以前的相關博文。

 

  這裡又有個問題了,我們通常使用 __init__ 來初始化時,會為其添加數據屬性,例如 self.name = xxx ,但是卻幾乎不會為實例添加方法,也就是說實例中的方法,都是在類中找的。這樣做其實有好處,因為方法一般是通用的,如果每一個實例都要保存一套方法的話,實在太浪費資源,而把這些方法統一保存到類中,用到的時候來類里找,就節約了許多。

  當然,我們也可以任性地為某個實例添加方法,python 支持動態添加屬性。

class Test:
    pass

def fangfa():
    print '我是某個實例的方法'

a = Test()
b = Test()
a.abc = fangfa  # 特意添加一個方法
a.abc()
b.abc()     # b 沒有這個方法

 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 好久沒翻譯simple java了,睡前來一發。譯文鏈接:http://www.programcreek.com/2014/01/java-serialization/ 什麼是對象序列化 在Java中,對象序列化指的是將對象用位元組序列的形式表示,這些位元組序列包含了對象的數據和信息,一個序列化後的對象 ...
  • 如果你伺服器環境允許yum,安裝MySQL-python模塊就很簡單了。 如果直接安裝不行,先 安裝MySQL-devel後正常運行 yum install mysql-devel yum install MySQL-python -y 1 yum install MySQL-python -y 當 ...
  • 這裡首先有一個問題要考慮的是,這類方法是否要被測試? 理論上,這類方法都會被其它public類型的方法調用,只要對那些public的方法做充分的測試,就可以保證這些方法的可靠性,就沒有必要再測了。好像是有道理的。 我們先看看好的單元測試的原則:(ATRIP) 自動化(Automatic) 徹底(Th ...
  • 使用repalceAll 方法出現java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 0異常 代碼如下: 以junit測試方式運行後報瞭如下錯誤: java.util.regex.Pattern ...
  • PHP 的真正威力源自於它的函數。 在 PHP 中,提供了超過 1000 個內建的函數。 在本章中,我們將為您講解如何創建自己的函數。 如要在頁面載入時執行腳本,您可以把它放到函數里。 函數是通過調用函數來執行的。 你可以在頁面的任何位置調用函數。 創建 PHP 函數 函數是通過調用函數來執行的。 ...
  • python3登錄極路由並讀取寬頻帳號帳號密碼,fiddler抓包分析過程略... 步驟:1、登錄路由,提取stok。 2、用stok拼成url,post請求 3、解析json數據 代碼: qpython3中包含了requests庫,所以也可以在手機上運行。 ...
  • scala的訪問修飾符有如下幾個特性: 如果不指定訪問修飾符,scala預設為public; 較之Java,scala對protected的定義更加嚴格; scala可以對可見性進行細粒度的控制。 scala的預設訪問修飾符 如果沒有修飾符,scala會預設把類、欄位、方法的訪問修飾符當做publi... ...
  • 獲取Frame對象 獲取TextField對象 獲取TextArea對象 獲取Button對象 調用Frame對象的add()方法,添加進去 調用TextField對象的getText()方法,可以獲取文本框內的數據 調用TextArea對象的setText()方法,設置文本數據 列目錄 獲取到文本 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...