面向物件初始
阿新 • • 發佈:2020-08-06
內容詳細
1.面向物件基本格式
# ###### 定義類 ###### class 類名: def 方法名(self,name): print(name) return 123 def 方法名(self,name): print(name) return 123 def 方法名(self,name): print(name) return 123 # ###### 呼叫類中的方法 ###### # 1.建立該類的物件 obj = 類名() # 2.通過物件呼叫方法 result = obj.方法名('alex') print(result)
應用場景:遇到很多函式,需要給函式進行歸類和劃分。 【封裝】
2.物件的作用
儲存一些值,以後方便自己使用。
class File: def read(self): with open(self.xxxxx, mode='r', encoding='utf-8') as f: data = f.read() return data def write(self, content): with open(self.xxxxx, mode='a', encoding='utf-8') as f: f.write(content) # # 例項化了一個File類的物件 obj1 = File() # # 在物件中寫了一個xxxxx = 'test.log' obj1.xxxxx = "test.log" # # 通過物件呼叫類中的read方法,read方法中的self就是obj。 # # obj1.read() obj1.write('alex') # 例項化了一個File類的物件 obj2 = File() # 在物件中寫了一個xxxxx = 'test.log' obj2.xxxxx = "info.txt" # 通過物件呼叫類中的read方法,read方法中的self就是obj。 # obj2.read() obj2.write('alex')
class Person: def __init__(self,n,a,g): # 初始化方法(構造方法),給物件的內部做初始化。 self.name = n self.age = a self.gender = g def show(self): temp = "我是%s,年齡:%s,性別:%s " % (self.name, self.age, self.gender,) print(temp) # 類() 例項化物件,自動執行此類中的 __init__方法。 p1 = Person('李兆琪',19,'男') p1.show() p2 = Person('利奇航',19,'男') p2.show()
總結:將資料封裝到物件,方便使用。
總結
"""
如果寫程式碼時,函式比較多比較亂。
1. 可以將函式歸類並放到同一個類中。
2. 函式如果有一個反覆使用的公共值,則可以放到物件中。
"""
class File:
def __init__(self,path):
self.file_path = path
def read(self):
print(self.file_path)
def write(self,content):
print(self.file_path)
def delete(self):
print(self.file_path)
def update(self):
print(self.file_path)
p1 = File('log.txt')
p1.read()
p2 = File('xxxxxx.txt')
p2.read()
# 1. 迴圈讓使用者輸入:使用者名稱/密碼/郵箱。 輸入完成後再進行資料列印。
# ########## 以前的寫法
USER_LIST = []
while True:
user = input('請輸入使用者名稱:')
pwd = input('請輸入密碼:')
email = input('請輸入郵箱:')
temp = {'username':user,'password':pwd,'email':email}
USER_LIST.append(temp)
for item in USER_LIST:
temp = "我的名字:%s,密碼:%s,郵箱%s" %(item['username'],item['password'],item['email'],)
print(temp)
# ########## 面向物件寫法
class Person:
def __init__(self,user,pwd,email):
self.username = user
self.password = pwd
self.email = email
USER_LIST = [物件(使用者/密碼/郵箱),物件(使用者/密碼/郵箱),物件(使用者/密碼/郵箱)]
while True:
user = input('請輸入使用者名稱:')
pwd = input('請輸入密碼:')
email = input('請輸入郵箱:')
p = Person(user,pwd,email)
USER_LIST.append(p)
for item in USER_LIST:
temp = "我的名字:%s,密碼:%s,郵箱%s" %(item.username,item.password,item.email,)
print(temp)
# ########## 面向物件寫法
class Person:
def __init__(self,user,pwd,email):
self.username = user
self.password = pwd
self.email = email
def info(self):
return "我的名字:%s,密碼:%s,郵箱%s" %(item.username,item.password,item.email,)
USER_LIST = [物件(使用者/密碼/郵箱),物件(使用者/密碼/郵箱),物件(使用者/密碼/郵箱)]
while True:
user = input('請輸入使用者名稱:')
pwd = input('請輸入密碼:')
email = input('請輸入郵箱:')
p = Person(user,pwd,email)
USER_LIST.append(p)
for item in USER_LIST:
msg = item.info()
print(msg)
4.繼承
# 父類(基類)
class Base:
def f1(self):
pass
# 子類(派生類)
class Foo(Base):
def f2(self):
pass
# 建立了一個子類的物件
obj = Foo()
# 執行物件.方法時,優先在自己的類中找,如果沒有就是父類中找。
obj.f2()
obj.f1()
# 建立了一個父類的物件
obj = Base()
obj.f1()
問題:什麼時候才能用到繼承?多個類中如果有公共的方法,可以放到基類中避免重複編寫。
class Base:
def f1(self):
pass
class Foo(Base):
def f2(self):
pass
class Bar(Base):
def f3(self):
pass
obj1 = Foo()
obj2 = Bar()
繼承關係中的查詢方法的順序:
# 示例一
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1()
obj.f2()
# 示例二
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
self.f1()
print('foo.f2')
obj = Foo()
obj.f2()
# 示例三
class Base:
def f1(self):
print('base.f1')
class Foo(Base):
def f2(self):
self.f1()
print('foo.f2')
def f1(self):
print('foo.f1')
obj = Foo()
obj.f2()
# 示例四
class Base:
def f1(self):
self.f2()
print('base.f1')
def f2(self):
print('base.f2')
class Foo(Base):
def f2(self):
print('foo.f2')
obj = Foo()
obj.f1()
# 示例五
class TCPServer:
pass
class ThreadingMixIn:
pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
# 示例六
class BaseServer:
def serve_forever(self, poll_interval=0.5):
self._handle_request_noblock()
def _handle_request_noblock(self):
self.process_request(request, client_address)
def process_request(self, request, client_address):
pass
class TCPServer(BaseServer):
pass
class ThreadingMixIn:
def process_request(self, request, client_address):
pass
class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass
obj = ThreadingTCPServer()
obj.serve_forever()
注意事項:
- self 到底是誰?
- self 是哪個類建立的,就從此類開始找,自己沒有就找父類,同時繼承多個基類的就從左到右依次查詢,第一個基類找完了,沒找到,就到後續的基類中查詢。
5.多型(多種形態/多種型別)鴨子模型
# Python
def func(arg):
v = arg[-1] # arg.append(9)
print(v)
# java
def func(str arg):
v = arg[-1]
print(v)
面試題:什麼是鴨子模型。
對於一個函式而言,Python對於引數的型別不會限制,那麼傳入引數時就可以是各種型別,在函式中如果有例如:arg.send方法,那麼就是對於傳入型別的一個限制(型別必須有send方法)。這就是鴨子模型
總結
-
面向物件的三大特性:封裝/繼承/多型
-
封裝
class File: def read(self): pass def write(self): pass
class Person: def __init__(sef,name,age): self.name = name self.age = age p = Person('alex',19)
-
繼承
class Base: pass class Foo(Base): pass
- 多繼承
- self到底是誰?
- self是由於那個類建立,則找方法時候就從他開始找。
-
多型
def func(arg): # 多種型別,很多事物 arg.send() # 必須具有send方法,呱呱叫
-
-
格式和關鍵詞
class 類: def __init__(self,x): self.x = x def 方法(self,name): print(self.x, name) # 例項化一個類的物件 v1 = 類(666) v2.方法('alex')
三個詞:
- 類
- 物件
- 方法
-
什麼時候用面向物件?
- 函式(業務功能)比較多,可以使用面向物件來進行歸類。
- 想要做資料封裝(建立字典儲存資料時,面向物件)。
- 遊戲示例:建立一些角色並且根據角色需要再建立人物。
內容詳細
1.成員
-
類
- 類變數
- 繫結方法
- 類方法
- 靜態方法
- 屬性
-
例項(物件)
- 例項變數
-
定義:寫在類的下一級和方法同一級。
-
訪問:
類.類變數名稱 物件.類變數名稱
-
面試題
class Base: x = 1 obj = Base() print(obj.x) # 先去物件中找,沒有再去類中找。 obj.y = 123 # 在物件中添加了一個y=123的變數。 print(obj.y) obj.x = 123 print(obj.x) print(Base.x)
class Parent: x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Parent.x,Child1.x,Child2.x) # 1 1 1 Child1.x = 2 print(Parent.x,Child1.x,Child2.x) # 1 2 1 Child2.x = 3 print(Parent.x,Child1.x,Child2.x) # 1 2 3
總結:找變數優先找自己,自己沒有找 類 或 基類;修改或賦值只能在自己的內部設定。
1.3 方法(繫結方法/普通方法)
- 定義:至少有一個self引數
- 執行:先建立物件,由物件.方法()。 *也可以用類.方法()呼叫,不推薦
class Foo:
def func(self,a,b):
print(a,b)
obj = Foo()
obj.func(1,2)
# ###########################
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
obj = Foo()
obj.func(1, 2)
1.4 靜態方法
- 定義:
@staticmethod
裝飾器- 引數無限制
- 執行:
- 類.靜態方法名 ()
- 物件.靜態方法() (不推薦)
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
@staticmethod
def f1():
print(123)
obj = Foo()
obj.func(1, 2)
Foo.f1()
obj.f1() # 不推薦
1.5 類方法
- 定義:
@classmethod
裝飾器- 至少有
cls
引數,當前類。
- 執行:
- 類.類方法()
- 物件.類方法() (不推薦)
class Foo:
def __init__(self):
self.name = 123
def func(self, a, b):
print(self.name, a, b)
@staticmethod
def f1():
print(123)
@classmethod
def f2(cls,a,b):
print('cls是當前類',cls)
print(a,b)
obj = Foo()
obj.func(1, 2)
Foo.f1()
Foo.f2(1,2)
面試題:
# 問題: @classmethod和@staticmethod的區別?
"""
一個是類方法一個靜態方法。
定義:
類方法:用@classmethod做裝飾器且至少有一個cls引數。
靜態方法:用staticmethod做裝飾器且引數無限制。
呼叫:
類.方法直接呼叫。
物件.方法也可以呼叫。
"""
1.6 屬性
- 定義:
- @property裝飾器
- 只有一個self引數
- 執行:
- 物件.方法 不用加括號。
class Foo:
@property
def func(self):
print(123)
return 666
obj = Foo()
result = obj.func
print(result)
# 屬性的應用
class Page:
def __init__(self, total_count, current_page, per_page_count=10):
self.total_count = total_count
self.per_page_count = per_page_count
self.current_page = current_page
@property
def start_index(self):
return (self.current_page - 1) * self.per_page_count
@property
def end_index(self):
return self.current_page * self.per_page_count
USER_LIST = []
for i in range(321):
USER_LIST.append('alex-%s' % (i,))
# 請實現分頁展示:
current_page = int(input('請輸入要檢視的頁碼:'))
p = Page(321, current_page)
data_list = USER_LIST[p.start_index:p.end_index]
for item in data_list:
print(item)
# 結合私有成員修飾符,可以將自己的資料做成介面,外部訪問時,修改的只是介面內容,而無法更改自己設定的內容
2.成員修飾符
- 公有,所有地方都能訪問到。
- 私有,只有自己可以訪問到。
class Foo:
def __init__(self, name):
self.__name = name
def func(self):
print(self.__name)
obj = Foo('alex')
# print(obj.__name) # 訪問不到
obj.func() # 可以訪問
class Foo:
__x = 1
@staticmethod
def func():
print(Foo.__x)
# print(Foo.__x) # 訪問不到
Foo.func() # 可以訪問
class Foo:
def __fun(self):
print('msg')
def show(self):
self.__fun()
obj = Foo()
# obj.__fun() # 訪問不到
obj.show()
3.小補充
class Foo:
def __init__(self,num):
self.num = num
cls_list = []
for i in range(10):
cls_list.append(Foo)
for i in range(len(cls_list)):
obj = cls_list[i](i)
print(obj.num)
class Foo:
def __init__(self,num):
self.num = num
B = Foo
obj = B('alex')
class Foo:
def f1(self):
print('f1')
def f2(self):
print('f2')
obj = Foo()
v = [ obj.f1,obj.f2 ]
for item in v:
item()
class Foo:
def f1(self):
print('f1')
def f2(self):
print('f2')
def f3(self):
v = [self.f1 , self.f2 ]
for item in v:
item()
obj = Foo()
obj.f3()
class Account:
def login(self):
pass
def register(self):
pass
def run(self):
info = {'1':self.register, '2':self.login }
choice = input('請選擇:')
method = info.get(choice)
method()
class Foo:
pass
class Foo(object):
pass
# 在python3中這倆的寫法是一樣,因為所有的類預設都會繼承object類,全部都是新式類。
# 如果在python2中這樣定義,則稱其為:經典類
class Foo:
pass
# 如果在python2中這樣定義,則稱其為:新式類
class Foo(object):
pass
class Base(object):
pass
class Bar(Base):
pass
贈送
# 強制訪問私有成員
class Foo:
def __init__(self,name):
self.__x = name
obj = Foo('alex')
print(obj._Foo__x) # 強制訪問私有例項變數
總結
-
資料封裝
-
繼承關係的查詢
-
巢狀
class School(object): def __init__(self,title,addr): self.title = title self.address = addr class ClassRoom(object): def __init__(self,name,school_object): self.name = name self.school = school_object s1 = School('北京','沙河') s2 = School('上海','浦東') s3 = School('深圳','南山') c1 = ClassRoom('全棧21期',s1) c1.name c1.school.title c1.school.address # ############################################ v = [11,22,33,{'name':'山海','addr':'浦東'}] v[0] v[3]['name']