2019年12月16日 星期一

print(dir(urllib.request.urlopen(url))) 實作



import urllib.request

url = 'http://www.baidu.com/'

response = urllib.request.urlopen(url)

print(type(response))
print(dir(response))
print(dir(urllib.request.urlopen(url)))

-------------------------------------------------------------------------------------------------------

<class 'http.client.HTTPResponse'>
['__abstractmethods__', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_check_close', '_close_conn', '_get_chunk_left', '_method', '_peek_chunked', '_read1_chunked', '_read_and_discard_trailer', '_read_next_chunk_size', '_read_status', '_readall_chunked', '_readinto_chunked', '_safe_read', '_safe_readinto', 'begin', 'chunk_left', 'chunked', 'close', 'closed', 'code', 'debuglevel', 'detach', 'fileno', 'flush', 'fp', 'getcode', 'getheader', 'getheaders', 'geturl', 'headers', 'info', 'isatty', 'isclosed', 'length', 'msg', 'peek', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'reason', 'seek', 'seekable', 'status', 'tell', 'truncate', 'url', 'version', 'will_close', 'writable', 'write', 'writelines']
['__abstractmethods__', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_abc_cache', '_abc_negative_cache', '_abc_negative_cache_version', '_abc_registry', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_check_close', '_close_conn', '_get_chunk_left', '_method', '_peek_chunked', '_read1_chunked', '_read_and_discard_trailer', '_read_next_chunk_size', '_read_status', '_readall_chunked', '_readinto_chunked', '_safe_read', '_safe_readinto', 'begin', 'chunk_left', 'chunked', 'close', 'closed', 'code', 'debuglevel', 'detach', 'fileno', 'flush', 'fp', 'getcode', 'getheader', 'getheaders', 'geturl', 'headers', 'info', 'isatty', 'isclosed', 'length', 'msg', 'peek', 'read', 'read1', 'readable', 'readinto', 'readinto1', 'readline', 'readlines', 'reason', 'seek', 'seekable', 'status', 'tell', 'truncate', 'url', 'version', 'will_close', 'writable', 'write', 'writelines']

-------------------------------------------------------------------------------------------------------------

>>> print(help(response.url))
No Python documentation found for 'http://www.baidu.com/'.
Use help() to get the interactive help utility.
Use help(str) for help on the str class.

None
>>> print(help(response.info))
Help on method info in module http.client:

info() method of http.client.HTTPResponse instance
    Returns an instance of the class mimetools.Message containing
    meta-information associated with the URL.

    When the method is HTTP, these headers are those returned by
    the server at the head of the retrieved HTML page (including
    Content-Length and Content-Type).

    When the method is FTP, a Content-Length header will be
    present if (as is now usual) the server passed back a file
    length in response to the FTP retrieval request. A
    Content-Type header will be present if the MIME type can be
    guessed.

    When the method is local-file, returned headers will include
    a Date representing the file's last-modified time, a
    Content-Length giving file size, and a Content-Type
    containing a guess at the file's type. See also the
    description of the mimetools module.

None
>>> print(response.info)
<bound method HTTPResponse.info of <http.client.HTTPResponse object at 0x0000019A39B707B8>>
>>> print(response.url)
http://www.baidu.com/

>>>





dir(str) & help(str.replace)




C:\Users\a>python
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> dir(str)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>>
>>>
模塊下的方法,, 怎麼用? , 使用 help 
>>> help(str.replace)
Help on method_descriptor:

replace(self, old, new, count=-1, /)
    Return a copy with all occurrences of substring old replaced by new.

      count
        Maximum number of occurrences to replace.
        -1 (the default value) means replace all occurrences.

    If the optional argument count is given, only the first count occurrences are
    replaced.


>>>



-------------------------------------------------------------------------------------


Python dir() 函數
描述
dir() 函數不帶參數時,返回當前範圍內的變數、方法和定義的類型列表;帶參數時,返回參數的屬性、方法清單。如果參數包含方法__dir__(),該方法將被調用。如果參數不包含__dir__(),該方法將最大限度地收集參數資訊。
語法
dir 語法:
dir([object])
參數說明:
·         object -- 物件、變數、類型。
返回值
返回模組的屬性清單。
實例
以下實例展示了 dir 的使用方法:
>>>dir() # 獲得當前模組的屬性清單 ['__builtins__', '__doc__', '__name__', '__package__', 'arr', 'myslice'] 
>>> dir([ ​]) # 查看列表的方 ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'
>>>

--------------------------------------------------------------------------------------------------------------------------

Python help() 函數


描述
help() 函數用於查看函數或模組用途的詳細說明。
語法
help 語法:
help([object])
參數說明:
·         object -- 對象;
返回值
返回物件説明資訊。
實例
以下實例展示了 help 的使用方法:
>>>help('sys') # 查看 sys 模組的説明 ……顯示説明資訊…… 
>>>help('str') # 查看 str 資料類型的説明 ……顯示説明資訊…… 
>>>a = [1,2,3] 
>>>help(a) # 查看清單 list 説明資訊 ……顯示説明資訊…… 
>>>help(a.append) # 顯示listappend方法的説明 ……顯示説明資訊……










Python基礎入門--八大數據類型:1.數字2.字符串3.列表4.元組5.字典6.集合7.文件8其它



Python基礎入門--八大數據結構


  1. Python數據類型(一)-數字
  2. Python數據類型(二) -字符串
  3. Python數據類型(三) -列表
  4. Python數據類型(四) -元組
  5. Python數據類型(五) -字典
  6. Python數據類型(六) -集合
  7. Python數據類型(七) -文件
  8. Python其它數據類型(八)

Urllib.request用法簡單介紹


Urllib.request用法簡單介紹




urllib- URL處理模塊

源代碼: Lib / urllib /

urllib 是一個軟件包,收集了幾個用於處理URL的模塊:
               是Python標準庫的一部分,包含 四個子模塊


主要介紹 urllib.request 的一些簡單用法.

首先是 urlopen 函數,用於打開一個 URL:




urllib.request將你的HTTP請求保存為一個``Request``物件。在最簡單的情況下,一個Request物件裡包含你所請求的特定URL。以當前的Request對象作為參數調用``urlopen``返回伺服器對你正在請求的URL的回應。回應是個檔類物件,所以你可以調用如``.read()``等命令。

import urllib.request

req = urllib.request.Request('http://www.voidspace.org.uk')
with urllib.request.urlopen(req) as response:
   the_page = response.read()


# -*- coding:utf-8 -*- 
#獲取並列印google首頁的html
import urllib.request

response=urllib.request.urlopen('http://www.google.com')
html=response.read()

print(html)



urlopen 返回一個類檔對象,可以像檔一樣操作,同時支援一下三個方法:

info()      :返回一個對象,表示遠程服務器返回的頭資訊。
getcode():返回Http狀態碼,如果是http請求,200表示請求成功完成;404表示網址未找到。
geturl()    :返回請求的url地址。

使用urllib.request最簡單的方式:



下面是使用urllib.request最簡單的方式:

import urllib.request
with urllib.request.urlopen('http://python.org/') as response:
   html = response.read()

Python 類別 (Classes)


https://docs.python.org/3/tutorial/classes.html



9. 類   (Classes)
類提供了一種組合資料和功能的方法。創建一個新類意味著創建一個新 類型 的物件,從而允許創建一個該類型的新 實例 。每個類的實例可以擁有保存自己狀態的屬性。一個類的實例也可以有改變自己狀態的(定義在類中的)方法。
和其他程式設計語言相比,Python 用非常少的新語法和語義將類加入到語言中。它是 C++ Modula-3 中類機制的結合。Python 的類提供了物件導向程式設計的所有標準特性:類繼承機制允許多個基類,派生類可以覆蓋它基類的任何方法,一個方法可以調用基類中相同名稱的的方法。物件可以包含任意數量和類型的資料。和模組一樣,類也擁有 Python 天然的動態特性:它們在運行時創建,可以在創建後修改。
C++術語中,通常類成員(包括資料成員)是 public (除了見下文 私有變數 ),所有成員函數都是 virtual 。與在Modula-3中一樣,沒有用於從其方法引用物件成員的簡寫:方法函數使用表示物件的顯式第一個參數聲明,該參數由調用隱式提供。與Smalltalk一樣,類本身也是物件。這為導入和重命名提供了語義。與C++Modula-3不同,內置類型可以用作用戶擴展的基類。此外,與C++一樣,大多數具有特殊語法(算術運算子,下標等)的內置運算子都可以重新定義為類實例。
(Lacking universally accepted terminology to talk about classes, I will make occasional use of Smalltalk and C++ terms. I would use Modula-3 terms, since its object-oriented semantics are closer to those of Python than C++, but I expect that few readers have heard of it.)
9.1. 名稱和對象   (A Word About Names and Objects)


物件具有個性,多個名稱(在多個作用域內)可以綁定到同一個物件。這在其他語言中稱為別名。乍一看Python時通常不會理解這一點,在處理不可變的基本類型(數位,字串,元組)時可以安全地忽略它。但是,別名對涉及可變物件,如清單,字典和大多數其他類型,的Python代碼的語義可能會產生驚人的影響。這通常用於程式的好處,因為別名在某些方面表現得像指針。例如,傳遞一個物件很便宜,因為實現只傳遞一個指標;如果函數修改了作為參數傳遞的物件,調用者將看到更改 --- 這就不需要像 Pascal 中那樣使用兩個不同的參數傳遞機制。
9.2. Python 作用域和命名空間
在介紹類之前,我首先要告訴你一些Python的作用域規則。類定義對命名空間有一些巧妙的技巧,你需要知道作用域和命名空間如何工作才能完全理解正在發生的事情。順便說一下,關於這個主題的知識對任何高級Python程式師都很有用。
讓我們從一些定義開始。
namespace (命名空間)是一個從名字到物件的映射。 大部分命名空間當前都由 Python 字典實現,但一般情況下基本不會去關注它們(除了要面對性能問題時),而且也有可能在將來更改。 下面是幾個命名空間的例子:存放內置函數的集合(包含 abs() 這樣的函數,和內建的異常等);模組中的全域名稱;函式呼叫中的局部名稱。 從某種意義上說,物件的屬性集合也是一種命名空間的形式。 關於命名空間的重要一點是,不同命名空間中的名稱之間絕對沒有關係;例如,兩個不同的模組都可以定義一個 maximize 函數而不會產生混淆 --- 模組的使用者必須在其前面加上模組名稱。
順便說明一下,我把任何跟在一個點號之後的名稱都稱為 屬性 --- 例如,在運算式 z.real 中,real 是物件 z 的一個屬性。按嚴格的說法,對模組中名稱的引用屬於屬性引用:在運算式 modname.funcname 中,modname 是一個模組物件而 funcname 是它的一個屬性。在此情況下在模組的屬性和模組中定義的全域名稱之間正好存在一個直觀的映射:它們共用相同的命名空間! 1
屬性可以是唯讀或者可寫的。如果為後者,那麼對屬性的賦值是可行的。模組屬性是可以寫,你可以寫出 modname.the_answer = 42 。可寫的屬性同樣可以用 del 語句刪除。例如, del modname.the_answer 將會從名為 modname 的物件中移除 the_answer 屬性。
在不同時刻創建的命名空間擁有不同的生存期。包含內置名稱的命名空間是在 Python 解譯器啟動時創建的,永遠不會被刪除。模組的全域命名空間在模組定義被讀入時創建;通常,模組命名空間也會持續到解譯器退出。被解譯器的頂層調用執行的語句,從一個指令檔讀取或互動式地讀取,被認為是 __main__ 模組調用的一部分,因此它們擁有自己的全域命名空間。(內置名稱實際上也存在於一個模組中;這個模組稱作 builtins 。)
一個函數的本地命名空間在這個函數被調用時創建,並在函數返回或拋出一個不在函數內部處理的錯誤時被刪除。(事實上,比起描述到底發生了什麼,忘掉它更好。)當然,每次遞迴呼叫都會有它自己的本地命名空間。
一個 作用域 是一個命名空間可直接訪問的 Python 程式的文本區域。 這裡的可直接訪問意味著對名稱的非限定引用會嘗試在命名空間中查找名稱。
Although scopes are determined statically, they are used dynamically. At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:
  • 最先搜索的最內部作用域包含局部名稱
  • 從最近的封閉作用域開始搜索的任何封閉函數的範圍包含非局部名稱,也包括非全域名稱
  • 倒數第二個作用域包含當前模組的全域名稱
  • 最外面的範圍(最後搜索)是包含內置名稱的命名空間
如果一個名稱被聲明為全域變數,則所有引用和賦值將直接指向包含該模組的全域名稱的中間作用域。 要重新綁定在最內層作用域以外找到的變數,可以使用 nonlocal 語句聲明為非本地變數。 如果沒有被聲明為非本地變數,這些變數將是唯讀的(嘗試寫入這樣的變數只會在最內層作用域中創建一個 新的 區域變數,而同名的外部變數保持不變)。
通常,當前局部作用域將(按字面文本)引用當前函數的局部名稱。 在函數以外,局部作用域將引用與全域作用域相一致的命名空間:模組的命名空間。 類定義將在局部命名空間內再放置另一個命名空間。
重要的是應該意識到作用域是按字面文本來確定的:在一個模組內定義的函數的全域作用域就是該模組的命名空間,無論該函數從什麼地方或以什麼別名被調用。 另一方面,實際的名稱搜索是在運行時動態完成的 --- 但是,語言定義在 編譯時 是朝著靜態名稱解析的方向演化的,因此不要過於依賴動態名稱解析! (事實上,區域變數已經是被靜態確定了。)
Python 的一個特殊之處在於 -- 如果不存在生效的 global 語句 -- 對名稱的賦值總是進入最內層作用域。 賦值不會複製資料 --- 它們只是將名稱綁定到物件。 刪除也是如此:語句 del x 會從局部命名空間的引用中移除對 x 的綁定。 事實上,所有引入新名稱的操作都使用局部作用域:特別地,import 語句和函式定義會在局部作用域中綁定模組或函數名稱。
global 語句可被用來表明特定變數生存於全域作用域並且應當在其中被重新綁定;nonlocal 語句表明特定變數生存於外層作用域中並且應當在其中被重新綁定。
9.2.1. 作用域和命名空間示例
This is an example demonstrating how to reference the different scopes and namespaces, and how global and nonlocal affect variable binding:
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
示例代碼的輸出是:
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
請注意 局部 賦值(這是預設狀態)不會改變 scope_test  spam 的綁定。 nonlocal 賦值會改變 scope_test  spam 的綁定,而 global 賦值會改變模組層級的綁定。
您還可以在 global 賦值之前看到之前沒有 spam 的綁定。
9.3. 初探類
類引入了一些新語法,三種新物件類型和一些新語義。
9.3.1. 類定義語法
最簡單的類定義看起來像這樣:
class ClassName:
    <statement-1>
    .
    .
    .
    <statement-N>
類定義與函式定義 (def 語句) 一樣必須被執行才會起作用。 (你可以嘗試將類定義放在 if 語句的一個分支或是函數的內部。)
在實踐中,類定義內的語句通常都是函式定義,但也允許有其他語句,有時還很有用 --- 我們會稍後再回來說明這個問題。 在類內部的函式定義通常具有一種特別形式的參數列表,這是方法調用的約定規範所指明的 --- 這個問題也將在稍後再說明。
當進入類定義時,將創建一個新的命名空間,並將其用作局部作用域 --- 因此,所有對區域變數的賦值都是在這個新命名空間之內。 特別的,函式定義會綁定到這裡的新函數名稱。
當(從結尾處)正常離開類定義時,將創建一個 類物件 這基本上是一個包圍在類定義所創建命名空間內容周圍的包裝器;我們將在下一節瞭解有關類物件的更多資訊。 原始的(在進入類定義之前起作用的)局部作用域將重新生效,類物件將在這裡被綁定到類定義頭所給出的類名稱 (在這個示例中為 ClassName)
9.3.2. 類對象
類物件支援兩種操作:屬性引用和產生實體。
屬性引用 使用 Python 中所有屬性引用所使用的標準語法obj.name 有效的屬性名稱是類物件被創建時存在於類命名空間中的所有名稱。 因此,如果類定義是這樣的:
class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'
那麼 MyClass.i  MyClass.f 就是有效的屬性引用,將分別返回一個整數和一個函數物件。 類屬性也可以被賦值,因此可以通過賦值來更改 MyClass.i 的值。 __doc__ 也是一個有效的屬性,將返回所屬類的文檔字串"A simple example class"
類的 產生實體 使用函數標記法。 可以把類物件視為是返回該類的一個新實例的不帶參數的函數。 舉例來說(假設使用上述的類):
x = MyClass()
創建類的新 實例 並將此物件分配給區域變數 x
產生實體操作(調用類物件)會創建一個空物件。 許多類喜歡創建帶有特定初始狀態的自訂實例。 為此類定義可能包含一個名為 __init__() 的特殊方法,就像這樣:
def __init__(self):
    self.data = []
當一個類定義了 __init__() 方法時,類的產生實體操作會自動為新創建的類實例發起調用 __init__() 因此在這個示例中,可以通過以下語句獲得一個經初始化的新實例:
x = MyClass()
當然,__init__() 方法還可以有額外參數以實現更高靈活性。 在這種情況下,提供給類產生實體運算子的參數將被傳遞給 __init__() 例如,:
>>> 
>>> class Complex:
...     def __init__(self, realpart, imagpart):
...         self.r = realpart
...         self.i = imagpart
...
>>> x = Complex(3.0, -4.5)
>>> x.r, x.i
(3.0, -4.5)
9.3.3. 實例物件
現在我們可以用實例物件做什麼?實例物件理解的唯一操作是屬性引用。有兩種有效的屬性名稱,資料屬性和方法。
資料屬性 對應於 Smalltalk 中的執行個體變數,以及 C++ 中的資料成員 資料屬性不需要聲明;像區域變數一樣,它們將在第一次被賦值時產生。 例如,如果 x 是上面創建的 MyClass 的實例,則以下程式碼片段將列印數值 16,且不保留任何追蹤資訊:
x.counter = 1
while x.counter < 10:
    x.counter = x.counter * 2
print(x.counter)
del x.counter
另一類實例屬性引用稱為 方法 方法是從屬於物件的函數。 (在 Python 中,方法這個術語並不是類實例所特有的:其他物件也可以有方法。 例如,清單物件具有 append, insert, remove, sort 等方法。 然而,在以下討論中,我們使用方法一詞將專指類實例物件的方法,除非另外顯式地說明。)
實例物件的有效方法名稱依賴於其所屬的類。 根據定義,一個類中所有是函數物件的屬性都是定義了其實例的相應方法。 因此在我們的示例中,x.f 是有效的方法引用,因為 MyClass.f 是一個函數,而 x.i 不是方法,因為 MyClass.i 不是一個函數。 但是 x.f  MyClass.f 並不是一回事 --- 它是一個 方法物件,不是函數物件。
9.3.4. 方法物件
通常,方法在綁定後立即被調用:
x.f()
 MyClass 示例中,這將返回字串 'hello world' 但是,立即調用一個方法並不是必須的x.f 是一個方法物件,它可以被保存起來以後再調用。 例如:
xf = x.f
while True:
    print(xf())
將繼續列印 hello world,直到結束。
當一個方法被調用時到底發生了什麼? 你可能已經注意到上面調用 x.f() 時並沒有帶參數,雖然 f() 的函式定義指定了一個參數。 這個參數發生了什麼事? 當不帶參數地調用一個需要參數的函數時 Python 肯定會引發異常 --- 即使參數實際未被使用...
實際上,你可能已經猜到了答案:方法的特殊之處就在於實例物件會作為函數的第一個參數被傳入。 在我們的示例中,調用 x.f() 其實就相當於 MyClass.f(x) 總之,調用一個具有 n 個參數的方法就相當於調用再多一個參數的對應函數,這個參數值為方法所屬實例物件,位置在其他參數之前。
如果你仍然無法理解方法的運作原理,那麼查看實現細節可能會澄清問題。 當一個實例的非資料屬性被引用時,將搜索實例所屬的類。 如果被引用的屬性名稱表示一個有效的類屬性中的函數物件,會通過打包(指向)查找到的實例物件和函數物件到一個抽象物件的方式來創建方法物件:這個抽象物件就是方法物件。 當附帶參數清單調用方法物件時,將基於實例物件和參數清單構建一個新的參數列表,並使用這個新參數清單調用相應的函數物件。
9.3.5. 類和執行個體變數
一般來說,執行個體變數用於每個實例的唯一資料,而類變數用於類的所有實例共用的屬性和方法:
class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind                  # shared by all dogs
'canine'
>>> e.kind                  # shared by all dogs
'canine'
>>> d.name                  # unique to d
'Fido'
>>> e.name                  # unique to e
'Buddy'
正如 名稱和對象 中已討論過的,共用資料可能在涉及 mutable 物件例如清單和字典的時候導致令人驚訝的結果。 例如以下代碼中的 tricks 列表不應該被用作類變數,因為所有的 Dog 實例將只共用一個單獨的列表:
class Dog:

    tricks = []             # mistaken use of a class variable

    def __init__(self, name):
        self.name = name

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks                # unexpectedly shared by all dogs
['roll over', 'play dead']
正確的類設計應該使用執行個體變數:
class Dog:

    def __init__(self, name):
        self.name = name
        self.tricks = []    # creates a new empty list for each dog

    def add_trick(self, trick):
        self.tricks.append(trick)

>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
9.4. 補充說明
如果同樣的屬性名稱同時出現在實例和類中,則屬性查找會優先選擇實例:
>>> 
>>> class Warehouse:
        purpose = 'storage'
        region = 'west'

>>> w1 = Warehouse()
>>> print(w1.purpose, w1.region)
storage west
>>> w2 = Warehouse()
>>> w2.region = 'east'
>>> print(w2.purpose, w2.region)
storage east
資料屬性可以被方法以及一個物件的普通使用者(用戶端)所引用。 換句話說,類不能用於實現純抽象資料類型。 實際上,在 Python 中沒有任何東西能強制隱藏資料 --- 它是完全基於約定的。 (而在另一方面,用 C 語言編寫的 Python 實現則可以完全隱藏實現細節,並在必要時控制物件的訪問;此特性可以通過用 C 編寫 Python 擴展來使用。)
用戶端應當謹慎地使用資料屬性 --- 用戶端可能通過直接運算元據屬性的方式破壞由方法所維護的固定變數。 請注意用戶端可以向一個實例物件添加他們自己的資料屬性而不會影響方法的可用性,只要保證避免名稱衝突 --- 再次提醒,在此使用命名約定可以省去許多令人頭痛的麻煩。
在方法內部引用資料屬性(或其他方法!)並沒有簡便方式。 我發現這實際上提升了方法的可讀性:當流覽一個方法代碼時,不會存在混淆區域變數和執行個體變數的機會。
方法的第一個參數常常被命名為 self 這也不過就是一個約定self 這一名稱在 Python 中絕對沒有特殊含義。 但是要注意,不遵循此約定會使得你的代碼對其他 Python 程式師來說缺乏可讀性,而且也可以想像一個 類流覽器 程式的編寫可能會依賴於這樣的約定。
任何一個作為類屬性的函數都為該類的實例定義了一個相應方法。 函式定義的文本並非必須包含于類定義之內:將一個函數物件賦值給一個區域變數也是可以的。 例如:
# Function defined outside the class
def f1(self, x, y):
    return min(x, x+y)

class C:
    f = f1

    def g(self):
        return 'hello world'

    h = g
現在 fg  h 都是 C 類的引用函數物件的屬性,因而它們就都是 C 的實例的方法 --- 其中 h 完全等同於 g 但請注意,本示例的做法通常只會令程式的閱讀者感到迷惑。
方法可以通過使用 self 參數的方法屬性調用其他方法:
class Bag:
    def __init__(self):
        self.data = []

    def add(self, x):
        self.data.append(x)

    def addtwice(self, x):
        self.add(x)
        self.add(x)
方法可以通過與普通函數相同的方式引用全域名稱。 與方法相關聯的全域作用域就是包含其定義的模組。 (類永遠不會被作為全域作用域。) 雖然我們很少會有充分的理由在方法中使用全域作用域,但全域作用域存在許多合法的使用場景:舉個例子,導入到全域作用域的函數和模組可以被方法所使用,在其中定義的函數和類也一樣。 通常,包含該方法的類本身是在全域作用域中定義的,而在下一節中我們將會發現為何方法需要引用其所屬類的很好的理由。
每個值都是一個物件,因此具有  (也稱為 類型),並存儲為 object.__class__ 
9.5. 繼承
當然,如果不支援繼承,語言特性就不值得稱為。派生類定義的語法如下所示:
class DerivedClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>
名稱 BaseClassName 必須定義於包含派生類定義的作用域中。 也允許用其他任意運算式代替基類名稱所在的位置。 這有時也可能會用得上,例如,當基類定義在另一個模組中的時候:
class DerivedClassName(modname.BaseClassName):
派生類定義的執行過程與基類相同。 當構造類物件時,基類會被記住。 此資訊將被用來解析屬性引用:如果請求的屬性在類中找不到,搜索將轉往基類中進行查找。 如果基類本身也派生自其他某個類,則此規則將被遞迴地應用。
派生類的產生實體沒有任何特殊之處DerivedClassName() 會創建該類的一個新實例。 方法引用將按以下方式解析:搜索相應的類屬性,如有必要將按基類繼承鏈逐步向下查找,如果產生了一個函數物件則方法引用就生效。
派生類可能會重載其基類的方法。 因為方法在調用同一物件的其他方法時沒有特殊許可權,調用同一基類中定義的另一方法的基類方法最終可能會調用覆蓋它的派生類的方法。 (對 C++ 程式師的提示:Python 中所有的方法實際上都是 virtual 方法。)
在派生類中的重載方法實際上可能想要擴展而非簡單地替換同名的基類方法。 有一種方式可以簡單地直接調用基類方法:即調用 BaseClassName.methodname(self, arguments) 有時這對用戶端來說也是有用的。 (請注意僅當此基類可在全域作用域中以 BaseClassName 的名稱被訪問時方可使用此方式。)
Python有兩個內置函數可被用於繼承機制:
  • 使用 isinstance() 來檢查一個實例的類型isinstance(obj, int) 僅會在 obj.__class__  int 或某個派生自 int 的類時為 True
  • 使用 issubclass() 來檢查類的繼承關係issubclass(bool, int)  True,因為 bool  int 的子類。 但是,issubclass(float, int)  False,因為 float 不是 int 的子類。
9.5.1. 多重繼承
Python supports a form of multiple inheritance as well. A class definition with multiple base classes looks like this:
class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>
對於多數應用來說,在最簡單的情況下,你可以認為搜索從父類所繼承屬性的操作是深度優先、從左至右的,當層次結構中存在重疊時不會在同一個類中搜索兩次。 因此,如果某一屬性在 DerivedClassName 中未找到,則會到 Base1 中搜索它,然後(遞迴地)到 Base1 的基類中搜索,如果在那裡未找到,再到 Base2 中搜索,依此類推。
真實情況比這個更複雜一些;方法解析順序會動態改變以支援對 super() 的協同調用。 這種方式在某些其他多重繼承型語言中被稱為後續方法調用,它比單繼承型語言中的 super 調用更強大。
動態改變順序是有必要的,因為所有多重繼承的情況都會顯示出一個或更多的菱形關聯(即至少有一個父類可通過多條路徑被最底層類所訪問)。 例如,所有類都是繼承自 object,因此任何多重繼承的情況都提供了一條以上的路徑可以通向 object 為了確保基類不會被訪問一次以上,動態演算法會用一種特殊方式將搜索順序線性化, 保留每個類所指定的從左至右的順序,只調用每個父類一次,並且保持單調(即一個類可以被子類化而不影響其父類的優先順序)。 總而言之,這些特性使得設計具有多重繼承的可靠且可擴展的類成為可能。 要瞭解更多細節,請參閱 https://www.python.org/download/releases/2.3/mro/
9.6. 私有變數
那種僅限從一個物件內部訪問的私有執行個體變數在 Python 中並不存在。 但是,大多數 Python 代碼都遵循這樣一個約定:帶有一個底線的名稱 (例如 _spam) 應該被當作是 API 的非僅供部分 (無論它是函數、方法或是資料成員) 這應當被視為一個實現細節,可能不經通知即加以改變。
由於存在對於類私有成員的有效使用場景(例如避免名稱與子類所定義的名稱相衝突),因此存在對此種機制的有限支持,稱為 名稱改寫 任何形式為 __spam 的識別字(至少帶有兩個首碼底線,至多一個尾碼底線)的文本將被替換為 _classname__spam,其中 classname 為去除了首碼底線的當前類名稱。 這種改寫不考慮識別字的句法位置,只要它出現在類定義內部就會進行。
名稱改寫有助於讓子類重載方法而不破壞類內方法調用。例如:
class Mapping:
    def __init__(self, iterable):
        self.items_list = []
        self.__update(iterable)

    def update(self, iterable):
        for item in iterable:
            self.items_list.append(item)

    __update = update   # private copy of original update() method

class MappingSubclass(Mapping):

    def update(self, keys, values):
        # provides new signature for update()
        # but does not break __init__()
        for item in zip(keys, values):
            self.items_list.append(item)
上面的示例即使在 MappingSubclass 引入了一個 __update 識別字的情況下也不會出錯,因為它會在 Mapping 類中被替換為 _Mapping__update 而在 MappingSubclass 類中被替換為 _MappingSubclass__update
請注意,改寫規則的設計主要是為了避免意外衝突;訪問或修改被視為私有的變數仍然是可能的。這在特殊情況下甚至會很有用,例如在調試器中。
請注意傳遞給 exec()  eval() 的代碼不會將發起調用類的類名視作當前類;這類似於 global 語句的效果,因此這種效果僅限於同時經過位元組碼編譯的代碼。 同樣的限制也適用於 getattr()setattr()  delattr(),以及對於 __dict__ 的直接引用。
9.7. 雜項說明
有時會需要使用類似於 Pascal “record” C “struct”這樣的資料類型,將一些命名資料項目捆綁在一起。 這種情況適合定義一個空類:
class Employee:
    pass

john = Employee()  # Create an empty employee record

# Fill the fields of the record
john.name = 'John Doe'
john.dept = 'computer lab'
john.salary = 1000
一段需要特定抽象資料類型的 Python 代碼往往可以被傳入一個模擬了該資料類型的方法的類作為替代。 例如,如果你有一個基於檔物件來格式化某些資料的函數,你可以定義一個帶有 read()  readline() 方法從字串緩存獲取資料的類,並將其作為參數傳入。
實例方法物件也具有屬性m.__self__ 就是帶有 m() 方法的實例物件,而 m.__func__ 則是該方法所對應的函數物件。
9.8. 反覆運算器
到目前為止,您可能已經注意到大多數容器物件都可以使用 for 語句:
for element in [1, 2, 3]:
    print(element)
for element in (1, 2, 3):
    print(element)
for key in {'one':1, 'two':2}:
    print(key)
for char in "123":
    print(char)
for line in open("myfile.txt"):
    print(line, end='')
這種訪問風格清晰、簡潔又方便。 反覆運算器的使用非常普遍並使得 Python 成為一個統一的整體。 在幕後,for 語句會調用容器物件中的 iter() 該函數返回一個定義了 __next__() 方法的反覆運算器物件,該方法將逐一訪問容器中的元素。 當元素用盡時,__next__() 將引發 StopIteration 異常來通知終止 for 迴圈。 你可以使用 next() 內置函數來調用 __next__() 方法;這個例子顯示了它的運作方式:
>>> 
>>> s = 'abc'
>>> it = iter(s)
>>> it
<iterator object at 0x00A1DB50>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    next(it)
StopIteration
看過反覆運算器協議的幕後機制,給你的類添加反覆運算器行為就很容易了。 定義一個 __iter__() 方法來返回一個帶有 __next__() 方法的物件。 如果類已定義了 __next__(),則 __iter__() 可以簡單地返回 self:
class Reverse:
    """Iterator for looping over a sequence backwards."""
    def __init__(self, data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index = self.index - 1
        return self.data[self.index]
>>> 
>>> rev = Reverse('spam')
>>> iter(rev)
<__main__.Reverse object at 0x00A1DB50>
>>> for char in rev:
...     print(char)
...
m
a
p
s
9.9. 生成器
Generator 是一個用於創建反覆運算器的簡單而強大的工具。 它們的寫法類似標準的函數,但當它們要返回資料時會使用 yield 語句。 每次對生成器調用 next() 時,它會從上次離開位置恢復執行(它會記住上次執行語句時的所有資料值)。 顯示如何非常容易地創建生成器的示例如下:
def reverse(data):
    for index in range(len(data)-1, -1, -1):
        yield data[index]
>>> 
>>> for char in reverse('golf'):
...     print(char)
...
f
l
o
g
可以用生成器來完成的操作同樣可以用前一節所描述的基於類的反覆運算器來完成。 但生成器的寫法更為緊湊,因為它會自動創建 __iter__()  __next__() 方法。
另一個關鍵特性在於區域變數和執行狀態會在每次調用之間自動保存。 這使得該函數相比使用 self.index  self.data 這種執行個體變數的方式更易編寫且更為清晰。
除了會自動創建方法和保存程式狀態,當生成器終結時,它們還會自動引發 StopIteration 這些特性結合在一起,使得創建反覆運算器能與編寫常規函數一樣容易。
9.10. 生成器運算式
某些簡單的生成器可以寫成簡潔的運算式代碼,所用語法類似清單推導式,將外層為圓括號而非方括號。 這種運算式被設計用於生成器將立即被外層函數所使用的情況。 生成器運算式相比完整的生成器更緊湊但較不靈活,相比等效的列表推導式則更為節省記憶體。
例如:
>>> 
>>> sum(i*i for i in range(10))                 # sum of squares
285

>>> xvec = [10, 20, 30]
>>> yvec = [7, 5, 3]
>>> sum(x*y for x,y in zip(xvec, yvec))         # dot product
260

>>> unique_words = set(word for line in page  for word in line.split())

>>> valedictorian = max((student.gpa, student.name) for student in graduates)

>>> data = 'golf'
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']
註腳
1
存在一個例外。 模組物件有一個秘密的唯讀屬性 __dict__,它返回用於實現模組命名空間的字典;__dict__ 是屬性但不是全域名稱。 顯然,使用這個將違反命名空間實現的抽象,應當僅被用於事後調試器之類的場合。


print(dir(urllib.request.urlopen(url))) 實作

import urllib.request url = 'http://www.baidu.com/' response = urllib.request.urlopen(url) print(type(response)) print(dir(...