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