面向對象編程(練習題)


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、

編寫程序, 如下有三點要求:

  1. 自定義用戶信息數據結構, 寫入文件, 然后讀取出內容, 利用json模塊進行數據的序列化和反序列化
    e.g
    {
        "egon":{"password":"123",'status':False,'timeout':0},
        "alex":{"password":"456",'status':False,'timeout':0},
    }

     

  1. 定義用戶類,定義方法db,例如 執行obj.db可以拿到用戶數據結構
  2. 在該類中實現登錄、退出方法, 登錄成功將狀態(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: 文件已存在

本章作業

題目:選課系統開發,要求有四種角色:學校、學員、課程、講師

詳細要求:

  1. 創建北京、上海 2 所學校

  2. 創建linux , python , go 3個課程 , linux\py 在北京開, go 在上海開

  3. 課程包含,周期,價格,通過學校創建課程

  4. 通過學校創建班級, 班級關聯課程、講師

  5. 創建學員時,選擇學校,關聯班級

  6. 創建講師角色時要關聯學校

  7. 提供兩個角色接口

  8. 為學員、講師、管理員分別提供用戶界面,並提供對應功能: 1 學員視圖, 可以注冊, 交學費, 選擇班級, 2 講師視圖, 講師可管理自己的班級, 上課時選擇班級, 查看班級學員列表 , 修改所管理的學員的成績 3 管理視圖,創建講師, 創建班級,創建課程

注1:上面的操作產生的數據都通過pickle序列化保存到文件里 注2:此作業必須畫流程圖,圖中標注好不同類或對象之間的調用關系




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM