面向對象-面試題


1. 簡述面向對象的三大特性。

# 答案
封裝:
    封裝指的是把一堆數據屬性與方法數據放在一個容器中,這個容器就是對象。讓對象可以通過 "." 來調用對象中的數據屬性與方法屬性。
    
繼承:
    繼承指的是子類可以繼承父類的數據屬性與方法屬性,並可以對其進行修改或使用。
    
多態:
    在python中的多態指的是讓多種類若具備類似的數據屬性與方法屬性,都統一好命名規范,這樣可以提高開發者的代碼統一性,使得調用者更方便去理解。

2. 什么是鴨子模型?

# 答案
在python中不會強制性要求所有人的代碼都統一規范,不統一也不會報錯,若使用抽象類就會使python代碼強制統一規范,這樣不符合python動態語言的特性。所以讓大家都自覺統一好規范,若大家的對象方法都類似的話就一種規范,只要長得像鴨子,就稱之為鴨子類型。

3. super 的作用?

# 答案
'''
        使用super()可以在子類中調用父類的方法或屬性, 可能你會說, 子類本來就可以調用父類中所有非私有的屬性或方法,而我現在說的是, 當子類中實現了某個方法, 父類中也有這個方法, 當你調用這個方法時, 既想執行子類的又想執行父類的, 在這種情況下就可以使用super()
'''

4. mro 是什么?

# 答案
'''
        mro全稱Method Resolution Order,指的是方法解析順序。
        方法調用時就需要對當前類和基類進行搜索以確定方法所在的位置。而搜索的順序就是所謂的「方法解析順序」。
'''

5. 什么是 c3 算法?

# 答案
'''
C3算法最早被提出是用於Lisp的,應用在Python中是為了解決原來基於深度優先搜索算法不滿足本地優先級,和單調性的問題。
本地優先級:指聲明時父類的順序,比如C(A,B),如果訪問C類對象屬性時,應該根據聲明順序,優先查找A類,然后再查找B類。
單調性:如果在C的解析順序中,A排在B的前面,那么在C的所有子類里,也必須滿足這個順序。
'''

6. 列舉面向對象中帶雙下划線的特殊方法。

# 答案
#__setattr__: 添加/修改屬性會觸發它的執行
#__delattr__: 刪除屬性的時候會觸發
#__getattr__: 只有在使用點調用屬性且屬性不存在的時候才會觸發
# __getattribute__: 不管是否存在,我都會執行

7. 雙下划線和單下划線的區別?

# 答案
'''
"單下划線" 開始的成員變量叫做保護變量,意思是只有類對象和子類對象自己能訪問到這些變量。

"雙下划線" 開始的是私有成員,意思是只有類對象自己能訪問,連子類對象也不能訪問到這個數據。
'''

8. 實例變量和類變量的區別?

# 答案
'''
類變量是所有對象共有,其中一個對象將它值改變,其他對象得到的就是改變后的結果;而實例變量則屬對象私有,某一個對象將其值改變,不影響其他對象;
'''

9. 靜態方法和類方法區別?

# 答案
'''
Python的類就是個語法糖。一個函數寫在類里面和寫在類外面沒有區別,唯一的區別就是參數,所謂實例方法就是第一個參數是self,所謂類方法就是第一個參數是class,而靜態方法不需要額外的參數,所以必須區分。
'''

10. isinstance 和 type 的作用?

# 答案
'''
type和isinstance都可以判斷變量是否屬於某個內建類型
type只接收一個參數,不但可以判斷變量是否屬於某個類型,而且可以得到參數變量未知的所屬的類型;而isinstance只能判斷是否屬於某個已知類型,不能直接得到變量未知的所屬的類型
'''

11. 有用過with statement(語句)嗎?它的好處是什么?

# 答案
'''
with語句會在嵌套的代碼執行之后,自動關閉文件。這種做法的還有另一個優勢就是,無論嵌套的代碼是以何種方式結束的,它都關閉文件。如果在嵌套的代碼中發生異常,它能夠在外部exception handler catch異常前關閉文件。如果嵌套代碼有return/continue/break語句,它同樣能夠關閉文件。
'''

12. 下列數據結構中,哪一種是不可迭代的

'''
    A.  dict
    B.  object
    C.  set
    D.  str
'''

# 答案:
B

13. 實現一個Singleton單例類,要求遵循基本語言編程規范(用盡量多的方 式)。

# 答案:
1.__new__
class Borg(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            ob = super(Borg, cls)
            cls._instance = ob.__new__(cls, *args, **kwargs)
        return cls._instance
class MyClass(Borg):
    def __init__(self):
        self.a = 1
        
2.共享屬性
class Borg2(object):
    _state = {}

    def __new__(cls, *args, **kwargs):
        ob = super(Borg2, cls).__new__(cls, *args, **kwargs)
        ob.__dict__ = cls._state
        return ob

class MyClass(Borg2):
    def __init__(self):
        self.a = 1
        
3.裝飾器
def singleton(cls, *args, **kwargs):
    instances = {}

    def getinstance():
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return getinstance

@singleton
class MyClass(object):
    def __init__(self):
        self.a = 1

4.import方法
# mysingleton .py
class MyClass(object):
    def __init__(self):
        self.a = 1

s_myclass = MyClass()

from mysingleton import s_myclass

s_myclass.a

14. 請􏰂述with的用法,如果自己的類需要支持with語句,應該如何書寫?

基本格式
with context_expression [as target(s)]:
    with-body

這里 context_expression 要返回一個上下文管理器對象,該對象並不賦值給 as 子句中的 target(s) ,如果指定了 as 子句的話,會將上下文管理器的 __enter__() 方法的返回值賦值給 target(s)。
target(s) 可以是單個變量,或者由“()”括起來的元組(不能是僅僅由“,”分隔的變量列表,必須加“()”)。

自定義的上下文管理器要實現上下文管理協議所需要的 __enter__() 和 __exit__() 兩個方法
context_manager.__enter__() :進入上下文管理器的運行時上下文,在語句體執行前調用。with 語句將該方法的返回值賦值給 as 子句中的 target,如果指定了 as 子句的話
context_manager.__exit__(exc_type, exc_value, exc_traceback) :退出與上下文管理器相關的運行時上下文,返回一個布爾值表示是否對發生的異常進行處理。

15. python 中如何判斷一個對象是否可調用? 哪些對象可以是可調用對象?如何定義一個類,使其對象本身就是可調用對象?

# 答案:
# python 中如何判斷一個對象是否可調用
def func():
    pass
print(callable(func))  # True

# 哪些對象可以是可調用對象
1.類對象
2.所有帶有_call_()方法的對象

# 如何定義一個類,使其對象本身就是可調用對象
一個類實例也可以變成一個可調用對象,只需要實現一個特殊方法call()。

16. 請實現一個棧。

# 答案:
class Stack(object) :
  def __init__(self,size):
    #類的構造函數
    self.size = size
    self.stack = []

  def __str__(self):
    #類的字符串輸出方法,類似於java的.toString()方法
    return str(self.stack)

  def getSize(self) :
    #獲取棧當前大小
    return len(self.stack)

  def push(self, x) :
    #入棧,棧滿拋異常
    if self.isfull() :
      #return -1
      raise Exception("Stack is full")
    self.stack.append(x)

  def pop(self) :
    #出棧,棧空拋異常
    if self.isempty() :
      #return -1
      raise Exception("Stack is empty")
    topElement = self.stack[-1] 
    self.stack.remove(topElement)
    return topElement

  def isempty(self) :
    #判斷棧空
    if len(self.stack) == 0 :
      return True
    return False

  def isfull(self) :
    #判斷棧滿
    if len(self.stack) == self.size :
      return True
    return False

17. 關於Python類的繼承不正確的說法是?(多選)

 A. Python類無法繼承
 B. 可以繼承, 無法執行父類的構造函數 
 C. 可以有多個父類
 D. 只能有一個父類 
 
 # 答案
 '''
 A
 D
 '''

18. 實現一個hashtable類,對外暴露的有add和get方法,滿足以下測試代碼

def test():
    import uuid
    names = {"name", "web", "python"}
    ht = HashTable()
    for key in names:
        value = uuid.uuid4()
        ht.add(key, value)
        print("add 元素", key, value)
    for key in names:
        v = ht.get(key)
        print("get 元素", key, v)
 
# 答案:
class HashMap(object):
     def __init__(self):
         # 初始化總表為,容量為2的表格(含兩個子表)
         self.maps = BetterMap(2)
         self.num = 0        # 表中數據個數
     
     def get(self,k):        
         return self.maps.get(k)
    
     def add(self, k, v):
         # 若當前元素數量達到臨界值(子表總數)時,進行重排操作
         # 對總表進行擴張,增加子表的個數為當前元素個數的兩倍!
         if self.num == len(self.maps.maps): 
             self.resize()
         
         # 往重排過后的 self.map 添加新的元素
         self.maps.add(k, v)
         self.num += 1
         
     def resize(self):
         """ 重排操作,添加新表, 注意重排需要線性的時間 """
         # 先建立一個新的表,子表數 = 2 * 元素個數
         new_maps = BetterMap(self.num * 2)
         
         for m in self.maps.maps:  # 檢索每個舊的子表
             for k,v in m.items:   # 將子表的元素復制到新子表
                 new_maps.add(k, v)
         
         self.maps = new_maps      # 令當前的表為新表

19.請用兩個隊列來實現一個棧(給出偽代碼即可)

# 答案:
class StackWithTwoQueues(object):
    #定義兩個空隊列
    def __init__(self):
        self.queue1 = []
        self.queue2 = []
    #入棧
    def push(self, item):
        self.queue1.append(item)
    #出棧
    def pop(self):
        if len(self.queue1) == 0:
            return(None)
        while(len(self.queue1) != 1):
            self.queue2.append(self.queue1.pop(0))
        self.queue1, self.queue2 = self.queue2, self.queue1
        return (self.queue2.pop())
#test
if __name__ == '__main__':
    ss = StackWithTwoQueues()
    list = [0, 1, 2, 3, 4]
    for i in range(5):
        ss.push(list[i])
    print(list)
    for i in range(5):
        print(ss.pop(), ',', end = '')
#output
#[0, 1, 2, 3, 4]
#4, 3, 2, 1, 0

20.已知如下鏈表類,請實現單鏈表逆置

class Node:
    def __init__(self, value, next):
        self.value = value
        self.next = next

# 答案:
class Solution:
    def ReverseList(self, pHead):
        if not pHead or not pHead.next:
            return pHead
          
        last = None
          
        while pHead:
            tmp = pHead.next
            pHead.next = last
            last = pHead
            pHead = tmp
        return last

21.類的加載順序(類中有繼承有構造有靜態)?

1、 類對象 
2、 實例對象 
3、 self變量名稱問題 
4、 類屬性、實例變量、局部變量 
5、 類方法 
6、 實例方法 
7、 類方法與實例方法相互調用 
8、 靜態方法 
9、 繼承時三類方法的影響 

22.參考下面代碼片段

class Context:
    pass

with Context as ctx:
    ctx.do_something()
    
# 請在 Context 類下添加代碼完成該類的實現 

# 答案:
class Context(object):
    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        if all([exc_type, exc_val, exc_tb]):
            print 'handler except'
            print 'exception {}'.format(exc_val)
        return True

def main():
    with tornado.stack_context.StackContext(Contextor):
        async_task()

23. 以下代碼輸出是什么?請給出答案並解釋。

class Parent:
    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)
Child1.x = 3
print(Parent.x, Child1.x, Child2.x)

# 答案
'''
1 1 1
1 2 1
1 3 1
'''

24. 函數del_node(self,data)的功能:在根節點指針為root的二叉樹(又稱二叉 排序樹)上排除數值為 K 的節點,若刪除成功,返回 0,否則返回-1, 概述節點的 定義類型為

class Node(object):
    def __init__(self, data):
        self.data = data  # 節點的數值 
        self.left_child = Node  # 指向左右子樹的指針 
        self.right_child = Node
        
    def set_data(self, data):
        self.data = data

# 答案: 

25. 請給出下面代碼片段的輸出,請簡述上面代碼需要改進的地方?

class Singleton:
    _instance = None
    def __new__(cls, *args, **kwargs):
        print("New")
        if cls._instance is None:
            print("Create")
            cls._instance = super().__new__(cls,*args, **kwargs)
        return cls._instance
    def __init__(self):
        print("Initalize")
        self.prop = None

s1 = Singleton()
s2 = Singleton()

# 答案:

26. 請簡單解釋Python中的staticmethod(靜態方法)和classmethod(類方法), 並將以下代碼填寫完整。

class A:
    def foo(self, x):
        print('executing class_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()
# 調用 foo 函數,參數傳入 1
# ____________________
# 調用 class_foo 函數,參數傳入 1
# ____________________
# 調用 static_foo 函數,參數傳入 1
# ____________________

# 答案:
a.foo(1)
A.class_foo(1)
a.static_foo(1)
A.static_foo(1)

27.已知一個訂單對象(tradeOrder)有如下字段:

字段英文名 中 文 名 字段類型 取值
Id 主 鍵 Long 123456789
Name 姓 名 String 張三
Items 商 品 列 表 集 合 List<商品> (關聯商 品) 查找商品對象,一 個訂單有兩個商 品。商品字段任意 取值。
IsMember 是 否 是 會 員 Boolean True
CouponAmount 優 惠 券 金 額 Bigdecimal Null

商品對象

字段英文名稱 中文名 字段類型 取值
Id 主鍵 Long 987654321
Name 商品名稱 String 手機

問題: 若將訂單對象轉成 JSON 格式,請書寫出轉換后的 JSON 字符串。

28. 寫代碼(棧與隊列)

編程實現一個先進先出的隊列類, 能指定初始化時的隊列大小, 以及 enqueue,dequeue,isempty, isfull 四種方法

使用方法如下

s = Queue(2)  # 初始化一個大小為 2 的隊列
s.is_empty()  # 初始化后, 隊列為空, 返回 True
s.enqueue(1)  # 將 1 加入隊列
s.enqueue(2)  # 將 2 加入隊列
s.isfull()  # 加入了兩個元素, 隊列已滿, 返回 True 6. s.dequeue() # 移除一個元素, 返回 1
s.dequeue()  # 移除一個元素, 返回 2
s.is_empty()  # 隊列已經為空, 返回 True


免責聲明!

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



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