面向對象練習題

1.面向對象三大特性,各有什麼用處,說說你的理解。
  繼承:解決代碼重用問題
  多態:爲了類在繼承和派生的時候,保證使用家譜中任一類的實例的某一屬性時能夠正確調用。
  封裝:明確區份內外,控制外部對隱藏屬性的操做行爲,隔離複雜度html


2.類的屬性和對象的屬性有什麼區別?
  類的屬性分爲數據屬性和函數屬性。
  類的數據屬性時全部對象共享的,類的函數屬性是綁定給對象用的,稱爲綁定到對象的方法。

  對象的屬性可能來自類定義,即類屬性。(類定義自身、類定義繼承兩種途徑)
  對象的屬性還多是該對象實例定義的,即對象屬性

3.面向過程編程與面向對象編程的區別與應用場景?
  面向過程的程序設計的核心是過程(流水線式思惟),過程即解決問題的步驟,面向過程的設計就比如精心設計好一條流水線,考慮周全何時處理什麼問題。
  優勢:複雜問題流程化,進而簡單化。缺點:可擴展性和可維護性差
  適用:通常用於那些功能一旦實現以後就不多須要改變的場景, 若是你只是寫一些簡單的腳本,去作一些一次性任務。

  面向對象編程是利用「類」和「對象」來建立各類模型來實現對真實世界的描述。與面向過程機械式的思惟方式造成鮮明對比,面向對象更加註重對現實世界而非流程的模擬,是一種「上帝式」的思惟方式。
  優勢:更容易擴展和修改,更容易理解  缺點:編程複雜度高、可控性差
  適用:應用於需求常常變化的軟件中,通常需求的變化都集中在用戶層,互聯網應用,企業內部軟件,遊戲等都是面向對象的程序設計大顯身手的好地方。

4.類和對象在內存中是如何保存的。
  以字典的方式保存,代碼在類定義階段便會執行,於是會產生新的名稱空間,用來存放類的變量名和函數名,能夠經過__dict__查看。
  __dict__查出字典,key爲屬性名,value爲屬性值

5.什麼是綁定到對象的方法、綁定到類的方法、解除綁定的函數、如何定義,如何調用,給誰用?有什麼特性
  (1)綁定到對象的方法:在類中定義沒有加裝飾器修飾的方法。
        對象.bound_method()  自動將對象當作第一個參數傳入
    (2)綁定到類的方法:在類中定義的裝飾器@classmethod修飾的方法。
        類.bound_method()   自動將類當第一個參數傳入
  (3)非綁定方法:在類中用@staticmethod裝飾器裝飾的方法。
        沒有自動傳值,不綁定類和對象,類和對象都可調用。python

6.使用實例進行 獲取、設置、刪除 數據, 分別會觸發類的什麼私有方法。sql

# item系列就是爲了把對象模擬成像字典同樣,就能夠像字典同樣訪問
class A(object):
    def __getitem__(self, item):
        return self.__dict__.get(item)

    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__)   # {}
item系列方法解決

 

7.python中經典類和新式類的區別編程

  首先object是全部python類的基類,它提供了一些常見方法(如__str__)的實現。json

  在python2中,沒有顯式繼承object類的類,以及該類的子類都是經典類。 深度優先
  python2中,顯式地聲明繼承object類,以及該類的子類都是新式類。     廣度優先
    在python3中,不管是否繼承object,都默認繼承object,即python3中全部類均爲新式類數據結構

 

8.以下示例, 請用面向對象的形式優化如下代碼app

在沒有學習類這個概念時,數據與功能是分離的
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 exec:
    host = '127.0.0.1'
    port = 3306
    charset = 'utf-8'
    db = 'db1'
    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 = exec('select * from tb1;')
print(ex.__dict__)  # {'args': ('select * from tb1;',)}

 

9.示例1,現有以下代碼,會輸出什麼:ide

class People(object):
    __name = "luffy"
    __age = 18

p1 = People()
print(p1.__name, p1.__age)

答:會報錯,AttributeError: 'People' object has no attribute '__name'

 

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: 對象的建立,是一個靜態方法,第一個參數是cls。(想一想也是,不多是self,對象還沒建立,哪來的self)
     init : 對象的初始化, 是一個實例方法,第一個參數是self。
     call : 爲了將一個類實例當作函數調用,咱們須要在類中實現__call__()方法,能夠用來改變實例的內部成員的值.
    先有建立,纔有初始化。即先new,然後init。學習

 

11.請簡單解釋Python中 staticmethod(靜態方法)和 classmethod(類方法), 並分別補充代碼執行下列方法。

  staticmethod(靜態方法):又稱爲非綁定方法,不與類和對象綁定,就是一個普通方法,不會自動傳值。
  classmethod(類方法):是綁定到類的方法,自動將類做爲第一個參數傳入

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('hqs')
a.foo('alex')
A.class_foo('alex')
a.static_foo('alex')
# A.static_foo('alex')
"""
executing foo(<__main__.A object at 0x10402cc50>, alex)
executing class_foo(<class '__main__.A'>, alex)
executing static_foo(alex)
executing static_foo(alex)
"""

 

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()
"""
TypeError: 'NoneType' object is not callable
由於eat方法添加了@property裝飾器,將函數屬性假裝得像數據屬性同樣被用戶訪問。
修改方法:去掉d.eat後面的括號便可。
"""
d.eat
# 輸出: ChenRonghua is eating

 

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()
    print(G.mro())
    print(F.mro())
示例代碼

 

新式類廣度優先,super無論當前類的繼承關係,會按照實例化的類的MRO列表,一直日後找。
G D A B
F C B D A
[<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 Animal(metaclass=abc.ABCMeta):   # metaclass元類
    def __init__(self, name):
        self.name = name

    @abc.abstractclassmethod    # 定義抽象方法,無需實現功能
    def talk(self):
        pass

class People(Animal):
    def talk(self):
        print('people %s is talking loudly' % self.name)

class Pig(Animal):
    def talk(self):
        print('pig %s is talking' % self.name)

class Dog(Animal):
    def talk(self):
        print('Dog %s is talking' % self.name)

def func(animal):
    animal.talk()

s = Dog('was')
func(s)
多態性代碼

 

16.不少同窗都是學會了面向對象的語法,卻依然寫不出面向對象的程序,緣由是什麼呢?
緣由就是由於你還沒掌握一門面向對象設計利器,即領域建模,請解釋下什麼是領域建模,
以及如何經過其設計面向對象的程序?http://www.cnblogs.com/alex3714/articles/5188179.html 此blog最後面有詳解
    領域模型,顧名思義,就是需求所涉及的領域的一個建模,更通俗的講法是業務模型。
    定義:
        需求到面向對象的橋樑
    做用:
        1.發掘重要的業務領域概念
        2.創建業務領域概念之間的關係
    方法:
        從用例中找名詞
    領域建模的三字經方法:找名詞、加屬性、連關係。
        參考:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label15
             http://www.cnblogs.com/linhaifeng/articles/7341318.html

 

17.請寫一個小遊戲,人狗大站,2個角色,人和狗,遊戲開始後,生成2我的,3條狗,互相混戰,
  人被狗咬了會掉血,狗被人打了也掉血,狗和人的攻擊力,具有的功能都不同。
  注意,請按題14領域建模的方式來設計類。

class Role:
    def __init__(self, name, life_value, attack_force):
        self.name = name
        self.life_value = life_value
        self.attack_force = attack_force

    def attack(self, obj):
        obj.life_value -= self.attack_force

class Person(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 = Person('alex', 100, 32)
d1 = Dog('bela', 40, 40)

p1.attack(d1)
print(d1.life_value)
d1.attack(p1)
print(p1.life_value)
"""
alex attack bela
8
bela attack alex
60
"""

 

18.編寫程序, 在元類中控制把自定義類的數據屬性都變成大寫.

new: 對象的建立,是一個靜態方法,第一個參數是cls。(想一想也是,不多是self,對象還沒建立,哪來的self)
init : 對象的初始化, 是一個實例方法,第一個參數是self。
call : 爲了將一個類實例當作函數調用,咱們須要在類中實現__call__()方法,能夠用來改變實例的內部成員的值.
先有建立,纔有初始化。即先new,然後init。

class Mymeta(type):
    """修改類屬性爲大寫"""
    def __new__(cls, *args, **kwargs):
        for k,v in args[2].items():
            if not callable(v) and not k.startswith('__'):
                args[2][k] = v.upper()
            else:
                args[2][k] = v
        return type.__new__(cls, *args, **kwargs)

    """經過call改寫了對象屬性爲大寫"""
    def __call__(self, *args, **kwargs):
        # print(self, args, kwargs)  # <class '__main__.Chinese'> ('hqs', 12) {}
        new_args = []
        for index, i in enumerate(args):
            if isinstance(i, str):
                new_args.append(i.upper())
            else:
                new_args.append(i)
        args = tuple(new_args)
        print(args)
        obj = object.__new__(self)
        self.__init__(obj, *args, **kwargs)
        return obj

class Chinese(object, metaclass=Mymeta):
    country = 'CHINA'
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def talk(self):
        print("%s is talking" % self.name)


people1 = Chinese('hqs', 12)
print(people1.name, people1.country, people1.age)
"""
('HQS', 12)
HQS CHINA 12
"""
自定義類

 

19.編寫程序, 在元類中控制自定義的類無需init方法.
  # 同上18題答案

 

20.編寫程序, 編寫一個學生類, 要求有一個計數器的屬性, 統計總共實例化了多少個學生.

class Student:
    __count = 0
    def __init__(self, name, age):
        self.name = name
        self.age = age
        Student.__count += 1

    @staticmethod
    def get_count():
        print("總共實例化 %s 人" % Student.__count)

stu1 = Student('hqs', 20)
stu2 = Student('egon', 19)
stu1.get_count()
Student.get_count()

 

21.編寫程序, A 繼承了 B, 倆個類都實現了 handle 方法, 在 A 中的 handle 方法中調用 B 的 handle 方法

class B:
    def handle(self):
        print('from B handle')

class A(B):
    def handle(self):
        print("class A's instance")
        super().handle()

a = A()
a.handle()
"""
class A's instance
from B handle
"""

 

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秒即不容許登陸)

import json
import time
class User:
    def __init__(self, name, password):
        self.name = name
        self.password = password
        self.status = False
        self.timeout = 0

    @property
    def db(self):
        with open(self.name+".txt", 'r', encoding="utf-8") as f:
            data = json.load(f)
        return data

    def save(self):
        obj={}
        obj[self.name] = {"password": self.password, "status": self.status, "timeout": self.timeout}
        with open(self.name+'.txt', 'w', encoding='utf-8') as f:
            json.dump(obj, f)

    def login(self):
        with open(self.name+'.txt', 'r+', encoding='utf-8') as f:
            data = json.load(f)
            count = 0
            while count < 3:
                password = input("password>>:").strip()
                if password != data[self.name]['password']:
                    count += 1
                    continue
                else:
                    if data[self.name]['timeout'] != 0:
                        if time.time() - data[self.name]['timeout'] > 10:
                            print('不容許登陸,時間超時!')
                            break
                        else:
                            data[self.name]['status'] = True
                            f.seek(0)
                            f.truncate()
                            json.dump(data, f)
                            print("--------welcome--------")
                            break
                    else:
                        data[self.name]['status'] = True
                        f.seek(0)
                        f.truncate()
                        json.dump(data, f)
                        print("----------welcome----------")
                        break
            else:
                data[self.name]['timeout'] = time.time()
                f.seek(0)
                f.truncate()
                json.dump(data, f)

    def exit(self):
        with open(self.name+'.txt', 'r+', encoding="utf-8") as f:
            data = json.load(f)
            if data[self.name]["status"] == True:
                data[self.name]["status"] = False
                f.seek(0)
                f.truncate()
                json.dump(data, f)
            else:
                print("您如今處於退出狀態")

user1 = User('alex', '123')
user1.save()
user1.login()
用戶類

 

23.用面向對象的形式編寫一個老師角色, 並實現如下功能, 獲取老師列表, 建立老師、刪除老師、建立成功以後經過 pickle 序列化保存到文件裏,並在下一次重啓程序時能
讀取到建立的老師, 例如程序目錄結構以下.

.
|-- bin/
|   |-- main.py         程序運行主體程序(可進行菜單選擇等)
|-- config/
|   |-- settings.py     程序配置(例如: 配置存儲建立老師的路徑相關等)
|-- db                  數據存儲(持久化, 使得每次再重啓程序時, 相關數據對應保留)
|   |-- teachers/          存儲全部老師的文件
|   |-- ...                ...
|-- src/                程序主體模塊存放
|   |-- __init__.py
|   |-- teacher.py      例如: 實現老師相關功能的文件
|   |-- group.py        例如: 實現班級相關的功能的文件
|-- manage.py           程序啓動文件
|-- README.md           程序說明文件

 

24.根據23 題, 再編寫一個班級類, 實現如下功能, 建立班級, 刪除班級, 獲取班級列表、建立成功以後經過 pickle 序列化保存到文件裏,並在下一次重啓程序時能
讀取到建立的班級.

25.根據 23題, 編寫課程類, 實現如下功能, 建立課程(建立要求如上), 刪除課程, 獲取課程列表

26.根據23 題, 編寫學校類, 實現如下功能, 建立學校, 刪除學校, 獲取學校列表

27.經過23題, 它們雷同的功能, 是否能夠經過繼承的方式進行一些優化

僞代碼
class Behavior(object):
    def fetch(self, keyword):
        經過 keyword 參數 查詢出對應的數據列表

class School(Behavior):
    pass

class Teacher(Behavior):
    pass

s = School()
t = Teacher()

s.fetch("school")
t.fetch("teacher")
相關文章
相關標籤/搜索