天天看點

Python面向對象程式設計面向對象程式設計

文章目錄

  • 面向對象程式設計
    • 類和執行個體
    • 通路限制
    • 繼承和多态
      • 鴨子類型
    • 擷取對象資訊
      • 使用type()判斷
      • 使用isinstance
      • 使用dir()
      • getattr()`、`setattr()`以及`hasattr()
    • 執行個體屬性和類屬性

面向對象程式設計

類和執行個體

和Java一樣,把類作為程式設計的基本機關。

以Class為基本機關,裡面包括屬性和方法。

例如,學生類:

class Student(object):

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

    def print_score(self):
        print('%s: %s' % (self.name, self.score))
           

括号中的(Object)指的是繼承下來的類。

bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
           

此處的bart是類的一個執行個體化,也就是通過類創造了對象。

通過定義一個特殊的

__init__

方法,在建立執行個體的時候,就把

name

score

等屬性綁上去:

注:__init__

方法的第一個參數永遠是

self

,表示建立的執行個體本身,是以,在

__init__

方法内部,就可以把各種屬性綁定到

self

,因為

self

就指向建立的執行個體本身。(類似于java的this)

無論是什麼方法,第一個參數都得是self

通路限制

如果要讓内部屬性不被外部通路,可以把屬性的名稱前加上兩個下劃線

__

,在Python中,執行個體的變量名如果以

__

開頭,就變成了一個私有變量(private),隻有内部可以通路,外部不能通路

注:在Python中,變量名類似

__xxx__

的,也就是以雙下劃線開頭,并且以雙下劃線結尾的,是特殊變量,特殊變量是可以直接通路的,不是private變量,是以,不能用

__name__

__score__

這樣的變量名。

繼承和多态

繼承:直接擷取父類的屬性和變量

多态:子類方法可以覆寫父類同名方法,同時,父類作為參數的函數或者方法都可以不加修改地正常運作,原因就在于多态。

動态語言的鴨子類型特點決定了繼承不像靜态語言那樣是必須的。

鴨子類型

調用對象不看類型,隻看方法。

比如:

function calculate(a, b, c) => return (a+b)*c
 
example1 = calculate (1, 2, 3)
example2 = calculate ([1, 2, 3], [4, 5, 6], 2)
example3 = calculate ('apples ', 'and oranges, ', 3)
 
print to_string example1
print to_string example2
print to_string example3
           

其中的example3其實是不合理的,因為對于calculate函數所針對的對象應當是一個數。但是,因為str類型支援‘+’,是以這個函數可以執行。

運作結果:

9
[1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
apples and oranges, apples and oranges, apples and oranges, 
           

那麼,不要求str繼承int或者float類型,隻要支援*和+兩個方法就可以了。

再例如:

class Duck:
    def quack(self):
        print("這鴨子在呱呱叫")

    def feathers(self):
        print("這鴨子擁有白色與灰色羽毛")


class Person:
    def quack(self):
        print("這人正在模仿鴨子")

    def feathers(self):
        print("這人在地上拿起1根羽毛然後給其他人看")


def in_the_forest(duck):
    duck.quack()
    duck.feathers()


def game():
    donald = Duck()
    john = Person()
    in_the_forest(donald)
    in_the_forest(john) # 此處的代碼在java中無法運作,in_the_forset的參數是duck,但是john是個人。但是在python中這句代碼可以運作。python隻通路需要的方法,是以隻要函數中調用的方法在參數中存在就可以執行


game()

           

鴨子類型,讓python在不繼承的情況下,也可以使用多态的特性。

擷取對象資訊

使用type()判斷

用法:

>>> type(123)
<class 'int'>
>>> type(str)
<class 'type'>
>>> type('str')
<class 'str'>
           

要判斷一個對象是否是函數怎麼辦?可以使用

types

子產品中定義的常量:

>>> import types
>>> def fn():
...     pass
...
>>> type(fn)==types.FunctionType # 函數類型
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType # lambdaType類型
True
>>> type((x for x in range(10)))==types.GeneratorType # 生成器類型
True
           

使用isinstance

insinstance()可以用來判斷執行個體和類之間的關系。

用法:isinstance(對象,類),如果對象屬于該類就是True,不屬于就是False

如果:

object -> Animal -> Dog -> Husky
           

>>> class Animal(object):
...     pass
...
>>> class Dog(Animal):
...     pass
...
>>> class Baby(Dog):
...     pass
...
>>> MT = Baby()
>>> isinstance(MT, Dog)
True
           

使用dir()

使用dir()可以擷取一個對象所有的屬性和方法

>>> dir('abc')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__ge
tnewargs__', '__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', 'isdigi
t', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition'
, 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
 'swapcase', 'title', 'translate', 'upper', 'zfill']

           

我們自己寫的類,也可以加一些常用方法,比如

__len__

方法傳回長度。在Python中,如果你調用

len()

函數試圖擷取一個對象的長度,實際上,在

len()

函數内部,它自動去調用該對象的

__len__()

方法,是以,下面的代碼是等價的。我們自己寫的類,如果也想用

len(myObj)

的話,就自己寫一個

__len__()

方法:

>>> class MyDog(object):
...     def __len__(self):
...         return 100
...
>>> dog = MyDog()
>>> len(dog)
100
           

getattr()

setattr()

以及

hasattr()

用法:getattr(類對象,屬性)

getattr()傳回某個屬性的值,如果試圖擷取不存在的屬性,會抛出AttributeError的錯誤。

如果不想抛出錯誤,可以傳入一個default參數,如果屬性不存在,就傳回預設值。

setattr(對象,屬性,值)

添加一個屬性并設定他的值

hasattr()

判斷某對象是否存在一個屬性

例如,對于類Myobject:

>>> class MyObject(object):
...     def __init__(self):
...         self.x = 9
...     def power(self):
...         return self.x * self.x
...
>>> obj = MyObject()
           
>>> hasattr(obj, 'x') # 有屬性'x'嗎?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
False
>>> setattr(obj, 'y', 19) # 設定一個屬性'y'
>>> hasattr(obj, 'y') # 有屬性'y'嗎?
True
>>> getattr(obj, 'y') # 擷取屬性'y'
19
>>> obj.y # 擷取屬性'y'
19
>>> getattr(obj, 'z', 404) # 擷取屬性'z',如果不存在,傳回預設值404
404
           

執行個體屬性和類屬性

就類似Iava的靜态屬性。屬于類的屬性。

給執行個體綁定屬性的方法是通過執行個體變量,或者通過

self

變量:

class Student(object):
    def __init__(self, name):# 通過self變量
        self.name = name 

s = Student('Bob')
s.score = 90 # 通過執行個體變量
           

同時,也可以給執行個體綁定一個方法。

>>> def set_age(self, age): # 定義一個函數作為執行個體方法
...     self.age = age
...
>>> from types import MethodType # 這個類型是Python自帶的方法
>>> s.set_age = MethodType(set_age, s) # 給執行個體綁定一個方法
>>> s.set_age(25) # 調用執行個體方法
>>> s.age # 測試結果
25
           

通過Python自帶的方法進行綁定。

如果

Student

類本身需要綁定一個屬性呢?可以直接在class中定義屬性,這種屬性是類屬性,歸

Student

類所有:

class Student(object):
    name = 'Student'
           

這個屬性,所有的對象都可以通路。