Python基礎刻意練習:類與對象

本系列定位爲複習筆記,某些內容並未提及。
在此記錄一些典型疑問和我在學習中的問題或經常遺忘的細節,也會添加一些覺得有意思的部分(其實就是隨心所欲

對象

在這裏插入圖片描述
python無處不對象,對象是類的實例化
類包含屬性和方法,實例對象也包含屬性和方法,類本身也是一個類對象,類是type的實例化對象
通過將類實例化,如定義一個魚類,我們就能得到多個魚對象,並對個魚對象進行相應的屬性與方法的操作,如賦予每條魚不同的座標等。

定義類

Python中的類名約定以大寫字母開頭

屬性及烏龜的顏色,體重等特徵
方法則對應我的烏龜對象可以有哪些操作

通過.來對方法或屬性進行訪問
class關鍵字
定義一隻烏龜:

class Turtle:
    # 定義屬性
    color = 'green'
    weight = 10
    legs = 4
    shell = True
    mouth = '大嘴'

    # 定義方法
    def climb(self):
        print('我正在很努力的向前爬...')

    def run(self):
        print('我正在飛快的向前跑...')

    def bite(self):
        print('咬死你咬死你!!')

    def eat(self):
        print('有得喫,真滿足...')

    def sleep(self):
        print('困了,睡了,晚安,zzz')


tt = Turtle()# 實例化過程
print(tt)
# <__main__.Turtle object at 0x0000007C32D67F98>

print(type(tt))
# <class '__main__.Turtle'>

print(tt.__class__)
# <class '__main__.Turtle'>

print(tt.__class__.__name__)
# Turtle

tt.climb()
# 我正在很努力的向前爬...

tt.run()
# 我正在飛快的向前跑...

tt.bite()
# 咬死你咬死你!!

# Python類也是對象。它們是type的實例
print(type(Turtle))
# <class 'type'>


————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

多態

多態:不同對象對同一方法響應不同的行動

即調用方法時通過.來確定在哪個類或對象中來找這個方法,即使方法名相同,但所屬的對象或類不同,則互不干擾

class Animal:
    def run(self):
        raise AttributeError('子類必須實現這個方法')


class People(Animal):
    def run(self):
        print('人正在走')


class Pig(Animal):
    def run(self):
        print('pig is walking')


class Dog(Animal):
    def run(self):
        print('dog is running')


def func(animal):
    animal.run()


func(Pig())
# pig is walking


————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

方法中的self

類的方法與普通的函數只有一個特別的區別 —— 它們必須有一個額外的第一個參數名稱(對應於該實例,即該對象本身),按照慣例它的名稱是 self。在調用方法時,我們無需明確提供與參數 self 相對應的參數。

也即
在調用方法時,self參數會自動傳入方法作爲第一個參數,而不需要我們再輸入self參數。

class Ball:
    def setName(self, name):
        self.name = name

    def kick(self):
        print("我叫%s,該死的,誰踢我..." % self.name)


a = Ball()
a.setName("球A")
b = Ball()
b.setName("球B")
c = Ball()
c.setName("球C")
a.kick()
# 我叫球A,該死的,誰踢我...
b.kick()
# 我叫球B,該死的,誰踢我...


————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

另外
方法中如果要訪問屬性,即調用屬性的值,需要加上self

class Ball:
    a=1
    def setName(self):
        name=a #self.a 纔對


>>> a=Ball()
>>> a.a
1
>>> a.setName()
>>> a.name
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    a.name
AttributeError: 'Ball' object has no attribute 'name'
>>> 

Python的魔法方法

點擊查看常用的魔法方法及其使用方式
Python魔方方法即一類特殊的方法,該方法不能被主動調用,而是在某些情況下自動調用
如,當類實例化時,對象屬性值被修改時,對象被刪除時等情況

方法於屬性的定義位置沒有要求
本例中所涉及的__init__(self[, param1, param2...])方法,該方法在類實例化時會自動調用,對對象的屬性值進行設置。

class Ball:
    def __init__(self):
        self.name=1
    a=1



>>> B=Ball()
>>> B.name
1
>>> B.__init_()
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    B.__init_()
AttributeError: 'Ball' object has no attribute '__init_'

公有和私有

在 Python 中定義私有變量只需要在變量名或函數名前加上“__”兩個下劃線,那麼這個函數或變量就會爲私有的了。

私有屬性與方法只能在對象的內部進行隱藏調用,而不能在對象外進行調用

私有屬性設置:

class JustCounter:
    __secretCount = 0  # 私有變量
    publicCount = 0  # 公開變量

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print(self.__secretCount)


counter = JustCounter()
counter.count()  # 1
counter.count()  # 2
print(counter.publicCount)  # 2

print(counter._JustCounter__secretCount)  # 2 Python的私有爲僞私有
print(counter.__secretCount)  
# AttributeError: 'JustCounter' object has no attribute '__secretCount'

————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

私有方法設置:

class Site:
    def __init__(self, name, url):
        self.name = name  # public
        self.__url = url  # private

    def who(self):
        print('name  : ', self.name)
        print('url : ', self.__url)

    def __foo(self):  # 私有方法
        print('這是私有方法')

    def foo(self):  # 公共方法
        print('這是公共方法')
        self.__foo()


x = Site('老馬的程序人生', 'https://blog.csdn.net/LSGO_MYP')
x.who()
# name  :  老馬的程序人生
# url :  https://blog.csdn.net/LSGO_MYP

x.foo()
# 這是公共方法
# 這是私有方法

x.__foo()
# AttributeError: 'Site' object has no attribute '__foo'


————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

繼承機制

繼承:子類自動共享父類之間數據和方法的機制

即將父類的方法和屬性直接複製到子類中

class MyList(list):
    pass


lst = MyList([1, 5, 2, 7, 8])
lst.append(9)
lst.sort()
print(lst)

# [1, 2, 5, 7, 8, 9]

————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

繼承其他模塊的類

class DerivedClassName(modname.BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>
    
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

如果子類中定義與父類同名的方法或屬性,則會自動覆蓋父類對應的方法或屬性。

# 類定義
class people:
    # 定義基本屬性
    name = ''
    age = 0
    # 定義私有屬性,私有屬性在類外部無法直接進行訪問
    __weight = 0

    # 定義構造方法
    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w

    def speak(self):
        print("%s 說: 我 %d 歲。" % (self.name, self.age))


# 單繼承示例
class student(people):
    grade = ''

    def __init__(self, n, a, w, g):
        # 調用父類的構函
        people.__init__(self, n, a, w)
        self.grade = g

    # 覆寫父類的方法
    def speak(self):
        print("%s 說: 我 %d 歲了,我在讀 %d 年級" % (self.name, self.age, self.grade))


s = student('小馬的程序人生', 10, 60, 3)
s.speak()
# 小馬的程序人生 說: 我 10 歲了,我在讀 3 年級
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

注意此處people.__init__(self, n, a, w)的作用是防止__init__方法被子類完全覆蓋掉
如:

class Fish:
    def __init__(self):
        self.x = r.randint(0, 10)
        self.y = r.randint(0, 10)

    def move(self):
        self.x -= 1
        print("我的位置", self.x, self.y)


class GoldFish(Fish):  # 金魚
    pass


class Carp(Fish):  # 鯉魚
    pass


class Salmon(Fish):  # 三文魚
    pass


class Shark(Fish):  # 鯊魚
    def __init__(self):
        self.hungry = True

    def eat(self):
        if self.hungry:
            print("喫貨的夢想就是天天有得喫!")
            self.hungry = False
        else:
            print("太撐了,喫不下了!")
            self.hungry = True


g = GoldFish()
g.move()  # 我的位置 9 4
s = Shark()
s.eat() # 喫貨的夢想就是天天有得喫!
s.move()  
# AttributeError: 'Shark' object has no attribute 'x'
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

解決方法:

如上,在__init__方法中添一句Fish.__init__(self)super().__init__()
super()代指父類

多繼承

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

需要注意圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,Python從左至右搜索,即方法在子類中未找到時,從左到右查找父類中是否包含方法。

# 類定義
class People:
    # 定義基本屬性
    name = ''
    age = 0
    # 定義私有屬性,私有屬性在類外部無法直接進行訪問
    __weight = 0

    # 定義構造方法
    def __init__(self, n, a, w):
        self.name = n
        self.age = a
        self.__weight = w

    def speak(self):
        print("%s 說: 我 %d 歲。" % (self.name, self.age))


# 單繼承示例
class Student(People):
    grade = ''

    def __init__(self, n, a, w, g):
        # 調用父類的構函
        People.__init__(self, n, a, w)
        self.grade = g

    # 覆寫父類的方法
    def speak(self):
        print("%s 說: 我 %d 歲了,我在讀 %d 年級" % (self.name, self.age, self.grade))


# 另一個類,多重繼承之前的準備
class Speaker:
    topic = ''
    name = ''

    def __init__(self, n, t):
        self.name = n
        self.topic = t

    def speak(self):
        print("我叫 %s,我是一個演說家,我演講的主題是 %s" % (self.name, self.topic))


# 多重繼承
class Sample01(Speaker, Student):
    a = ''

    def __init__(self, n, a, w, g, t):
        Student.__init__(self, n, a, w, g)
        Speaker.__init__(self, n, t)


test = Sample01("Tim", 25, 80, 4, "Python")
test.speak()  # 方法名同,默認調用的是在括號中排前地父類的方法


# 我叫 Tim,我是一個演說家,我演講的主題是 Python

class Sample02(Student, Speaker):
    a = ''

    def __init__(self, n, a, w, g, t):
        Student.__init__(self, n, a, w, g)
        Speaker.__init__(self, n, t)


test = Sample02("Tim", 25, 80, 4, "Python")
test.speak()  # 方法名同,默認調用的是在括號中排前地父類的方法

# Tim 說: 我 25 歲了,我在讀 4 年級
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

組合

即在類中創建另一個類的實例化對象

class Turtle:
    def __init__(self, x):
        self.num = x


class Fish:
    def __init__(self, x):
        self.num = x


class Pool:
    def __init__(self, x, y):
        self.turtle = Turtle(x)
        self.fish = Fish(y)

    def print_num(self):
        print("水池裏面有烏龜%s只,小魚%s條" % (self.turtle.num, self.fish.num))


p = Pool(2, 3)
p.print_num()
# 水池裏面有烏龜2只,小魚3條
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

類屬性和實例屬性

類屬性:類裏面方法外面定義的變量稱爲類屬性。類屬性所屬於類對象並且多個實例對象之間共享同一個類屬性,說白了就是類屬性所有的通過該類實例化的對象都能共享。

class A():
    a = xx  #類屬性
    def __init__(self):
        A.a = xx  #使用類屬性可以通過 (類名.類屬性)調用。

實例屬性:實例屬性和具體的某個實例對象有關係,並且一個實例對象和另外一個實例對象是不共享屬性的,說白了實例屬性只能在自己的對象裏面使用,其他的對象不能直接使用,因爲self是誰調用,它的值就屬於該對象。

class 類名():
    __init__(self):
        self.name = xx #實例屬性

區別

  • 類屬性:類外面,可以通過實例對象.類屬性和類名.類屬性進行調用。類裏面,通過self.類屬性和類名.類屬性進行調用。
  • 實例屬性 :類外面,可以通過實例對象.實例屬性調用。類裏面,通過self.實例屬性調用。
  • 實例屬性就相當於局部變量。出了這個類或者這個類的實例對象,就沒有作用了。
  • 類屬性就相當於類裏面的全局變量,可以和這個類的所有實例對象共享。

注意:屬性與方法名相同,屬性會覆蓋方法。

Python 嚴格要求方法需要有實例才能被調用,這種限制其實就是 Python 所謂的綁定概念。
因此沒有類方法和屬性方法的區別。

————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

數據屬性

Python 對象的數據屬性通常存儲在名爲.__ dict__的字典中,我們可以直接訪問__dict__,或利用 Python 的內置函數vars()獲取.__ dict__

class CC:
    def setXY(self, x, y):
        self.x = x
        self.y = y

    def printXY(self):
        print(self.x, self.y)


dd = CC()
print(dd.__dict__)
# {}

print(vars(dd))
# {}

print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}

dd.setXY(4, 5)
print(dd.__dict__)
# {'x': 4, 'y': 5}

print(vars(CC))
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}

print(CC.__dict__)
# {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

BIF

issubclass(class, classinfo) 方法用於判斷參數 class 是否是類型參數 classinfo 的子類。
一個類被認爲是其自身的子類。
classinfo可以是類對象的元組,只要class是其中任何一個候選類的子類,則返回True。

isinstance(object, classinfo)用於判斷一個對象是否是一個已知的類型
type()不會認爲子類是一種父類類型,不考慮繼承關係。
isinstance()會認爲子類是一種父類類型,考慮繼承關係。
如果第一個參數不是對象,則永遠返回False
如果第二個參數不是類或者由類對象組成的元組,會拋出一個TypeError異常。

a = 2
print(isinstance(a, int))  # True
print(isinstance(a, str))  # False
print(isinstance(a, (str, int, list)))  # True


class A:
    pass


class B(A):
    pass


print(isinstance(A(), A))  # True
print(type(A()) == A)  # True!!!!!!!!!!!!!!!!!!!!!!!!!!
print(isinstance(B(), A))  # True
print(type(B()) == A)  # False!!!!!!!!!!!!!!!!!!!!!!!!!
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

hasattr(object, name)用於判斷對象是否包含對應的屬性。

getattr(object, name[, default])用於返回一個對象屬性值,若不存在則返回defalt

class A(object):
    bar = 1


a = A()
print(getattr(a, 'bar'))  # 1
print(getattr(a, 'bar2', 3))  # 3
print(getattr(a, 'bar2'))
# AttributeError: 'A' object has no attribute 'bar2'
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580
class A(object):
    def set(self, a, b):
        x = a
        a = b
        b = x
        print(a, b)


a = A()
c = getattr(a, 'set')
c(a='1', b='2')  # 2 1

————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580

setattr(object, name, value)對應函數 getattr(),用於設置屬性值,該屬性不一定是存在的。

delattr(object, name)用於刪除屬性。

描述符

class property([fget[, fset[, fdel[, doc]]]])用於在新式類中返回屬性值。
fget – 獲取屬性值的函數
fset – 設置屬性值的函數
fdel – 刪除屬性值函數
doc – 屬性描述信息

class C(object):
    def __init__(self):
        self.__x = None

    def getx(self):
        return self.__x

    def setx(self, value):
        self.__x = value

    def delx(self):
        del self.__x

    x = property(getx, setx, delx, "I'm the 'x' property.")


cc = C()
cc.x = 2
print(cc.x)  # 2
————————————————
版權聲明:本文爲CSDN博主「老馬的程序人生」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/LSGO_MYP/article/details/102292580
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章