面向物件的繫結方法
-
指定物件的值:
class Student:
pass
#指定屬性
stu1 = Student()
stu1.name = '張無忌'
stu1.sex = 'man'
stu1.age = 18
#指定屬性
stu2 = Student()
stu2.name = '周芷若'
stu2.sex = 'woman'
stu2.age = 18
-
但是,如果有1000個學生,怎麼優化寫法?
定義函式,用於為物件設定屬性:
def set_attr(obj,name,sex,age):
obj.name = name
obj.sex = sex
obj.age = age
set_attr(stu3,'趙敏','woman',18)
print(stu3.__dict__)
#輸出內容 : {'name': '趙敏', 'sex': 'woman', 'age': 18}
把函式放到類中就是一個初始化函式
-
初始化函式應該和類是一個整體
-
set_attr() 這個函式的目的用於設定物件的屬性,如果沒有物件此函式則沒有存在的意義
新的呼叫方式:
class Student:
def set_attr(obj, name, sex, age):
obj.name = name
obj.sex = sex
obj.age = age
```
#新的呼叫方式
stu3 = Student()
Student.set_attr(stu3,'趙敏','woman',18)
print(stu3.__dict__)
-
但是,物件與初始化函式是分開的,可以建立物件,而不必執行函式
通常物件一旦被建立,初始化函式就會執行,物件與初始化函式通常是繫結關係:
示範1:
class Student:
#初始化函式名稱是固定的,__開頭__結尾的函式,會在某些時機下自動觸發執行
def __init__(self):
print('執行了__init__')
print(self)
pass
s1 = Student()
#__init__在類的呼叫是就會執行
print(s1)
#self就是自身的意思
示範2:
class Student:
def __init__(self):
self.name = '張三丰'
self.age = 78
s1 = Student()
print(s1.__dict__)
s2 = Student()
print(s2.__dict__)
#這樣寫死了,因為兩個的值是一樣的
正確的寫法:
class Student:
def __init__(self,name,age):
self.name = name
self.age = age#固定的寫法,self可以自定義,但是不建議,相當於識別符號
s1 = Student('張三丰',78)
print(s1.__dict__)
s2 = Student('金庸',68)
print(s2.__dict__)
總結:
-
init函式用於初始化物件,它在建立物件時,就會自動執行:
-
並傳入呼叫類時傳遞的引數,self作為第一個引數沒有意義,固定寫法,識別符號
練習:
class Phone:
def __init__(self,p_type,price,country):
self.p_type = p_type
self.p_price = price
self.country = country
p1 = Phone('iphone','5800','American')
print(p1.__dict__)
繫結方法
-
繫結方法有類的繫結,物件的繫結,
-
繫結方法可以理解為繫結函式,有繫結類的方法,繫結物件的方法,以及非繫結方法
-
在面向物件程式設計思想中,就是要求我們模仿現實生活中的抽象概念,因此把函式稱之為方法
-
為什麼要繫結?
-
呼叫函式,即處理與函式繫結在那個在一起的資料,即會返回物件
-
而物件本質上就是一種存放資料的容器
-
所以就相當於把資料和函式繫結在一起
-
為什麼要把資料和函式繫結在一起?
-
得到物件,就得到了資料和處理資料的方法,就相當於執行了我們一個希望執行到的功能完整的函式.
我們實現一個循序漸進的過程:
處理一份資料:
name = '張三'
age = 20
sex = 'man'
def show_info():
print('hello,i am %s my age is %s my sex %s'%(name,age,sex))
show_info()
把資料引用到一個函式裡面,完成對其的呼叫或處理
如果繼續重複這樣的資料,我們需要重新定義變數的值,可以優化為傳參的形式:
def show_info(name,age,sex):
print('hello,i am %s my age is %s my sex %s'%(name,age,sex))
show_info(name,age,sex)
name = '張三'
age = 20
sex = 'man'
但是,傳參的缺點如下:
-
傳參的缺點在於如果引數的傳遞形式或者格式有誤,報錯
-
另一方面如果傳入的引數較多,費時費力,解決辦法的一種方式是把資料裝到容器裡
-
但是每次處理都要需要先獲取資料,然後再傳遞給函式,依然比較容易出錯
-
而且資料和函式是分離的,所以
-
** 將要處理的資料與處理資料的函式進行繫結,函式和資料就不是分離狀態了**
-
如何繫結,就得用類和物件了
程式碼:
繫結物件
class Student:
school = 'BeiJing'
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
賦予某些技能(方法)
def learning(self):
print('正在學習...')
賦予某些具體的技能
def say_hi(self):
print('hello,i am %s my age is %s my sex %s'%(self.name,self.age,self.sex) )
預設情況下,在類中定義的方法都是繫結方法
stu1 = Student('李白',18,'man')
stu1.say_hi()#用物件呼叫
Student.say_hi(stu1)#用類呼叫
註釋:以物件開頭,用物件來調類中的方法(函式),預設會把物件傳入方法中,也就是self,自身的意思
以類開頭,用類來呼叫方法時,需要手動傳入物件
記憶體原理(可以無視):
-
print(stu1.say_hi)
輸出 : <bound method Student.say_hi of <main.Student object at 0x000001CE452B9EF0>>
這是一個繫結方法,本質上是Student類中的sayhi函式,現在把這個函式繫結給記憶體中地址為0x000001CE452B9EF0的物件
-
只要拿到物件,就同時拿到了資料和處理資料的方法,這就是之所以繫結的原因
-
可以更有效和更有效率的處理資料
-
以上是繫結給物件的方法,預設是繫結物件的
-
繫結給物件的意思就是方法(函式)用的都是類裡面物件的內容,而不直接呼叫類
繫結類:
class Student:
school = 'BeiJing'#school就是類裡的屬性
def __init__(self,name,sex,age):
self.name = name#這些就是物件的屬性
self.sex = sex
self.age = age
(self.age_1 = age)也可以這樣寫,age_1是可變的,不過預設兩邊是一樣的
這是繫結給物件的方法,只涉及物件
def sayhello(self):
print(self.name,'你好')
繫結給類的方法,直接訪問類,需要一個裝飾器,預設引數變為cls,類的縮寫,固定格式
@classmethod
def print_school(cls):
print('學校名為%s'%Student.school)#訪問類中叫school的屬性
print(cls.school)
def sayhello(self):
print(self.school) # 這樣也可以操作,但是要用物件去掉,違背初衷,且太過於麻煩
Student.print_school()#類的呼叫
s1 = Student('name','sex','age')
s1.sayhello()#物件的呼叫
解釋:
-
不加裝飾器,正常呼叫不需要傳入引數,就像訪問普通函式一樣,
-
但是函式需要一個引數,這是類中方法的固定用法,因此不可避免要報錯。
-
引入@classmethod裝飾器,固定用法,cls表示類,縮寫
-
-
明確兩點
如何定義物件繫結方法,以及類的繫結方法:
繫結物件是用於調取物件(非類裡)屬性的方法,繫結類是調取類的屬性
在呼叫時有何區別
繫結類要加@classmethod裝飾器
-
-
-
思考,一個方法在什麼場景下會繫結物件或者類?
當要處理的資料包含在類裡時,就不能繫結給物件,應該直接繫結給類
當要處理的資料包含在物件裡時,就應該直接繫結給物件
-
-
非繫結方法
class Teacher:
def __init__(self,name,sex):
self.name = name
self.sex = sex
@staticmethod #靜態方法,用於定義一個非繫結方法
def test_func(): #也可以傳參
print('test_func, run!')
Teacher.test_func() #類訪問
t1 = Teacher('name','fun')
t1.test_func() #物件訪問
非繫結方法,在類中定義,既不繫結給類,也不繫結給物件 特點: 沒有自動傳參的效果,誰都可以呼叫,就是一個普通函式 使用場景,這個功能不需要訪問類和物件的資料
練習
1.建立Student類
2.擁有以下屬性: 姓名 性別 年齡 學校 班級
3.擁有以下方法
-
save(name) 其作用是將這個物件序列化到檔案中
-
get_obj(name) 其作用是根據name從檔案中反序列化為得到一個物件
-
分析save方法和get_obj 應該作為繫結給物件還是繫結給類
import json
class Student:
school = "beijing"
def __init__(self,name,sex,age,classes):
self.name = name
self.age = age
self.sex = sex
self.classes = classes
def save(self):
dic = {"name":self.name,"sex":self.sex,
"age":self.age,"classes":self.classes}
with open(self.name,"wt",encoding="utf-8") as f:
json.dump(dic,f)
@classmethod
def get_obj(cls,name):
with open(name,"rt",encoding="utf-8") as f:
dic = json.load(f)
obj = cls(dic["name"],dic["sex"],dic["age"],dic["classes"])
return obj
# stu1 = Student("阿爾法","man",20,"py5期")
# stu2 = Student("張三","woman",20,"py5期")
# stu1.save()
# stu2.save()
stu = Student.get_obj("阿爾法")
print(stu)
print(stu.name)
總結
類和物件的繫結方法的總結
1,相同點 都會自動傳值 都可以被類和物件呼叫 引數名都可以被修改,但是不建議修改 2,不同點 物件繫結方法在物件呼叫時,傳的是物件自己,而類繫結方法自動傳的是類自己 第一個引數不一樣,一個是self , 一個是cls
個人總結
訪問順序:
物件 ------> 類
呼叫方式:
1,物件呼叫
以物件開頭的呼叫方式,物件要先定義物件,因此要用物件傳參
2,類的呼叫
以類的名字開頭的呼叫方式,不用提前定義
初始化函式:
以init為標誌的函式,通常直接與方法繫結,方法直接呼叫其內定義的屬性
繫結方法:
1,物件的繫結
物件的繫結就是方法中,引數是初始化函式定義中的屬性,函式的結果或返回值就是物件
2,類的繫結
類的繫結就是方法中,直接呼叫初始化函式之外的屬性,要加一個裝飾器@classmethod
繫結的情景:
1,物件的繫結
屬性在物件裡,就不需要繫結給類,多此一舉
2,類的繫結
屬性包含在類裡,直接繫結給類
非繫結方法:
在類中定義,既不繫結給類,也不繫結給物件
已解決
類的公共內容是什麼?
是類裡所有物件共有的屬性,也即是初始化函式之外的內容,一般寫在初始化函式上面
物件跟類是什麼關係?
物件是使用類裡某些屬性和方法的東西,例項化的內容,從類裡創建出來的內容
呼叫類會產生物件,返回的是物件
初始化函式外的屬性是不是叫類裡的屬性?
不止是之外的屬性,類裡的所有東西都是一種屬性,方法也是一種屬性,萬物皆物件,萬物皆屬性
方法是函式,也是物件的技能,也是一種屬性.
怎麼區分處理的資料是在物件裡還是類裡?
物件裡是作為屬性返回的,類是是共有的屬性
物件的屬性和技能?
屬性是類似於你的名字,身高,體重,年齡,技能就類似於你使用的python
物件的屬性和技能就是呼叫類裡屬性和方法返回的值.