当退出python时是否释放全部内存_Python面试题:高级特性考察
1、函數裝飾器有什么作用?請列舉說明?
答: 裝飾器就是一個函數,它可以在不需要做任何代碼變動的前提下給一個函數增加額外功能,啟動裝飾的效果。 它經常用于有切面需求的場景,比如:插入日志、性能測試、事務處理、緩存、權限校驗等場景。 下面是一個日志功能的裝飾器from functools import wraps
def log(label):
def decorate(func):
@wraps(func)
def _wrap(*args,**kwargs):
try:
func(*args,**kwargs)
print("name",func.__name__)
except Exception as e:
print(e.args)
return _wrap
return decorate
@log("info")
def foo(a,b,c):
print(a+b+c)
print("in foo")
#decorate=decorate(foo)
if __name__ == '__main__':
foo(1,2,3)
#decorate()
2、Python 垃圾回收機制?
答:Python 不像 C++,Java 等語言一樣,他們可以不用事先聲明變量類型而直接對變量進行賦值。對 Python 語言來講,對象的類型和內存都是在運行時確定的。這也是為什么我們稱 Python 語言為動態類型的原因。
主要體現在下面三個方法:
(1)引用計數機制 (2)標記-清除 (3)分代回收
3、魔法函數 _call_怎么使用?
答: call 可以把類實例當做函數調用。 使用示例如下class Bar:
def __call__(self, *args, **kwargs):
print('in call')
if __name__ == '__main__':
b = Bar()
b()
4、如何判斷一個對象是函數還是方法?from types import MethodType, FunctionType
class Bar:
def foo(self):
pass
def foo2():
pass
def run():
print("foo 是函數", isinstance(Bar().foo, FunctionType))
print("foo 是方法", isinstance(Bar().foo, MethodType))
print("foo2 是函數", isinstance(foo2, FunctionType))
print("foo2 是方法", isinstance(foo2, MethodType))
if __name__ == '__main__':
run()
輸出:
foo 是函數 False
foo 是方法 True
foo2 是函數 True
foo2 是方法 False
5、@classmethod 和 @staticmethod 用法和區別
答:相同之處:@staticmethod 和@classmethod 都可以直接類名.方法名()來調用,不用在示例化一個類。 @classmethod 我們要寫一個只在類中運行而不在實例中運行的方法。如果我們想讓方法不在實例中運行,可以這么做:def iget_no_of_instance(ins_obj):
return ins_obj.__class__.no_inst
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
ik1 = Kls()
ik2 = Kls()
print(iget_no_of_instance(ik1))
@staticmethod 經常有一些跟類有關系的功能但在運行時又不需要實例和類參與的情況下需要用到靜態方法class Kls(object):
def __init__(self, data):
self.data = data
@staticmethod
def check_ind():
return (IND == 'ON')
def do_reset(self):
if self.check_ind():
print('Reset done for:', self.data)
def set_db(self):
if self.check_ind():
self.db = 'New db connection'
print('DB connection made for: ', self.data)
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
6、Python 中的接口如何實現?
答: 接口提取了一群類共同的函數,可以把接口當做一個函數的集合,然后讓子類去實現接口中的函數。但是在 Python 中根本就沒有一個叫做 interface 的關鍵字,如果非要去模仿接口的概念,可以使用抽象類來實現。抽象類是一個特殊的類,它的特殊之處在于只能被繼承,不能被實例化。使用 abc 模塊來實現抽象類。
7、Python 中的反射了解么?
答:Python 的反射機制設定較為簡單,一共有四個關鍵函數分別是 getattr、hasattr、setattr、delattr。
8、metaclass 作用?以及應用場景?
答: metaclass 即元類,metaclass 是類似創建類的模板,所有的類都是通過他來 create 的(調用new),這使得你可以自由的控制創建類的那個過程,實現你所需要的功能。 我們可以使用元類創建單例模式和實現 ORM 模式。
9、hasattr()、getattr()、setattr() 的用法
答:這三個方法屬于 Python 的反射機制里面的,hasattr 可以判斷一個對象是否含有某個屬性,getattr 可以充當 get 獲取對象屬性的作用。而 setattr 可以充當 person.name = "liming"的賦值操作。代碼示例如下:class Person():
def __init__(self):
self.name = "liming"
self.age = 12
def show(self):
print(self.name)
print(self.age)
def set_name(self):
setattr(Person, "sex", "男")
def get_name(self):
print(getattr(self, "name"))
print(getattr(self, "age"))
print(getattr(self, "sex"))
def run():
if hasattr(Person, "show"):
print("判斷 Person 類是否含有 show 方法")
Person().set_name()
Person().get_name()
if __name__ == '__main__':
run()
10、請列舉你知道的 Python 的魔法方法及用途。
1 __init__:
類的初始化方法。它獲取任何傳給構造器的參數(比如我們調用 x = SomeClass(10, ‘foo’) , __init__就會接到參數 10 和 ‘foo’ 。 __init__在 Python 的類定義中用的最多。
2 __new__:
new__是對象實例化時第一個調用的方法,它只取下 cls 參數,并把其他參數傳給 __init 。 __new__很少使用,但是也有它適合的場景,尤其是當類繼承自一個像元組或者字符串這樣不經常改變的類型的時候.
3 __del__:
__new__和 __init__是對象的構造器, __del__是對象的銷毀器。它并非實現了語句 del x (因此該語句不等同于 x.__del__())。而是定義了當對象被垃圾回收時的行為。 當對象需要在銷毀時做一些處理的時候這個方法很有用,比如 socket 對象、文件對象。但是需要注意的是,當 Python 解釋器退出但對象仍然存活的時候,__del__并不會 執行。 所以養成一個手工清理的好習慣是很重要的,比如及時關閉連接。
11、如何知道一個 Python 對象的類型?
答:可以通過 type 方法
12、Python 的傳參是傳值還是傳址?
答:Python 中的傳參即不是傳值也不是傳地址,傳的是對象的引用。
13、Python 中的元類 (metaclass) 使用舉例
答:可以使用元類實現一個單例模式,代碼如下class Singleton(type):
def __init__(self, *args, **kwargs):
print("in __init__")
self.__instance = None
super(Singleton, self).__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
print("in __call__")
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
class Foo(metaclass=Singleton):
pass # 在代碼執行到這里的時候,元類中的__new__方法和__init__方法其實已經被執行了,而不是在 Foo 實例化的時候執行。且僅會執行一次。
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)
14、簡述 any() 和 all() 方法
答: any(x):判斷 x 對象是否為空對象,如果都為空、0、false,則返回 false,如果不都為空、0、false,則返回 true。 all(x):如果 all(x) 參數 x 對象的所有元素不為 0、''、False 或者 x 為空對象,則返回 True,否則返回 False。
15、filter 方法求出列表所有奇數并構造新列表a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(list(filter(lambda x: x % 2 == 1, a)))
其實現在不推薦使用 filter,map 等方法了,一般列表生成式就可以搞定了。
16、什么是猴子補丁?
答: 猴子補丁(monkey patching):在運行時動態修改模塊、類或函數,通常是添加功能或修正缺陷。猴子補丁在代碼運行時內存中)發揮作用,不會修改源碼,因此只對當前運行的程序實例有效。因為猴子補丁破壞了封裝,而且容易導致程序與補丁代碼的實現細節緊密耦合,所以被視為臨時的變通方案,不是集成代碼的推薦方式。大概是下面這樣的一個效果def post():
print("this is post")
print("想不到吧")
class Http():
@classmethod
def get(self):
print("this is get")
def main():
Http.get=post #動態的修改了 get 原因的功能,
if __name__ == '__main__':
main()
Http.get()
17、在 Python 中是如何管理內存的?
答: 垃圾回收:Python 不像 C++,Java 等語言一樣,他們可以不用事先聲明變量類型而直接對變量進行賦值。對 Python 語言來講,對象的類型和內存都是在運行時確定的。這也是為什么我們稱 Python 語言為動態類型的原因(這里我們把動態類型可以簡單的歸結為對變量內存地址的分配是在運行時自動判斷變量類型并對變量進行賦值)。
引用計數:Python 采用了類似 Windows 內核對象一樣的方式來對內存進行管理。每一個對象,都維護這一個對指向該對對象的引用的計數。當變量被綁定在一個對象上的時候,該變量的引用計數就是 1,(還有另外一些情況也會導致變量引用計數的增加),系統會自動維護這些標簽,并定時掃描,當某標簽的引用計數變為 0 的時候,該對就會被回收。
內存池機制 Python 的內存機制以金字塔行,1、2 層主要有操作系統進行操作
第 0 層是 C 中的 malloc,free 等內存分配和釋放函數進行操作
第 1 層和第 2 層是內存池,有 Python 的接口函數 PyMem_Malloc 函數實現,當對象小于 256K 時有該層直接分配內存
第 3 層是最上層,也就是我們對 Python 對象的直接操作
在 C 中如果頻繁的調用 malloc 與 free 時,是會產生性能問題的.再加上頻繁的分配與釋放小塊的內存會產生內存碎片。Python 在這里主要干的工作有:
如果請求分配的內存在 1~256 字節之間就使用自己的內存管理系統,否則直接使用 malloc。
這里還是會調用 malloc 分配內存,但每次會分配一塊大小為 256k 的大塊內存。
經由內存池登記的內存到最后還是會回收到內存池,并不會調用 C 的 free 釋放掉以便下次使用。對于簡單的 Python 對象,例如數值、字符串,元組(tuple 不允許被更改)采用的是復制的方式(深拷貝?),也就是說當將另一個變量 B 賦值給變量 A 時,雖然 A 和 B 的內存空間仍然相同,但當 A 的值發生變化時,會重新給 A 分配空間,A 和 B 的地址變得不再相同。
18、當退出 Python 時是否釋放所有內存分配?
答:不是的,循環引用其他對象或引用自全局命名空間的對象的模塊,在 Python 退出時并非完全釋放。另外,也不會釋放 c 庫保留的內存部分
總結
以上是生活随笔為你收集整理的当退出python时是否释放全部内存_Python面试题:高级特性考察的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贵州茅台跌破2200元关口 白酒股怎么了
- 下一篇: python画椭圆turtle_Pyth