Python學習備忘錄

來源:互聯網
上載者:User

來源:http://blog.csdn.net/nilxin/article/details/1613574

類中的特殊方法

一般說來,特殊的方法都被用來模仿某個行為。例如,如果你想要為你的類使用x[key]這樣的索引操作(就像列表和元組一樣),那麼你只需要實現__getitem__()方法就可以了。想一下,Python就是對list類這樣做的!

下面這個表中列出了一些有用的特殊方法。如果你想要知道所有的特殊方法,你可以在《Python參考手冊》中找到一個龐大的列表。

名稱                     說明
---------------------------------------------------------
__init__(self,...)      這個方法在建立對象恰好要被返回使用之前被調用。
__del__(self)           恰好在對象要被刪除之前調用。
__str__(self)           在我們對對象使用print語句或是使用str()的時候調用。
__lt__(self,other)      當使用 小於 運算子(<)的時候調用。類似地,對於所有的運算子(+,>等等)都有特殊的方法。
__getitem__(self,key)   使用x[key]索引操作符的時候調用。
__len__(self)           對序列對象使用內建的len()函數的時候調用。
__repr__(s)             repr() and `...` conversions
__cmp__(s, o)           Compares s to o and returns <0, 0, or >0.
                        Implements >, <, == etc...
__hash__(s)             Compute a 32 bit hash code; hash() and dictionary ops
__nonzero__(s)          Returns 0 or 1 for truth value testing
__getattr__(s, name)    called when attr lookup doesn't find <name>
__setattr__(s, name, val) called when setting an attr
                        (inside, don't use "self.name = value"
                        use "self.__dict__[name] = val")
__delattr__(s, name)    called to delete attr <name>
__call__(self, *args)   called when an instance is called as function.

exec和eval語句

exec語句用來執行儲存在字串或檔案中的Python語句。例如,我們可以在運行時產生一個包含Python代碼的字串,然後使用exec語句執行這些語句。

下面是一個簡單的例子。

>>> exec 'print "Hello World"'
Hello World

eval語句用來計算儲存在字串中的有效Python運算式。下面是一個簡單的例子。

>>> eval('2*3')
6

assert語句

assert語句用來聲明某個條件是真的。例如,如果你非常確信某個你使用的列表中至少有一個元素,而你想要檢驗這一點,並且在它非真的時候引發一個錯誤,那麼assert語句是應用在這種情形下的理想語句。當assert語句失敗的時候,會引發一個AssertionError。

>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> assert len(mylist) >= 1
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError repr函數

repr函數用來取得對象的規範字串表示。反引號(也稱轉換符)可以完成相同的功能。注意,在大多數時候有eval(repr(object)) == object。

>>> i = []
>>> i.append('item')
>>> `i`
"['item']"
>>> repr(i)
"['item']"

基本上,repr函數和反引號用來擷取對象的可列印的表示形式。你可以通過定義類的__repr__方法來控制你的對象在被repr函數調用的時候返回的內容。

類和執行個體變數

有兩種類型的域 —— 類的變數和對象的變數,它們根據是類還是對象擁有這個變數而區分。

類的變數 由一個類的所有對象(執行個體)共用使用。只有一個類變數的拷貝,所以當某個對象對類的變數做了改動的時候,這個改動會反映到所有其他的執行個體上。

對象的變數 由類的每個對象/執行個體擁有。因此每個對象有自己對這個域的一份拷貝,即它們不是共用的,在同一個類的不同執行個體中,雖然對象的變數有相同的名稱,但是是互不相關的。通過一個例子會使這個易於理解。

#!/usr/bin/python
# Filename: objvar.py

class Person:
    '''Represents a person.'''
    population = 0

    def __init__(self, name):
        '''Initializes the person's data.'''
        self.name = name
        print '(Initializing %s)' % self.name

        # When this person is created, he/she
        # adds to the population
        Person.population += 1

    def __del__(self):
        '''I am dying.'''
        print '%s says bye.' % self.name

        Person.population -= 1

        if Person.population == 0:
            print 'I am the last one.'
        else:
            print 'There are still %d people left.' % Person.population

    def sayHi(self):
        '''Greeting by the person.

        Really, that's all it does.'''
        print 'Hi, my name is %s.' % self.name

    def howMany(self):
        '''Prints the current population.'''
        if Person.population == 1:
            print 'I am the only person here.'
        else:
            print 'We have %d persons here.' % Person.population

swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()

kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()

swaroop.sayHi()
swaroop.howMany()輸出

___FCKpd___5nbsp;python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one.

這是一個很長的例子,但是它有助於說明類與對象的變數的本質。這裡,population屬於Person類,因此是一個類的變數。name變數屬於對象(它使用self賦值)因此是對象的變數。

觀察可以發現__init__方法用一個名字來初始化Person執行個體。在這個方法中,我們讓population增加1,這是因為我們增加了一個人。同樣可以發現,self.name的值根據每個對象指定,這表明了它作為對象的變數的本質。

記住,你只能使用self變數來參考同一個對象的變數和方法。這被稱為 屬性參考 。

在這個程式中,我們還看到docstring對於類和方法同樣有用。我們可以在運行時使用Person.__doc__和Person.sayHi.__doc__來分別訪問類與方法的文檔字串。

就如同__init__方法一樣,還有一個特殊的方法__del__,它在對象消逝的時候被調用。對象消逝即對象不再被使用,它所佔用的記憶體將返回給系統作它用。在這個方法裡面,我們只是簡單地把Person.population減1。

當對象不再被使用時,__del__方法運行,但是很難保證這個方法究竟在什麼時候運行。如果你想要指明它的運行,你就得使用del語句,就如同我們在以前的例子中使用的那樣。

給C++/Java/C#程式員的注釋

Python中所有的類成員(包括資料成員)都是公用的 ,所有的方法都是有效。

只有一個例外:如果你使用的資料成員名稱以雙底線首碼 比如__privatevar,Python的名稱管理體系會有效地把它作為私人變數。

這樣就有一個慣例,如果某個變數只想在類或對象中使用,就應該以單底線首碼。而其他的名稱都將作為公用的,可以被其他類/對象使用。記住這隻是一個慣例,並不是Python所要求的(與雙底線首碼不同)。

同樣,注意__del__方法與destructor的概念類似。

繼承

物件導向的編程帶來的主要好處之一是代碼的重用,實現這種重用的方法之一是通過繼承機制。繼承完全可以理解成類之間的類型和子類型關係。

假設你想要寫一個程式來記錄學校之中的教師和學生情況。他們有一些共同屬性,比如姓名、年齡和地址。他們也有專有的屬性,比如教師的薪水、課程和假期,學生的成績和學費。

你可以為教師和學生建立兩個獨立的類來處理它們,但是這樣做的話,如果要增加一個新的共有屬性,就意味著要在這兩個獨立的類中都增加這個屬性。這很快就會顯得不實用。

一個比較好的方法是建立一個共同的類稱為SchoolMember然後讓教師和學生的類繼承 這個共同的類。即它們都是這個類型(類)的子類型,然後我們再為這些子類型添加專有的屬性。

使用這種方法有很多優點。如果我們增加/改變了SchoolMember中的任何功能,它會自動地反映到子類型之中。例如,你要為教師和學生都增加一個新的身份證域,那麼你只需簡單地把它加到SchoolMember類中。然而,在一個子類型之中做的改動不會影響到別的子類型。另外一個優點是你可以把教師和學生對象都作為SchoolMember對象來使用,這在某些場合特別有用,比如統計學校成員的人數。一個子類型在任何需要父類型的場合可以被替換成父類型,即對象可以被視作是父類的執行個體,這種現象被稱為多態現象。

另外,我們會發現在重用父類的代碼的時候,我們無需在不同的類中重複它。而如果我們使用獨立的類的話,我們就不得不這麼做了。

在上述的場合中,SchoolMember類被稱為基本類或超類 。而Teacher和Student類被稱為匯出類或子類 。

現在,我們將學習一個例子程式。

使用繼承

#!/usr/bin/python

# Filename: inherit.py


class SchoolMember:

'''Represents any school member.'''

def __init__(self, name, age):

        self.name = name

        self.age = age

print '(Initialized SchoolMember: %s)' % self.name


def tell(self):

'''Tell my details.'''

print 'Name:"%s" Age:"%s"' % (self.name, self.age),


class Teacher(SchoolMember):

'''Represents a teacher.'''

def __init__(self, name, age, salary):

        SchoolMember.__init__(self, name, age)

        self.salary = salary

print '(Initialized Teacher: %s)' % self.name


def tell(self):

        SchoolMember.tell(self)

print 'Salary: "%d"' % self.salary


class Student(SchoolMember):

'''Represents a student.'''

def __init__(self, name, age, marks):

        SchoolMember.__init__(self, name, age)

        self.marks = marks

print '(Initialized Student: %s)' % self.name


def tell(self):

        SchoolMember.tell(self)

print 'Marks: "%d"' % self.marks


t = Teacher('Mrs. Shrividya', 40, 30000)

s = Student('Swaroop', 22, 75)


print # prints a blank line


members = [t, s]

for member in members:

    member.tell() # works for both Teachers and Students輸出


$ python inherit.py

(Initialized SchoolMember: Mrs. Shrividya)

(Initialized Teacher: Mrs. Shrividya)

(Initialized SchoolMember: Swaroop)

(Initialized Student: Swaroop)


Name:"Mrs. Shrividya" Age:"40" Salary: "30000"

Name:"Swaroop" Age:"22" Marks: "75"

為了使用繼承,我們把基本類的名稱作為一個元組跟在定義類時的類名稱之後。然後,我們注意到基本類的__init__方法專門使用self變數調用,這樣我們就可以初始化對象的基本類部分。這一點十分重要——Python不會自動調用基本類的constructor,你得親自專門調用它。

我們還觀察到我們在方法調用之前加上類名稱首碼,然後把self變數及其他參數傳遞給它。

注意,在我們使用SchoolMember類的tell方法的時候,我們把Teacher和Student的執行個體僅僅作為SchoolMember的執行個體。

另外,在這個例子中,我們調用了子類型的tell方法,而不是SchoolMember類的tell方法。可以這樣來理解,Python總是首先尋找對應類型的方法,在這個例子中就是如此。如果它不能在匯出類中找到對應的方法,它才開始到基本類中逐個尋找。基本類是在類定義的時候,在元組之中指明的。

一個術語的注釋——如果在繼承元組中列了一個以上的類,那麼它就被稱作多重繼承 。

字串

字串是字元的序列。字串基本上就是一組單詞。

我幾乎可以保證你在每個Python程式中都要用到字串,所以請特別留心下面這部分的內容。下面告訴你如何在Python中使用字串。

* 使用單引號(')

你可以用單引號指示字串,就如同'Quote me on this'這樣。所有的空白,即空格和定位字元都照原樣保留。

* 使用雙引號(")

在雙引號中的字串與單引號中的字串的使用完全相同,例如"What's your name?"。

* 使用三引號('''或""")

利用三引號,你可以指示一個多行的字串。你可以在三引號中自由的使用單引號和雙引號。例如:

'''This is a multi-line string. This is the first line.

This is the second line.

"What's your name?," I asked.

He said "Bond, James Bond."

'''

* 轉義符

假設你想要在一個字串中包含一個單引號('),那麼你該怎麼指示這個字串?例如,這個字串是What's your name?。你肯定不會用'What's your name?'來指示它,因為Python會弄不明白這個字串從何處開始,何處結束。所以,你需要指明單引號而不是字串的結尾。可以通過 轉義符 來完成這個任務。你用/'來指示單引號——注意這個反斜線。現在你可以把字串表示為'What/'s your name?'。

另一個表示這個特別的字串的方法是"What's your name?",即用雙引號。類似地,要在雙引號字串中使用雙引號本身的時候,也可以藉助於轉義符。另外,你可以用轉義符//來指示反斜線本身。

值得注意的一件事是,在一個字串中,行末的單獨一個反斜線表示字串在下一行繼續,而不是開始一個新的行。例如:

"This is the first sentence./

This is the second sentence."

等價於"This is the first sentence. This is the second sentence."

* 自然字串

如果你想要指示某些不需要如轉義符那樣的特別處理的字串,那麼你需要指定一個自然字串。自然字串通過給字串加上首碼r或R來指定。例如r"Newlines are indicated by /n"。

* Unicode字串

Unicode是書寫國際文本的標準方法。如果你想要用你的母語如北印度語或阿拉伯語寫文本,那麼你需要有一個支援Unicode的編輯器。類似地,Python允許你處理Unicode文本——你只需要在字串前加上首碼u或U。例如,u"This is a Unicode string."。

記住,在你處理文字檔的時候使用Unicode字串,特別是當你知道這個檔案含有用非英語的語言寫的文本。

* 字串是不可變的

這意味著一旦你創造了一個字串,你就不能再改變它了。雖然這看起來像是一件壞事,但實際上它不是。我們將會在後面的程式中看到為什麼我們說它不是一個缺點。

* 按字面意義級連字號串

如果你把兩個字串按字面意義相鄰放著,他們會被Python自動級連。例如,'What/'s' 'your name?'會被自動轉為"What's your name?"。

給C/C++程式員的注釋

在Python中沒有專門的char資料類型。確實沒有需要有這個類型,我相信你不會為此而煩惱。

給Perl/PHP程式員的注釋

記住,單引號和雙引號字串是完全相同的——它們沒有在任何方面有不同。

給Regex使用者的注釋

一定要用自然字串處理Regex。否則會需要使用很多的反斜線。例如,後向引用符可以寫成'//1'或r'/1'。

私人變數

Python對私人類成員有部分支援。任何象__spam這樣形式的標識符(至少有兩個前置底線,至多有一個結尾底線)目前被替換成_classname__spam,其中classname是所屬類名去掉前置底線的結果。這種攪亂不管標識符的文法位置,所以可以用來定義類私人的執行個體、變數、方法,以及全域變數,甚至於儲存對於此類是私人的其它類的執行個體。如果攪亂的名字超過255個字元可能會發生截斷。在類外面或類名只有底線時不進行攪亂。

名字攪亂的目的是給類一種定義“私人”執行個體變數和方法的簡單方法,不需擔心它的其它類會定義同名變數,也不怕類外的代碼弄亂執行個體的變數。注意攪亂規則主要是為了避免偶然的錯誤,如果你一定想做的話仍然可以訪問或修改私人變數。這甚至是有用的,比如偵錯工具要用到私人變數,這也是為什麼這個漏洞沒有堵上的一個原因。(小錯誤:匯出類和基類取相同的名字就可以使用基類的私人變數)。

注意傳遞給exec,eval()或evalfile()的代碼不會認為調用它們的類的類名是當前類,這與global語句的情況類似,global的作用局限於一起位元組編譯的代碼。同樣的限制也適用於getattr() ,setattr()和delattr(),以及直接存取__dict__的時候。

下面例子中的類實現了自己的__getattr__和__setattr__方法,把所有屬性儲存在一個私人變數中,這在Python的新舊版本中都是可行的:

class VirtualAttributes:
    __vdict = None
    __vdict_name = locals().keys()[0]
    
    def __init__(self):
        self.__dict__[self.__vdict_name] = {}
   
    def __getattr__(self, name):
        return self.__vdict[name]
   
    def __setattr__(self, name, value):
        self.__vdict[name] = value

參考資料:

http://www.e7blog.com/blog/user1/python/

http://www.czug.org/docs/python/TutorialCN/X_e7_ac_ac_e4_b9_9d_e7_ab_a0_e7_b1_bb/

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.