練習題
1.面向對象三大特性,各有什么用處,說說你的理解。
面向對象的三大特性:
1.繼承:解決代碼的復用性問題
2.封裝:對數據屬性嚴格控制,隔離復雜度
3.多態性:增加程序的靈活性與可擴展性
2.類的屬性和對象的屬性有什么區別?
首先需要理解這樣一個概念:
Python中一切皆對象
因而‘類’也是一種對象
所以我們在談論類的屬性和對象的屬性的區別時,實際上是在談論‘類’這樣一種特殊的對象與其他對象的區別。
類屬性僅是與類相關的數據值,和普通對象屬性不同,類屬性和實例對象無關。這些值像靜態成員那樣被引用,即使在多次實例化中調用類,它們的值都保持不變。不管如何,靜態成員不會因為實例而改變它們的值,除非實例中顯式改變它們的值。
3.面向過程編程與面向對象編程的區別與應用場景?
1.1 面向過程的程序設計
“面向過程”(Procedure Oriented)是一種以過程為中心的編程思想。“面向過程”也可稱之為“面向記錄”編程思想,不支持豐富的“面向對象”特性(比如繼承、多態),並且它們不允許混合持久化狀態和域邏輯。
•特點:分析出解決問題所需要的步驟,然后用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了
•優點:復雜的問題流程化,進而簡單化(一個復雜的問題,分成一個個小的步驟去實現,實現小的步驟將會非常簡單)
•缺點:可擴展性差
•應用場景:面向過程的程序設計思想一般用於那些功能一旦實現之后就很少需要改變的場景, 如果你只是寫一些簡單的腳本,去做一些一次性任務,用面向過程的方式是極好的,著名的例子有Linux內核,git,以及Apache HTTP Server等。但如果你要處理的任務是復雜的,且需要不斷迭代和維護 的, 那還是用面向對象最方便了。
1.2 面向對象的程序設計
“面向對象程序設計”(Object-oriented programming,縮寫:OOP)是一種程序設計范型,同時也是一種程序開發的方法。對象指的是類的實例。它將對象作為程序的基本單元,將程序和數據封裝其中,以提高軟件的重用性、靈活性和擴展性。 面向對象程序設計可以看作一種在程序中包含各種獨立而又互相調用的對象的思想,這與傳統的思想剛好相反:傳統的程序設計主張將程序看作一系列函數的集合,或者直接就是一系列對電腦下達的指令。面向對象程序設計中的每一個對象都應該能夠接受數據、處理數據並將數據傳達給其它對象,因此它們都可以被看作一個小型的“機器”,即對象。
•優點:可擴展性高
•缺點:編程的復雜度遠高於面向過程,不了解面向對象而立即上手並基於它設計程序,極容易出現過度設計的問題,而且在一些擴展性要求低的場景使用面向對象會徒增編程難度,比如管理linux系統的shell腳本程序就不適合用面向對象去設計,面向過程反而更加適合。
•應用場景:面向對象程序設計推廣了程序的靈活性和可維護性,並且在大型項目設計中廣為應用。 此外,支持者聲稱面向對象程序設計要比以往的做法更加便於學習,因為它能夠讓人們更簡單地設計並維護程序,使得程序更加便於分析、設計、理解。
4.類和對象在內存中是如何保存的
類以及類中的方法在內存中只有一份,而根據類創建的每一個對象都在內存中需要存一份
根據類創建對象時,對象中除了封裝 name 和 age 的值之外,還會保存一個類對象指針,該值指向當前對象的類。
當通過某對象執行其類中方法時,過程如下:
根據當前對象中的 類對象指針 找到類中的方法
將對象當作參數傳給方法的第一個參數 self
5.什么是綁定到對象的方法、綁定到類的方法、解除綁定的函數、如何定義,如何調用,給誰用?有什么特性
8.如下示例, 請用面向對象的形式優化以下代碼
def exc1(host,port,db,charset):
conn=connect(host,port,db,charset)
conn.execute(sql)
return xxx
def exc2(host,port,db,charset,proc_name)
conn=connect(host,port,db,charset)
conn.call_proc(sql)
return xxx
# 每次調用都需要重復傳入一堆參數
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存儲過程的名字')
優化代碼:
class Exc:
host = '127.0.0.1'
port = 3306
db = 'db1'
charset = 'utf8'
conn = connect(host, port, db, charset)
def __init__(self, proc_name):
self.proc = proc_name
def test(self):
if self.proc =='select * from tb1;':
self.conn.execute(sql)
elif self.proc =='存儲過程的名字':
self.conn.call_proc(sql)
return XXX
exc1 = Exc('select * from tb1;')
exc1.test()
exc2 = Exc('存儲過程的名字')
exc2.test()
#從這里的優化結果可以看書,需要重復輸入的內容變少了,但是類的代碼量也不小
9.示例1, 現有如下代碼, 會輸出什么:
class People(object):
__name = "luffy"
__age = 18
p1 = People()
print(p1.__name, p1.__age)
#程序將會報錯,因為隱藏屬性不能直接被訪問
print(p1._People__name, p1._People__age) #打印結果luffy 18
10.示例2, 現有如下代碼, 會輸出什么:
class People(object):
def __init__(self):
print("__init__")
def __new__(cls, *args, **kwargs):
print("__new__")
return object.__new__(cls, *args, **kwargs)
People()
__new__
__init__
#__new__方法接受的參數雖然也是和__init__一樣,但__init__是在類實例創建之后調用,而 __new__方法正是創建這個類實例的方法。
11.請簡單解釋Python中 staticmethod(靜態方法)和 classmethod(類方法), 並分別補充代碼執行下列方法。
class A(object):
def foo(self, x):
print("executing foo(%s, %s)" % (self,x))
@classmethod
def class_foo(cls, x):
print("executing class_foo(%s, %s)" % (cls,x))
@staticmethod
def static_foo(x):
print("executing static_foo(%s)" % (x))
a = A()
#classmehtod是給類用的,即綁定到類,類在使用時會將類本身當做參數傳給類方法的第一個參數(即便是對象來調用也會將類當作第一個參數傳入
#classmethod,綁定到類的方法
a.class_foo('綁定到類') #輸出結果:executing class_foo(<class '__main__.A'>, 綁定到類)
A.class_foo('綁定到類') #輸出結果:executing class_foo(<class '__main__.A'>, 綁定到類)
#在類內部用staticmethod裝飾的函數即非綁定方法,就是普通函數,statimethod不與類或對象綁定,誰都可以調用,沒有自動傳值效果
#staticmethod 靜態方法
a.static_foo('靜態綁定') #輸出結果:executing static_foo(靜態綁定)
A.static_foo('靜態綁定') #輸出結果:executing static_foo(靜態綁定)
12.請執行以下代碼,解釋錯誤原因,並修正錯誤。
class Dog(object):
def __init__(self,name):
self.name = name
@property
def eat(self):
print(" %s is eating" %self.name)
d = Dog("ChenRonghua")
d.eat()
d.eat()應該改為d.eat
@property使eat的接口發生了改變
13.下面這段代碼的輸出結果將是什么?請解釋。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
# 1 1 1 繼承自父類的類屬性x,所以都一樣,指向同一塊內存地址
# 1 2 1 更改Child1,Child1的x指向了新的內存地址
# 3 2 3 更改Parent,Parent的x指向了新的內存地址
14.多重繼承的執行順序,請解答以下輸出結果是什么?並解釋。
class A(object):
def __init__(self):
print('A')
super(A, self).__init__()
class B(object):
def __init__(self):
print('B')
super(B, self).__init__()
class C(A):
def __init__(self):
print('C')
super(C, self).__init__()
class D(A):
def __init__(self):
print('D')
super(D, self).__init__()
class E(B, C):
def __init__(self):
print('E')
super(E, self).__init__()
class F(C, B, D):
def __init__(self):
print('F')
super(F, self).__init__()
class G(D, B):
def __init__(self):
print('G')
super(G, self).__init__()
if __name__ == '__main__':
g = G()
f = F()
# G
# D
# A
# B
#
# F
# C
# B
# D
# A
15.請編寫一段符合多態特性的代碼.
class Cat(Animal): #屬於動物的另外一種形態:貓
def talk(self):
print('say miao')
def func(animal): #對於使用者來說,自己的代碼根本無需改動
animal.talk()
cat1=Cat() #實例出一只貓
func(cat1) #甚至連調用方式也無需改變,就能調用貓的talk功能
#say miao
17.請寫一個小游戲,人狗大站,2個角色,人和狗,游戲開始后,生成2個人,3條狗,互相混戰,人被狗咬了會掉血,狗被人打了也掉血,狗和人的攻擊力,具備的功能都不一樣。注意,請按題14領域建模的方式來設計類。
class Role(object):
def __init__(self,name):
self.name = name
def attack(self,enemy):
enemy.life_value-=self.agressivity
class People(Role):
agressivity = 10
life_value = 100
def __init__(self,name):
super().__init__(name)
class Dogs(Role):
agressivity = 15
life_value = 80
def __init__(self,name):
super().__init__(name)
p1 = People('Tom')
p2 = People('Jack')
d1 = Dogs('niker')
d2 = Dogs('geeker')
d3 = Dogs('chaox')
print(p1.agressivity)
print(p1.life_value)
p1.attack(d1)
print(d1.life_value)
18.編寫程序, 在元類中控制把自定義類的數據屬性都變成大寫.
19.編寫程序, 在元類中控制自定義的類無需init方法.
20.編寫程序, 編寫一個學生類, 要求有一個計數器的屬性, 統計總共實例化了多少個學生.
class Student:
count = 0
@classmethod
def __init__(cls):
cls.count += 1
a1 = Student()
a2 = Student()
a3 = Student()
a4 = Student()
print(Student.count)
#輸出4
21.編寫程序, A 繼承了 B, 倆個類都實現了 handle 方法, 在 A 中的 handle 方法中調用 B 的 handle 方法
class B:
def handle(self):
print('from B')
class A(B):
def handle(self):
super().handle()
a = A()
a.handle()
22.編寫程序, 如下有三點要求:
- 自定義用戶信息數據結構, 寫入文件, 然后讀取出內容, 利用json模塊進行數據的序列化和反序列化
e.g
{
"egon":{"password":"123",'status':False,'timeout':0},
"alex":{"password":"456",'status':False,'timeout':0},
}
import json
eg={
"egon":{"password":"123",'status':False,'timeout':0},
"alex":{"password":"456",'status':False,'timeout':0},
}
with open('uesr_data.json', 'w', encoding='utf-8') as fp1:
json.dump(eg,fp1)
with open('uesr_data.json', 'r', encoding='utf-8') as fp2:
data = json.load(fp2)
print(data)
- 定義用戶類,定義方法db,例如 執行obj.db可以拿到用戶數據結構
import json
class User:
@property
def db(self):
with open('uesr_data.json', 'r', encoding='utf-8') as fp:
data = json.load(fp)
return data
obj = User()
print(obj.db)
- 在該類中實現登錄、退出方法, 登錄成功將狀態(status)修改為True, 退出將狀態修改為False(退出要判斷是否處於登錄狀態).密碼輸入錯誤三次將設置鎖定時間(下次登錄如果和當前時間比較大於10秒即不允許登錄).
import json
import time
import pathlib
import os
import sys
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
print(base_dir)
sys.path.append(base_dir)
class User:
def __init__(self):
while True:
self.name = input('請輸入用戶名\n>>>:')
if not self.file_exist(base_dir):
print('輸入的密碼有誤')
else:
break
self.data = self.db
def file_exist(self,path): # 通過判斷指定路徑下,以用戶名命名的文件是否存在,來判斷用戶輸入的用戶正確
global file_path
file_name = 'db/%s.json' % self.name
file_path = os.path.join(path,file_name)
file_is = pathlib.Path(file_path)
file_result = file_is.is_file()
if file_result:
return file_path
else:
return False
@property
def db(self):
with open(file_path, 'r',encoding='utf-8') as file:
data = json.load(file)
return data
def login(self):
count = 0
while count < 3:
if self.data['timeout'] != 0:
if time.time() - self.db['timeout'] > 10:
print('不允許登錄,時間超時!')
return False
with open(file_path,'r+',encoding='utf-8') as f:
count += 1
password = input('請輸入密碼\n>>>:')
if password != self.db['password']:
print('密碼輸入錯誤')
if count == 3:
self.data['timeout'] = time.time()
f.seek(0)
f.truncate()
json.dump(self.data, f)
continue
self.data['status'] = True
f.seek(0)
f.truncate()
json.dump(self.data,f)
print("--------welcome--------")
return True
def exit(self):
with open(file_path, 'r+', encoding="utf-8") as f:
data = json.load(f)
if data["status"]:
data["status"] = False
f.seek(0)
f.truncate()
json.dump(data, f)
else:
print("您現在處於退出狀態")
user1 = User()
user1.login()
print(user1.__dict__)
user1.exit()