1、面向對象三大特性,各有什么用處,說說你的理解
繼承:解決代碼重用
多態:不考慮對象類型的情況下直接使用對象
封裝:明確的區分內外,控制外部對隱藏屬性進行操作,隔離復雜度
2、 類的屬性和對象的屬性有什么區別?
類的屬性:數據屬性,和函數屬性,函數綁定給對象使用
對象的屬性:對象就是實例化的類
3、面向過程編程與面向對象編程的區別與應用場景?
面向過程:復雜的問題簡單化,但是可擴展性差,主要用於,腳本,自動部署,監控等等
面向對象:對比之下更為復雜,擴展能力強,一切皆對象,主要用於,程序開發,游戲等等
4、類和對象在內存中是如何保存的。
以 dict的形式保存正在內存中
5、什么是綁定到對象的方法、綁定到類的方法、解除綁定的函數、如何定義,如何調用,給誰用?有什么特性
綁定對象: f1=Foo()#生成對象 foo.func#綁定到對象,綁定到對象之后將會自動傳值給func
綁定到類:就是由類來調用,在需要綁定的函數添加裝飾器 @classmethod
非綁定方法: 不與類或對象綁定,誰都可以調用 ,需要按正常函數傳參,需要在非綁定函數添加裝飾器 @staticmethod
6、使用實例進行 獲取、設置、刪除 數據, 分別會觸發類的什么私有方法
# item系列就是為了把對象模擬成像字典一樣,就可以像字典一樣訪問 class A(object): def __getitem__(self, item): return self.__dict__.get(item)#這里用get進行訪問,值不存在也不會報錯 def __setitem__(self, key, value): self.__dict__[key] = value #其他方法與字典使用相同 def __delitem__(self, key): del self.__dict__[key] a = A() a['key'] = "val" print(a.__dict__) # {'key': 'val'} b = a["key"] print(b) # val del a["key"] print(a.__dict__) # {} #輸出 {'key': 'val'} val {}
7、python中經典類和新式類的區別
經典類:在python2中,沒有繼承object的類,以及子類都稱之為經典類,繼承查找方式為 深度優先。
#python2 中定義
class A:#經典類 pass class B(object):#新式類 pass
新式類:python3中,全部為新式類,繼承object的類,以及子類都稱之為新式類, 繼承查找方式為 廣度優先。
8、如下示例, 請用面向對象的形式優化以下代碼
def exc1(host,port,db,charset,sql): 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 Sql: host= '127.0.0.1' port=3306 db='db1' charset='utf8' sql='select * from tb1;' proc_name='存儲過程的名字' def __init__(self,*args): self.args=args def connect(self): pass def exc(self): if self.args == self.sql: conn = self.connect(self.host,self.port,self.db,self.charset) res=conn.execute(self.sql) return res elif self.args == self.proc_name: conn = self.connect(self.host, self.port, self.db, self.charset, self.proc_name) res = conn.call_proc(self.sql) return res ex=Sql('select * from tb1;') print(ex.__dict__) #輸出 {'args': ('select * from tb1;',)}
9、示例1, 現有如下代碼, 會輸出什么:
class People(object): __name = "luffy" __age = 18 p1 = People() print(p1.__name, p1.__age)
會拋出錯誤,因為__name及__age,隱藏了所以不能直接調用,__開頭在類執行的時候已經將屬性名稱更改為'_People__name',
10、示例2, 現有如下代碼, 會輸出什么:
class People(object): def __init__(self): print("__init__") def __new__(cls, *args, **kwargs): print("__new__") return object.__new__(cls, *args, **kwargs)
# __new__
# __init__
因為__new__ 會在__init__前執行
new: 對象的創建,是一個靜態方法,第一個參數是cls。(想想也是,不可能是self,對象還沒創建,哪來的self)
init : 對象的初始化, 是一個實例方法,第一個參數是self。
call : 對象可call,注意不是類,是對象。
先有創建,才有初始化。即先new,而后init。
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()
class A(object): def __init__(self,name): self.name=name 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('mlliu') a.foo('xiaojiu') A.class_foo('xiaojiu') a.static_foo('xiaojiu') #@classmethod 綁定類,自動傳值 #@staticmethod 不綁定類或者對象,普通func,正常傳值 #輸出 executing foo(<__main__.A object at 0x000001A2DC5375F8>, xiaojiu) executing class_foo(<class '__main__.A'>, xiaojiu) executing static_foo(xiaojiu)
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()
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 #輸出 ChenRonghua is eating #因為@property是自動執行函數,所以在最后調用該方法的時候,不需要加后面的()
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)
#111
#121
#323
使用mro()可以看出類的繼承順序,[<class '__main__.Child1'>, <class '__main__.Parent'>, <class 'object'>]
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
新式類廣度優先,super不管當前類的繼承關系,會按照實例化的類的MRO列表,一直往后找。
[<class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
[<class '__main__.F'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
15、請編寫一段符合多態特性的代碼
import abc class Student(metaclass=abc.ABCMeta): @abc.abstractmethod #抽象類 def height(self): pass class Xiaoming(Student): @property def height(self): print('185') class Zhangsan(Student): @property def height(self): print('176') p1 =Zhangsan() p1.height p2 =Xiaoming() p2.height #輸出 176 185
#多態的好處是你不用管他是什么類型都用同樣的方式去調用他
16、很多同學都是學會了面向對象的語法,卻依然寫不出面向對象的程序,原因是什么呢?原因就是因為你還沒掌握一門面向對象設計利器,即領域建模,請解釋下什么是領域建模,以及如何通過其設計面向對象的程序?http://www.cnblogs.com/alex3714/articles/5188179.html 此blog最后面有詳解
領域建模的三字經方法:找名詞、加屬性、連關系。
17、請寫一個小游戲,人狗大站,2個角色,人和狗,游戲開始后,生成2個人,3條狗,互相混戰,人被狗咬了會掉血,狗被人打了也掉血,狗和人的攻擊力,具備的功能都不一樣。注意,請按題領域建模的方式來設計類。
名詞:人、狗、血、攻擊力、武器、
加屬性:
人:血、攻擊力、武器
狗:血、攻擊力、武器
class Role: def __init__(self,name,hp,ad): self.name=name self.hp=hp self.ad=ad def attack(self,obj): obj.hp -= self.ad class People(Role): def attack(self,obj): super().attack(obj) print('%s attack %s'%(self.name,obj.name)) class Dog(Role): def attack(self,obj): super().attack(obj) print('%s attack %s'%(self.name,obj.name)) p1=People ('張三',100,20) p2=People('李四',120,25) d1=Dog('二哈',200,10) d2=Dog('三哈',210,9) d3=Dog('三哈',220,8) p1.attack(d1) print(d1.hp) d1.attack(p1) print(p1.hp) d3.attack(p1) print(p1.hp) #輸出 張三 attack 二哈 180 二哈 attack 張三 90 三哈 attack 張三 82
18、編寫程序, 在元類中控制把自定義類的數據屬性都變成大寫.
class Mymetaclass(type): def __new__(cls,name,bases,attrs): update_attrs={} for k,v in attrs.items(): if not callable(v) and not k.startswith('__'): update_attrs[k.upper()]=v else: update_attrs[k]=v return type.__new__(cls,name,bases,update_attrs) class Chinese(metaclass=Mymetaclass): country='China' tag='Legend of the Dragon' #龍的傳人 def walk(self): print('%s is walking' %self.name) print(Chinese.__dict__) #輸出 {'__module__': '__main__', 'COUNTRY': 'China', 'TAG': 'Legend of the Dragon', 'walk': <function Chinese.walk at 0x000001EAF1E25730>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__doc__': None}
19、編寫程序, 在元類中控制自定義的類無需init方法.
class Mymetaclass(type): def __call__(self, *args, **kwargs): # if args: # raise TypeError('must use keyword argument for key function') obj = object.__new__(self) #創建對象,self為類Foo for k,v in kwargs.items(): obj.__dict__[k.upper()]=v return obj class Chinese(metaclass=Mymetaclass): country='China' tag='Legend of the Dragon' #龍的傳人 def walk(self): print('%s is walking' %self.name) p=Chinese(name='egon',age=18,sex='male') print(p.__dict__) #輸出 <__main__.Chinese object at 0x000002E5068A7358> {'NAME': 'egon', 'AGE': 18, 'SEX': 'male'}
20、編寫程序, 編寫一個學生類, 要求有一個計數器的屬性, 統計總共實例化了多少個學生.
class Student: count =0 def __init__(self,name,age): self.name=name self.age=age Student.count +=1 stu1=Student('zhangsan',17) stu2=Student('lisi',17) stu3=Student('xiaohua',17) print(Student.count) #輸出 3
21、編寫程序, A 繼承了 B, 倆個類都實現了 handle 方法, 在 A 中的 handle 方法中調用 B 的 handle 方法
class B: def handle(self): print('form is B') class A(B): @property def handle(self): super().handle() print('form is A') a=A() a.handle #輸出 form is B form is A
22、
編寫程序, 如下有三點要求:
- 自定義用戶信息數據結構, 寫入文件, 然后讀取出內容, 利用json模塊進行數據的序列化和反序列化
e.g { "egon":{"password":"123",'status':False,'timeout':0}, "alex":{"password":"456",'status':False,'timeout':0}, }
- 定義用戶類,定義方法db,例如 執行obj.db可以拿到用戶數據結構
- 在該類中實現登錄、退出方法, 登錄成功將狀態(status)修改為True, 退出將狀態修改為False(退出要判斷是否處於登錄狀態).密碼輸入錯誤三次將設置鎖定時間(下次登錄如果和當前時間比較大於10秒即不允許登錄)
#!/usr/bin/env python # -*- coding:utf-8 -*- import json import time info_dic = { "egon":{"password":"123",'status':False,'timeout':0}, "alex":{"password":"456",'status':False,'timeout':0}, } class User: def __init__(self): self.file_name = 'info.json' self.fn_load = open(self.file_name, 'r+', encoding='utf-8') self.read_info = json.load(self.fn_load) count = 0 while count<3: self.name = input('name').strip() self.password = input('password').strip() if self.read_info.get(self.name) and self.read_info[self.name]['password'] == self.password : if time.mktime(time.localtime()) - self.read_info[self.name]['timeout'] > 10: print('登陸成功') self.read_info[self.name]['status'] = 'True' self.read_info[self.name]['timeout'] = (time.mktime(time.localtime())) return else: print('與上一次登陸間隔{}秒,過於頻繁禁止登陸'.format(time.mktime(time.localtime()) - self.read_info[self.name]['timeout'])) count =3 else: count += 1 print('用戶名或密碼不正確,請重新輸入') continue else: raise KeyError('登陸失敗') @property def db(self): print(self.read_info[self.name]) return self.read_info def exit(self): self.read_info[self.name]['status'] = 'False' self.fn_load.seek(0) json.dump(self.read_info,self.fn_load) self.fn_load.close() p1=User() p1.db p1.exit() # p2=User() # p2.db #輸出 nameegon password123 登陸成功 {'password': '123', 'status': 'True', 'timeout': 1526121027.0}
定義MySQL類
要求:
1.對象有id、host、port三個屬性
2.定義工具create_id,在實例化時為每個對象隨機生成id,保證id唯一
3.提供兩種實例化方式,方式一:用戶傳入host和port 方式二:從配置文件中讀取host和port進行實例化
4.為對象定制方法,save和get_obj_by_id,save能自動將對象序列化到文件中,文件路徑為配置文件中DB_PATH,文件名為id號,保存之前驗證對象是否已經存在,若存在則拋出異常,;get_obj_by_id方法用來從文件中反序列化出對象
# -*- coding: utf-8 -*-
import time
import hashlib import json import time import sys import os FILE = 'user_info.json' def user(): return json.load(open(FILE)) user_info = user() class Mysql: def __init__(self,host,port): self.host = host self.port = port self.id = Mysql.create_id(self) def create_id(self): m = hashlib.md5(str(time.clock()).encode('utf-8')) self.id = m.hexdigest() return m.hexdigest() def save(self): for root, dirs, files in os.walk(os.path.dirname(__file__)): if self.id in files: raise FileNotFoundError('文件已存在') json.dump(self.__dict__,open(self.id,'w',encoding='utf-8')) def get_obj_by_id(self,id): dic1 = json.load(open(id)) print(dic1) stu1 = Mysql('127.0.0.1',3306) print(stu1.id,stu1.host,stu1.port) stu1.get_obj_by_id('f0fbad80768437dfabc5050e0ebd4504') stu1.save() stu2 = Mysql(user_info['host'],user_info['port'])# print(stu2.id,stu2.host,stu2.port) stu2.save() #輸出 Traceback (most recent call last): 30565a8911a6bb487e3745c0ea3c8224 127.0.0.1 3306 File "G:/python練習/網絡編程/class_練習題.py", line 36, in <module> stu1.save() {'host': '127.0.0.1', 'port': 3306, 'id': 'f0fbad80768437dfabc5050e0ebd4504'} File "G:/python練習/網絡編程/class_練習題.py", line 26, in save raise FileNotFoundError('文件已存在') FileNotFoundError: 文件已存在
本章作業
題目:選課系統開發,要求有四種角色:學校、學員、課程、講師
詳細要求:
-
創建北京、上海 2 所學校
-
創建linux , python , go 3個課程 , linux\py 在北京開, go 在上海開
-
課程包含,周期,價格,通過學校創建課程
-
通過學校創建班級, 班級關聯課程、講師
-
創建學員時,選擇學校,關聯班級
-
創建講師角色時要關聯學校
-
提供兩個角色接口
-
為學員、講師、管理員分別提供用戶界面,並提供對應功能: 1 學員視圖, 可以注冊, 交學費, 選擇班級, 2 講師視圖, 講師可管理自己的班級, 上課時選擇班級, 查看班級學員列表 , 修改所管理的學員的成績 3 管理視圖,創建講師, 創建班級,創建課程
注1:上面的操作產生的數據都通過pickle序列化保存到文件里 注2:此作業必須畫流程圖,圖中標注好不同類或對象之間的調用關系
