1. 程式人生 > 其它 >Python基礎 - 09面向物件基礎

Python基礎 - 09面向物件基礎

Python基礎 - 09面向物件

面向物件:

類(有共同特徵和行為的抽象的)、物件(例項化的個體、個例)、 屬性: 特徵、 方法: 動作

一、類定義

所有的類名要求首字母大寫,多個單詞使用駝峰式命名。如 ValueError、 StopIterable

class Phone:
    brand = 'huawei'

print(Phone)          # <class '__main__.Phone'>

# 使用類建立物件
hw = Phone()
print(hw)             # <__main__.Phone object at 0x0000006683783B20>
print(hw.brand)       # huawei,  如果物件自己的空間存在 brand屬性,則不會去模型中取查詢
hw.brand = 'honor'
print(hw.brand)       # honor

  

構造器__init__(self)

1.找有沒有一塊空間是Phone類的

2.利用Phone類,向記憶體申請一塊和Phone一樣的空間,0x0000009196583B20

3.去 Phone中找有沒有 __init__,如沒有則執行將開闢的記憶體空間給物件p1 ->0x0000009196583B20

4.如果有__init__,則會進入__init__方法執行裡面動作。動態的self空間新增兩個屬性: brand, price

二、方法

種類:普通方法/物件方法、類方法、靜態方法、魔術方法

2.1 普通方法

# 方法
class Phone:
    brand = 'xiaomi'

    def __init__(self):
        print('-----init-----')

    def call(self):
        print('self ---> ', self)
        print('打電話....')

xm1 = Phone()
print(xm1)            #            <__main__.Phone object at 0x0000009196583B20>
xm1.call()            # self --->  <__main__.Phone object at 0x0000009196583B20>   \n 打電話....

  

2.2 類方法

# 類方法
# 定義需要依賴裝飾器 @classmethod
# 類方法中引數不是一個物件,而是類。   print(cls)     <class '__main__.Dog'>
# 類方法中只可以使用類屬性。
# 類方法中不可使用普通方法。
class Dog:
    def __init__(self, nickname):
        self.nickname = nickname

    def run(self):
        print('{}在院子裡跑圈'.format(self.nickname))

    @classmethod
def test(cls): print(cls) # print(cls.nickname) # AttributeError: type object 'Dog' has no attribute 'nickname' # print(self.nickname) # NameError: name 'self' is not defined d1 = Dog('球球') d1.run() # 球球在院子裡跑圈 d1.test() # <class '__main__.Dog'> Dog.test() # <class '__main__.Dog'> #------------------------------------------ class Person: __age = 18 def show(self): print('-->', Person.__age) @classmethod def update_age(cls): cls.__age = 20 print('---->類方法') print(Person.__age) @classmethod def show_age(cls): print('修改後年齡:', cls.__age) # print(Person.__age) # AttributeError: type object 'Person' has no attribute '__age' Person.update_age() # ---->類方法 \n 20 Person.show_age() # 修改後年齡: 20

  

2.3 靜態方法

# 靜態方法
# 需要裝飾器  @staticmethod
# 靜態方法是無需傳遞引數(cls, self)
# 只能訪問類的屬性和方法,物件的屬性和方法是無法訪問的。
# 載入時機同類方法

class Student:
    __age = 18
    name = 'lucy'

    def show(self):
        print('-->', Person.__age)

    @classmethod
    def update_age(cls):
        cls.__age = 20
        print('---->類方法')
        print(Person.__age)

    @classmethod
    def show_age(cls):
        print('修改後年齡:', cls.__age)

    @staticmethod
    def test():
        print('-->靜態方法')
        # print(self.name)  # 語法錯誤
        print(Student.__age)


s = Student()
s.test()            # -->靜態方法 \n 18

  

類方法 和靜態方法

不同: 1.裝飾器不同 2.類方法是有引數的,靜態方法是沒有引數的

相同: 1.只能訪問類的屬性和方法,無法訪問物件的 2.都可以通過類名呼叫訪問 3.可以在建立物件之前訪問。不依賴物件。

普通方法:沒有裝飾器,要依賴物件,每個普通方法都有一個self,只有建立了物件才能呼叫。

2.4 魔術方法

格式: __名字__()

2.4.1 構造器 __init__():初始化,觸發時機:初始化物件時觸發。(不是例項化觸發,是和例項化在一個操作中)

引數:至少有一個self,接收物件 返回值:無

class Person:
    name = 'zhangsan'

    def __init__(self):
        self.name = '張三'
        self.age = 18

    def eat(self):
        print('{}正在吃飯'.format(self.name))

    def run(self):
        print('{},今年{}歲,正在跑步'.format(self.name, self.age))


p1 = Person()
p1.name = '李四'
p1.eat()          # 李四正在吃飯
p2 = Person()
p2.eat()          # 張三正在吃飯
p2.run()          # 張三,今年18歲,正在跑步
# -----------------------------------------
class Person:
    name = 'zhangsan'

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

    def eat(self, food):
        print('{}正在吃{}'.format(self.name, food))

    def run(self):
        print('{},今年{}歲,正在跑步'.format(self.name, self.age))


p3 = Person('王五', 11)
p3.eat('烤鴨')              # 王五正在吃烤鴨
p3.run()                   # 王五,今年11歲,正在跑步

2.4.2 __new__():例項化 觸發時機:例項化物件時觸發

引數:至少一個cls接收當前類 返回值:必須返回一個物件例項

例項化物件是Object類底層實現,其他類繼承了Object的__new__才能實現例項化物件。

先觸發__new__才會觸發__init__

class Person:
    def __init__(self):
        print('-----> init')

    def __new__(cls, *args, **kwargs):
        print('--->new')

p = Person()  
print('p:',p)
'''          
--->new
p:  None         # 未例項化物件, p 未指向地址
'''
    def __new__(cls, *args, **kwargs):
        print('--->new')
        return object.__new__(cls, *args, **kwargs)     

'''
--->new      # 先例項化       
-----> init  # 後初始化
p:  <__main__.Person object at 0x000000B66357AFA0>
'''

 

    def __new__(cls, *args, **kwargs):
        print('--->new')
        # return object.__new__(cls, *args, **kwargs)
        return super(Person, cls).__new__(cls, *args, **kwargs)  # 正確

  

    def __new__(cls, name):
        print('--->new')
        return super(Person, cls).__new__(cls, name)

TypeError: object.__new__() takes exactly one argument (the type to instantiate)
--->new
class Person:
    def __init__(self, name):
        print('-----> init')
        self.name = name

    def __new__(cls, *args, **kwargs):
        print('--->new')
        pos = object.__new__(cls)    # 申請開闢記憶體空間0x8183A7BFA0, 然後返回給 __init__的 self,進行初始化
        print(pos)
        return pos


p = Person('Jack')    # --->new
print(p)              # None
print(p.name)         # Jack
'''
--->new
<__main__.Person object at 0x0000008183A7BFA0>
-----> init
<__main__.Person object at 0x0000008183A7BFA0>
'''

  

2.4.3 __call__:物件呼叫方法, p() / p(param)

觸發時機:將物件當成函式使用時,預設呼叫此函式中內容

class Person:
    def __init__(self, name):
        print('-----> init')
        self.name = name

    def __new__(cls, *args, **kwargs):
        print('--->new')
        pos = object.__new__(cls)
        print(pos)
        return pos

    def __call__(self, name):
        print('----> call')
        print('執行物件得到引數為', name)

p = Person('Luck')
print(p.name)

p('aaa')

'''
--->new
<__main__.Person object at 0x00000040DD9BBFA0>
-----> init
Luck
----> call
執行物件得到引數為 aaa
'''

  

2.4.4 __del__刪除物件

當一塊空間沒有了任何引用,預設執行__del__

python直譯器,回收所有在本次執行過程中使用到的空間。Python底層自帶垃圾回收,進行記憶體釋放。

import sys
class Person:
    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('刪除物件了')

p = Person('abc')
p1 = p
p2 = p
print(p1.name)            # abc
print(p2.name)            # abc
print(sys.getrefcount(p)) # 4   / p, p1, p2, sys 四個引用, 指向同一個地址

p1.name = 'tom'
print(p.name)             # tom
print(p2.name)            # tom

del p2                    # 刪除p2 對地址的引用
print(p.name)             # tom
print(sys.getrefcount(p)) # 3 \n  刪除物件了

  

2.4.5 __str__: 單純列印物件名稱,列印的是地址。

觸發時機:列印物件名稱時,自動觸發去呼叫__str__裡面的內容。

在__str__方法中新增return, return後面的內容是列印物件輸出的內容。

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

    def __str__(self):
        # print('物件str:', self.name)
return '物件str: {}'.format(self.name) t = Teacher('tt') print(t) # 物件str: tt