Python面试题总结(9)--高级特性
文章目錄
- 1. 函數(shù)裝飾器有什么作用?請列舉說明?
- 2. Python 垃圾回收機(jī)制?
- 3. 魔法函數(shù) _call_怎么使用?
- 4. 如何判斷一個對象是函數(shù)還是方法?
- 5. @classmethod 和 @staticmethod 用法和區(qū)別
- 6. Python 中的接口如何實(shí)現(xiàn)?
- 7. Python 中的反射了解么?
- 8. metaclass 作用?以及應(yīng)用場景?
- 9. hasattr()、getattr()、setattr() 的用法
- 10. 請列舉你知道的 Python 的魔法方法及用途。
- 11. 如何知道一個 Python 對象的類型?
- 12. Python 的傳參是傳值還是傳址?
- 13. Python 中的元類 (metaclass) 使用舉例
- 14. 簡述 any() 和 all() 方法
- 15. filter 方法求出列表所有奇數(shù)并構(gòu)造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- 16. 什么是猴子補(bǔ)丁?
- 17. 在 Python 中是如何管理內(nèi)存的?
- 18. 當(dāng)退出 Python 時是否釋放所有內(nèi)存分配?
1. 函數(shù)裝飾器有什么作用?請列舉說明?
答: 裝飾器就是一個函數(shù),它可以在不需要做任何代碼變動的前提下給一個函數(shù)增加額外功能,啟動裝飾的效果。 它經(jīng)常用于有切面需求的場景,比如:插入日志、性能測試、事務(wù)處理、緩存、權(quán)限校驗等場景。 舉例說明一個日志功能的裝飾器:
1).首先定義一個log文件
# -*- coding: utf-8 -*- import os import time import logging import sys log_dir1=os.path.join(os.path.dirname(os.path.dirname(__file__)),"logs") today = time.strftime('%Y%m%d', time.localtime(time.time())) full_path=os.path.join(log_dir1,today) if not os.path.exists(full_path):os.makedirs(full_path) log_path=os.path.join(full_path,"facebook.log") def get_logger():# 獲取logger實(shí)例,如果參數(shù)為空則返回root loggerlogger = logging.getLogger("facebook")if not logger.handlers:# 指定logger輸出格式formatter = logging.Formatter('%(asctime)s %(levelname)-8s: %(message)s')# 文件日志file_handler = logging.FileHandler(log_path,encoding="utf8")file_handler.setFormatter(formatter) # 可以通過setFormatter指定輸出格式# 控制臺日志console_handler = logging.StreamHandler(sys.stdout)console_handler.formatter = formatter # 也可以直接給formatter賦值# 為logger添加的日志處理器logger.addHandler(file_handler)logger.addHandler(console_handler)# 指定日志的最低輸出級別,默認(rèn)為WARN級別logger.setLevel(logging.INFO)# 添加下面一句,在記錄日志之后移除句柄return logger2).然后定義一個裝飾器文件
在這里引用wraps,一個裝飾器的裝飾器,目的為了保持引用進(jìn)來的函數(shù)名字不發(fā)生變化
3)在使用的時候直接在函數(shù)上面引用即可
@decorator def start():print("666")代碼參考來源
2. Python 垃圾回收機(jī)制?
答:Python 不像 C++,Java 等語言一樣,他們可以不用事先聲明變量類型而直接對變量進(jìn)行賦值。對 Python 語言來講,對象的類型和內(nèi)存都是在運(yùn)行時確定的。這也是為什么我們稱 Python 語言為動態(tài)類型的原因。
主要體現(xiàn)在下面三個方法:
1.引用計數(shù)機(jī)制 2.標(biāo)記-清除 3.分代回收
請參考:Python中垃圾回收機(jī)制
3. 魔法函數(shù) _call_怎么使用?
答: call 可以把類實(shí)例當(dāng)做函數(shù)調(diào)用。 使用示例如下
添加鏈接描述
4. 如何判斷一個對象是函數(shù)還是方法?
答:看代碼已經(jīng)結(jié)果就懂了
from types import MethodType, FunctionType
class Bar:
def foo(self):
pass
def foo2():
pass
def run():
print(“foo 是函數(shù)”, isinstance(Bar().foo, FunctionType))
print(“foo 是方法”, isinstance(Bar().foo, MethodType))
print(“foo2 是函數(shù)”, isinstance(foo2, FunctionType))
print(“foo2 是方法”, isinstance(foo2, MethodType))
if name == ‘main’:
run()
輸出
foo 是函數(shù) False
foo 是方法 True
foo2 是函數(shù) True
foo2 是方法 False
5. @classmethod 和 @staticmethod 用法和區(qū)別
答: 相同之處:@staticmethod 和@classmethod 都可以直接類名.方法名()來調(diào)用,不用在示例化一個類。 @classmethod 我們要寫一個只在類中運(yùn)行而不在實(shí)例中運(yùn)行的方法。如果我們想讓方法不在實(shí)例中運(yùn)行,可以這么做:
def iget_no_of_instance(ins_obj):
return ins_obj.class.no_inst
class Kls(object):
no_inst = 0
ik1 = Kls()
ik2 = Kls()
print(iget_no_of_instance(ik1))
@staticmethod 經(jīng)常有一些跟類有關(guān)系的功能但在運(yùn)行時又不需要實(shí)例和類參與的情況下需要用到靜態(tài)方法
IND = ‘ON’
class Kls(object):
def init(self, data):
self.data = data
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
6. Python 中的接口如何實(shí)現(xiàn)?
答: 接口提取了一群類共同的函數(shù),可以把接口當(dāng)做一個函數(shù)的集合,然后讓子類去實(shí)現(xiàn)接口中的函數(shù)。但是在 Python 中根本就沒有一個叫做 interface 的關(guān)鍵字,如果非要去模仿接口的概念,可以使用抽象類來實(shí)現(xiàn)。抽象類是一個特殊的類,它的特殊之處在于只能被繼承,不能被實(shí)例化。使用 abc 模塊來實(shí)現(xiàn)抽象類。
7. Python 中的反射了解么?
答:Python 的反射機(jī)制設(shè)定較為簡單,一共有四個關(guān)鍵函數(shù)分別是 getattr、hasattr、setattr、delattr。
8. metaclass 作用?以及應(yīng)用場景?
答: metaclass 即元類,metaclass 是類似創(chuàng)建類的模板,所有的類都是通過他來 create 的(調(diào)用new),這使得你可以自由的控制創(chuàng)建類的那個過程,實(shí)現(xiàn)你所需要的功能。 我們可以使用元類創(chuàng)建單例模式和實(shí)現(xiàn) ORM 模式。
9. hasattr()、getattr()、setattr() 的用法
答:這三個方法屬于 Python 的反射機(jī)制里面的,hasattr 可以判斷一個對象是否含有某個屬性,getattr 可以充當(dāng) get 獲取對象屬性的作用。而 setattr 可以充當(dāng) person.name = "liming"的賦值操作。代碼示例如下:
class Person():
def init(self):
self.name = “l(fā)iming”
self.age = 12
def run():
if hasattr(Person, “show”):
print(“判斷 Person 類是否含有 show 方法”)
if name == ‘main’:
run()
10. 請列舉你知道的 Python 的魔法方法及用途。
答:
1 init:
類的初始化方法。它獲取任何傳給構(gòu)造器的參數(shù)(比如我們調(diào)用 x = SomeClass(10, ‘foo’) , __init__就會接到參數(shù) 10 和 ‘foo’ 。 __init__在 Python 的類定義中用的最多。
2 new:
__new__是對象實(shí)例化時第一個調(diào)用的方法,它只取下 cls 參數(shù),并把其他參數(shù)傳給 init 。 __new__很少使用,但是也有它適合的場景,尤其是當(dāng)類繼承自一個像元組或者字符串這樣不經(jīng)常改變的類型的時候.
3 del:
__new__和 __init__是對象的構(gòu)造器, __del__是對象的銷毀器。它并非實(shí)現(xiàn)了語句 del x (因此該語句不等同于 x.del())。而是定義了當(dāng)對象被垃圾回收時的行為。 當(dāng)對象需要在銷毀時做一些處理的時候這個方法很有用,比如 socket 對象、文件對象。但是需要注意的是,當(dāng) Python 解釋器退出但對象仍然存活的時候,__del__并不會 執(zhí)行。 所以養(yǎng)成一個手工清理的好習(xí)慣是很重要的,比如及時關(guān)閉連接。
11. 如何知道一個 Python 對象的類型?
答:可以通過 type 方法
12. Python 的傳參是傳值還是傳址?
答:Python 中的傳參即不是傳值也不是傳地址,傳的是對象的引用。
13. Python 中的元類 (metaclass) 使用舉例
答:可以使用元類實(shí)現(xiàn)一個單例模式,代碼如下
class Singleton(type):
def init(self, *args, **kwargs):
print(“in init”)
self.__instance = None
super(Singleton, self).init(*args, **kwargs)
class Foo(metaclass=Singleton):
pass # 在代碼執(zhí)行到這里的時候,元類中的__new__方法和__init__方法其實(shí)已經(jīng)被執(zhí)行了,而不是在 Foo 實(shí)例化的時候執(zhí)行。且僅會執(zhí)行一次。
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)
14. 簡述 any() 和 all() 方法
答:
any()與all()函數(shù)的區(qū)別:any是任意,而all是全部。
any(x):判斷 x 對象是否為空對象,如果都為空、0、false,則返回 false,如果不都為空、0、false,則返回 true。
all(x):如果 all(x) 參數(shù) x 對象的所有元素不為 0、’’、False 或者 x 為空對象,則返回 True,否則返回 False。
15. filter 方法求出列表所有奇數(shù)并構(gòu)造新列表,a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
答:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] b = filter(lambda x: x % 2 == 1, a) print(b) print("-------------------------") print(list(b))運(yùn)行結(jié)果:
<filter object at 0x000000000267F048> ------------------------- [1, 3, 5, 7, 9]其實(shí)現(xiàn)在不推薦使用 filter,map 等方法了,一般列表生成式就可以搞定了。
16. 什么是猴子補(bǔ)丁?
答: 猴子補(bǔ)丁(monkey patching):在運(yùn)行時動態(tài)修改模塊、類或函數(shù),通常是添加功能或修正缺陷。猴子補(bǔ)丁在代碼運(yùn)行時內(nèi)存中發(fā)揮作用,不會修改源碼,因此只對當(dāng)前運(yùn)行的程序?qū)嵗行?。因為猴子補(bǔ)丁破壞了封裝,而且容易導(dǎo)致程序與補(bǔ)丁代碼的實(shí)現(xiàn)細(xì)節(jié)緊密耦合,所以被視為臨時的變通方案,不是集成代碼的推薦方式。大概是下面這樣的一個效果
def post():
print(“this is post”)
print(“想不到吧”)
class Http():
@classmethod
def get(self):
print(“this is get”)
def main():
Http.get=post #動態(tài)的修改了 get 原因的功能,
if name == ‘main’:
main()
Http.get()
17. 在 Python 中是如何管理內(nèi)存的?
答: 垃圾回收:Python 不像 C++,Java 等語言一樣,他們可以不用事先聲明變量類型而直接對變量進(jìn)行賦值。對 Python 語言來講,對象的類型和內(nèi)存都是在運(yùn)行時確定的。這也是為什么我們稱 Python 語言為動態(tài)類型的原因(這里我們把動態(tài)類型可以簡單的歸結(jié)為對變量內(nèi)存地址的分配是在運(yùn)行時自動判斷變量類型并對變量進(jìn)行賦值)。
引用計數(shù):Python 采用了類似 Windows 內(nèi)核對象一樣的方式來對內(nèi)存進(jìn)行管理。每一個對象,都維護(hù)這一個對指向該對對象的引用的計數(shù)。當(dāng)變量被綁定在一個對象上的時候,該變量的引用計數(shù)就是 1,(還有另外一些情況也會導(dǎo)致變量引用計數(shù)的增加),系統(tǒng)會自動維護(hù)這些標(biāo)簽,并定時掃描,當(dāng)某標(biāo)簽的引用計數(shù)變?yōu)?0 的時候,該對就會被回收。
內(nèi)存池機(jī)制 Python 的內(nèi)存機(jī)制以金字塔行,1、2 層主要有操作系統(tǒng)進(jìn)行操作
第 0 層是 C 中的 malloc,free 等內(nèi)存分配和釋放函數(shù)進(jìn)行操作
第 1 層和第 2 層是內(nèi)存池,有 Python 的接口函數(shù) PyMem_Malloc 函數(shù)實(shí)現(xiàn),當(dāng)對象小于 256K 時有該層直接分配內(nèi)存
第 3 層是最上層,也就是我們對 Python 對象的直接操作
在 C 中如果頻繁的調(diào)用 malloc 與 free 時,是會產(chǎn)生性能問題的.再加上頻繁的分配與釋放小塊的內(nèi)存會產(chǎn)生內(nèi)存碎片。Python 在這里主要干的工作有:
如果請求分配的內(nèi)存在 1~256 字節(jié)之間就使用自己的內(nèi)存管理系統(tǒng),否則直接使用 malloc。
這里還是會調(diào)用 malloc 分配內(nèi)存,但每次會分配一塊大小為 256k 的大塊內(nèi)存。
經(jīng)由內(nèi)存池登記的內(nèi)存到最后還是會回收到內(nèi)存池,并不會調(diào)用 C 的 free 釋放掉以便下次使用。對于簡單的 Python 對象,例如數(shù)值、字符串,元組(tuple 不允許被更改)采用的是復(fù)制的方式(深拷貝?),也就是說當(dāng)將另一個變量 B 賦值給變量 A 時,雖然 A 和 B 的內(nèi)存空間仍然相同,但當(dāng) A 的值發(fā)生變化時,會重新給 A 分配空間,A 和 B 的地址變得不再相同。
18. 當(dāng)退出 Python 時是否釋放所有內(nèi)存分配?
答:不是的,循環(huán)引用其他對象或引用自全局命名空間的對象的模塊,在 Python 退出時并非完全釋放。
另外,也不會釋放 c 庫保留的內(nèi)存部分
總結(jié)
以上是生活随笔為你收集整理的Python面试题总结(9)--高级特性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Eclipse —— 官网下载地址
- 下一篇: 元胞自动机python代码_Python