Python入門學習(六)

在熟悉了Python中常用的一些內置函數, 那接下來我們定義一個自己的函數吧

def add(x, y):      return x + y

函數

函數語法
def functonname(parameters):      ...      return result
定義空函數
def nop():      pass

實際上 pass 是用來作為佔位符的. 比如現在還沒想好怎麼寫函數的代碼, 就可以先放一個pass, 讓其他代碼可以運行起來.

函數也是Object
def pow(x, y):      result = 1      for i in range(0, y):          result = result * x      return result    print(pow) #<function pow at 0x104147e18>

函數也是內存中的一塊區域, 函數名指向這塊區域.

fn = pow  print(fn) #<function pow at 0x104147e18>  print(fn(2, 10)) #1024

參數

  • 必選參數
  • 默認參數
  • 可變參數
  • 關鍵字參數
  • 命名關鍵字參數

必選參數

def pow(x, y):      result = 1      for i in range(0, y):          result = result * x      return result    t = pow(2, 3)  print(t) # 8

上面函數中, 需要兩個參數分別是 x, y. 這兩個參數都是必選參數, 缺一不可. pow函數中 x 為底數, y 為指數, 現在我想讓指數默認為 2

默認參數

def pow(x, y = 2):      result = 1      for i in range(0, y):          result = result * x      return result    t = pow(2)  print(t) # 4

設, 我要求多個數的和. 具體有多個參數, 我也不知道

可變參數

def sum_1(numbers):      s = 0      for x in numbers:          s += x      return s    def sum_2(*numbers):      s = 0      for x in numbers:          s += x      return s    arr = [1, 2, 4]  print(sum_1(arr))  print(sum_2(1, 2, 4))  print(sum_2(*arr))

關鍵字參數

可變參數允許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝為一個tuple。而關鍵字參數允許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝為一個dict

def person(name, age, **kw) :  # ** => dict      print("kw tyep is", type(kw))      if "city" in kw :          print("city :", kw["city"])      if "job" in kw:          print("job :", kw.get("job"))      print("name:", name, ", age:", age, ", other:", kw)      person("Jion", 18, city = "Beijing")  person(name = "Tom", city = "Beijing", age = 17)  extra = {'city': 'Beijing', 'job': 'Engineer'}  person("Jion", 18, **extra)

命名關鍵字參數

如果要限制關鍵字參數的名字,就可以用命名關鍵字參數,例如,只接收city和job作為關鍵字參數

def person(name, age, *, city, job):      print(name, age, city, job)

命名關鍵字參數需要一個特殊分隔符 * ,* 後面的參數被視為命名關鍵字參數。

>>> person('Jack', 24, city='Beijing', job='Engineer')  Jack 24 Beijing Engineer

如果函數定義中已經有了一個可變參數,後面跟着的命名關鍵字參數就不再需要一個特殊分隔符 * 了.

def person(name, age, *, city = "Beijing", job):      # 要限制關鍵字參數的名字, 就要用到 "命名關鍵字參數"      # * 後的參數, 被視為"命名關鍵字參數"      print(name, age, city, job)  person("Jack", 24, job = "Engineer")  x = {"city":"Shanghai", "job":"Engineer"}  person("Jack", 23, **x)  person("Jack", 23, city = "Beijing", job = "Engineer")    def person(name, age, *args, city, job):      print(name, age, args, city, job)  x = {"A":1, "B":2, "C":3}  # 當實參為 *x 時, 會將實參中的key以tuple(元組)的形式, 傳遞到方法內  # person("Jack", 23, *x, city = "Beijing", job = "Engineer") # Jack 23 ('A', 'B', 'C') Beijing Engineer    # 當實參為 x 時, 會將實參的整體內容做為tuple(元組)的一個元素, 傳遞到方法內  person("Jack", 23, x, city = "Beijing", job = "Engineer") # Jack 23 ({'A': 1, 'B': 2, 'C': 3},) Beijing Engineer

返回值

返回常用類型

def abs(x):      if(x >= 0):          return x      else:          retrun -x    print(abs(-1)) #1

return 類似出棧操作, return之後的語句則不被執行

返回多個值

def show(x, y, z):      return x  * y * z, x + y + z    x = show(2, 3, 4)  print(x[0], x[1]) #24 9  print(x) #(24, 9)

當函數返回多個值時, 實際上是把多個需要返回的值, 封裝成一個tuple

返回函數

剛剛說過, 函數也是一個Object, 所以也可以作為返回值進行返回

遞歸
def trim(s):      if (s == ''):          return ''      if (ord(s[:1]) == 32):          return trim(s[1:])      elif (ord(s[-1:]) == 32):          return trim(s[:-1])      else:          return s

這是一個去除字符串前後空格的函數, 首先檢測字符串的第一位是不是空格, 如果是去掉第一位, 再次檢查新字符串的第一位 直至不是後, 檢查字符串的最後一位, 如果是, 則去掉最後一位, 再次檢測新字符串的最後一位.直到最後一位,不再是空格.

閉包
def make_adder(addend):      def adder(augend):          return augend + addend      return adder    p = make_adder(23)  q = make_adder(44)    print(p(100)) #123  print(q(100)) #144

閉包: 可以形象的把它理解為一個封閉的包裹,這個包裹就是一個函數,當然還有函數內部對應的邏輯,包裹裏面的東西就是自由變量,自由變量可以在隨着包裹到處遊盪。當然還得有個前提,這個包裹是被創建出來的。 在通過Python的語言介紹一下,一個閉包就是你調用了一個函數A,這個函數A返回了一個函數B給你。這個返回的函數B就叫做閉包。你在調用函數A的時候傳遞的參數就是自由變量。

def func(name):      def inner_func(age):          print 'name:', name, 'age:', age      return inner_func    bb = func('the5fire')  bb(26)  # >>> name: the5fire age: 26

這裏面調用func的時候就產生了一個閉包——inner_func,並且該閉包持有自由變量——name,因此這也意味着,當函數func的生命周期結束之後,name這個變量依然存在,因為它被閉包引用了,所以不會被回收。

def hellocounter (name):      count = 0      def counter():          # 如果不加 nonlocal 會報錯          # UnboundLocalError: local variable 'count' referenced before assignment          nonlocal count          count += 1          print ('Hello {0}, {1} access!'.format(name, count))      return counter    hello = hellocounter('ysisl')  hello()  hello()  hello()

在閉包函數內, 可以直接訪問父函數作用域下的變量, 但不可以修改. python3裏面,引入了一個關鍵字:nonlocal,這個關鍵字是幹什麼的? 就是告訴python程序, 我的這個count變量是再外部定義的, 你去外面找吧. 然後python就去外層函數找, 然後就找到了count = 0 這個定義和賦值, 程序就能正常執行了.

裝飾器

裝飾器: 是對閉包的一種實際運用的場景.

def makebold(fn):      def wrapped():          return "<b>" + fn() + "</b>"      return wrapped    def makeitalic(fn):      def wrapped():          return "<i>" + fn() + "</i>"      return wrapped    @makebold  @makeitalic  def hello():      return "hello world"    print hello() # <b><i>hello world</i></b>

相當於 makebold(makeitalic(hello()))

import time    def timecost(func):      def wrapper(*args, **kw):          def fn(*args, **kw):              start = int(time.time())              print("Call {0}() Before [{1}]".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))))              func(*args, **kw)              print("Call {0}() After [{1}]".format(func.__name__, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))))              end = int(time.time())              print("Run Cost Time {0}s".format(end - start))            return fn(*args, **kw)      return wrapper    @timecost  def now_datetime(format):      now = int(time.time())      print(time.strftime(format, time.localtime(now)))    now_datetime("%H:%M:%S")    # Call now_datetime() Before [2018-01-15 00:24:17]  # 00:24:17  # Call now_datetime() After [2018-01-15 00:24:17]  # Run Cost Time 0s  # 在方法前後加入自己想要的內容, 哈哈, 這就是傳說中的AOP嗎?