初學Python(九)——函式

Coffee_zq發表於2016-10-23

初學Python(九)——函式

  

  初學Python,主要整理一些學習到的知識點,這次是函式。

 

函式定義:

# -*- coding:utf-8 -*-  
  
  
#函式的定義  
def my_function(x):  
    if x>0:  
        return x  
    elif x<0:  
        return -x  
    else:  
        pass  
#函式的呼叫  
a = my_function(-1)  
b = my_function(2)  
c = my_function(0)  
print a,b,c  
  
#空函式,pass為佔位符  
def empty_function(x):  
    pass  
  
print empty_function(-1)  
  
#引數檢查,給my_function函式加上引數檢查  
def my_function(x):  
    if not isinstance(x,(int,float)):  
        #raise相當於java中的throw,丟擲異常  
        raise TypeError('UnExpectedType')  
    elif x>=0:  
        return x  
    else:  
        return -x  
  
print my_function(1)  
print my_function(-1)  
#print my_function('a')  
#返回多個值,牛er逼  
def multi_function(x):  
    x0 = x+1  
    x1 = x-1  
    #返回的其實就是一個tuple  
    return x0,x1  
  
print multi_function(2) 

 

引數:

#-*- coding:utf-8 -*-  
  
''''' 
預設引數: 
就是你不指定該引數的值時, 
該引數有一個預設值 
'''  
def default_para(x,n=2,s=3):  
    return x*n*s  
print default_para(2)  
print default_para(2,3)  
print default_para(2,n=5)  
print default_para(2,s=3)  
print default_para(2,n=2,s=4)  
  
  
#天坑  
def default_para_hole(L=[]):  
    L.append('ITFOOTBALLCLUB')  
    return L  
print default_para_hole()  
print default_para_hole()  
''''' 
第一遍為['ITFOOTBALLCLUB'] 
第二遍為['ITFOOTBALLCLUB', 'ITFOOTBALLCLUB'] 
問題在於L的值在定義函式時就已經指明瞭物件, 
如果你不指定引數,他預設只指向該物件, 
如果該物件變了,那麼預設引數的值也會變 
所以要儘量使用不可變物件[]改為None 
'''  
  
#去天坑版,None為不可變物件  
def default_para_no_hole(L=None):  
    if L is None:  
        L = []  
    L.append('ITFOOTBALLCLUB')  
    return L  
  
print default_para_no_hole()  
print default_para_no_hole()  
  
  
''''' 
可變引數: 
意思就是引數的個數是0..n個的 
'''  
#不用可變引數也能傳入多個引數,使用list和tuple  
def changeable_para(multi):  
    sum = 0  
    for n in multi:  
        sum+=n  
  
    return sum  
#0  
print changeable_para([])  
#list  
print changeable_para([1,2,3,4,5])  
#tuple  
print changeable_para((1,2,3,4))  
  
''''' 
上面的方式也能實現傳入0..n個引數的傳遞, 
但是需要實現組裝為list或tuple 
如果你本來就有一個list或tuple,這麼用 
無可厚非 
如果你不想每次都組裝,你就可以使用可變引數 
'''  
  
#改裝版,可變引數就是在引數前加上一個星號(*),so easy  
def changeable_para_update(*multi):  
    sum = 0  
    for n in multi:  
        sum+=n  
    return sum  
  
print changeable_para_update(1,2,3)  
  
#如果你本來就有list,可變引數也能融合  
name = [1,3,4,7,9]  
print changeable_para_update(*name)  
  
#這樣是不是犀利多了  
  
  
''''' 
關鍵字引數: 
傳遞0...n個帶引數名的引數 
引數名前加2個星號 
'''  
  
def key_para(x,y,n=2,*numbers,**kp):  
    print x,y,n,numbers,kp  
#只有必選引數      
key_para(1,2)  
#必選,預設  
key_para(1,2,3)  
#必選,預設,關鍵字  
key_para(1,2,3,kw=99)  
#必選,預設,可變(陣列)  
key_para(1,2,3,*[1,2])  
#必選,預設,可變(陣列)  
key_para(1,2,3,*(1,2))  
#必選,預設,可變  
key_para(1,2,3,1,2)  
#必選,預設,關鍵字(字典)  
key_para(1,2,3,**{'test':'af','pld':'afe'})  
#必選,預設,可變,關鍵字  
key_para(1,2,3,*(1,2),kw=99)  
  
  
#所有的函式引數都可以用func(*args,**kw)來呼叫 

 

遞迴函式:

# -*- coding:utf-8 -*-  
  
''''' 
遞迴函式 
'''  
  
def fact(n):  
    if n==1:  
        return 1  
    return fact(n-1)*n  
  
print fact(10)  
  
print fact(100)  
  
  
#尾遞迴解決棧溢位  
#棧溢位  
#print fact(1000)  
#尾遞迴  
def fact(n):  
    return fact_iter(1,1,n)  
def fact_iter(n,count,max):  
    if count > max:  
        return n  
    return fact_iter(n*count,count+1,max)  
''''' 
但是python沒有對尾遞迴做優化, 
所以上面的尾遞迴依然會棧溢位, 
(那還說個毛啊),不過國外有 
人寫了個裝飾器,可以解決這個問題 
有時間研究一下 
'''  

 

防止溢位:

#!/usr/bin/env python2.4  
# This program shows off a python decorator(  
# which implements tail call optimization. It  
# does this by throwing an exception if it is   
# it's own grandparent, and catching such   
# exceptions to recall the stack.  
  
import sys  
  
class TailRecurseException:  
  def __init__(self, args, kwargs):  
    self.args = args  
    self.kwargs = kwargs  
  
def tail_call_optimized(g):  
  """ 
  This function decorates a function with tail call 
  optimization. It does this by throwing an exception 
  if it is it's own grandparent, and catching such 
  exceptions to fake the tail call optimization. 
   
  This function fails if the decorated 
  function recurses in a non-tail context. 
  """  
  def func(*args, **kwargs):  
    f = sys._getframe()  
    if f.f_back and f.f_back.f_back \  
        and f.f_back.f_back.f_code == f.f_code:  
      raise TailRecurseException(args, kwargs)  
    else:  
      while 1:  
        try:  
          return g(*args, **kwargs)  
        except TailRecurseException, e:  
          args = e.args  
          kwargs = e.kwargs  
  func.__doc__ = g.__doc__  
  return func  
 
@tail_call_optimized  
def factorial(n, acc=1):  
  "calculate a factorial"  
  if n == 0:  
    return acc  
  return factorial(n-1, n*acc)  
  
print factorial(10000)  
# prints a big, big number,  
# but doesn't hit the recursion limit.  
 
@tail_call_optimized  
def fib(i, current = 0, next = 1):  
  if i == 0:  
    return current  
  else:  
    return fib(i - 1, next, current + next)  
  
print fib(10000)  
# also prints a big number,  
# but doesn't hit the recursion limit. 

 

相關文章