網易遊戲面試經驗(二)

前言

在以前我寫過一篇博客,講述了python的閉包和裝飾器,python的裝飾器一直是面試熱點,也是python很重要的特性之一,不過我認爲閉包是裝飾器的基礎,比裝飾器擁有更寬廣的概念和做用,因此若是面試官問我關於裝飾器的問題,我都會從閉包的角度去分析裝飾器,關於這個大塊面試官問了我以下幾個問題:什麼是裝飾器?什麼是閉包?閉包和裝飾器的做用?閉包和裝飾器的使用場景?下面從這幾個問題出發,在前一篇博客的基礎之上更加深入的探討關於閉包和裝飾器的知識html

正文

關於閉包的概念,我從網上找了以下幾種說法:python

  • This technique of using the values of outside parameters within a dynamic function is called closures
  • a closure is simply a function with free variables, where the bindings for all such variables are known in advance
  • a closure is a function (object) that remembers its creation environment (enclosing scope)
  • This technique by which some data gets attached to the code is called closure in Python
  • A closure occurs when a function has access to a local variable from an enclosing scope that has finished its execution

上面的話語基本涵蓋了閉包的特性,關於這些語句的理解,我仍是先列舉一個很是簡單的例子:面試

# coding="utf-8"
def fun(msg):
    def nested_fun():
        print msg
    return nested_fun

new_fun = fun("i like python")
new_fun()

上面的代碼首先定義了一個函數fun,在這個函數之中再定義了一個嵌套函數,以後返回了這個函數,在這個函數以外,從新將fun函數包括msg參數賦值給了new_fun,以後執行new_fun()函數,運行這段代碼,能夠發如今console中打印出了i love python這句話。上面的代碼有兩個注意點:1.函數也是一種對象,能夠做爲參數返回和傳遞;2.new_fun=fun("i like python")這句代碼實際上是將new_fun指向了fun函數的返回值nested_fun函數,在執行new_fun函數的時候其實在執行了nested_fun函數,在這個函數中打印出的msg對象其實來自於上層函數,並非本身的本地變量,爲何還會打印出來呢?因此這就是閉包,根據這個例子能夠很好的體會上面列出的幾種說法。
在python中閉包所知足的條件爲:閉包

  1. 必須擁有嵌套函數
  2. 嵌套函數調用定義在閉包函數裏面的值
  3. 閉包函數必須返回嵌套函數

裝飾器和閉包能夠實現必定的封裝功能,將函數或者變量封裝起來,同時利用他們能夠減小代碼冗餘,減小一些重複工做量。下面舉一個例子,若是如今咱們想實現一個簡單的乘法函數,好比times2(n)函數就是給n*2,times5(n)實現給n乘以5,這個功能可使用默認值很容易的實現,代碼以下:app

def times2(n, x=2):
    return n * x

print times2(3)

可是這有個明顯的缺點,每一個times()函數都須要進行定義細節,如今能夠用閉包來實現,代碼以下:ide

def multiplier(n):
    def multi(x):
        return x * n
    return multi

times2 = multiplier(2)
times5 = multiplier(5)

print times2(4)
print times5(4)

這段代碼的美妙你們能夠好好體會一下。
說完了閉包,再說一說裝飾器,裝飾器就是用函數或者類去封裝(裝飾)另外一個對象,裝飾器支持和被封裝的對象相同的接口,因此被裝飾的對象甚至感受不到本身被裝飾了,在python中,裝飾器更多的是一個函數將另外一個函數做爲參數,他會利用閉包來實現整個裝飾功能,和上面舉得閉包的例子不一樣的是,裝飾器利用的是閉包能夠捕獲函數。
裝飾器的經常使用場景以下:函數

  • 注入參數
  • 記錄函數行爲
  • 預處理/後處理
  • 修改調用時的上下文

下面簡單的列舉一個記錄函數行爲的裝飾器的使用:es5

def logging(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print func.__name__, args, kwargs
        return res
    return wrapper

@logging
def fib(n):
    if n == 1 or n == 0:
        return 1
    return fib(n-1) + fib(n-2)

print fib(10)

上面的裝飾器代碼實現了打印被裝飾的函數的執行狀況,你們能夠本身運行。code

總結

語言的美會獲得承認和傳播,好比lamdba函數,瞭解了語言的特性以後,能夠極大的提升工做效率,增長代碼的美感,提升代碼的健壯性。htm

相關文章
相關標籤/搜索