1. 程式人生 > 實用技巧 >Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

  1. 預設引數必須放在最後面,否則會報:

    SyntaxError: non-default argument follows default argument
    # 可寫函式說明
    def printinfo( age=35,name):   # 預設引數不在最後,會報錯
        "列印任何傳入的字串"
        print("名字: ", name)
        print("年齡: ", age)
        return
  2. def(**kwargs) 把N個關鍵字引數轉化為字典:

    >>> def func(country,province,**kwargs):
    ...     print(country,province,kwargs)
    ... 
    >>> func("China","Sichuan",city = "Chengdu", section = "JingJiang")
    China Sichuan {'city': 'Chengdu', 'section': 'JingJiang'}
    >>>
  3. lambda 匿名函式也是可以使用"關鍵字引數"進行引數傳遞

    >>> g= lambda x,y : x**2+y**2
    >>> g(2,3)
    13
    >>> g(y=3,x=2)
    13

    同樣地,lambda 匿名函式也可以設定預設值

    >>> g= lambda x=0,y=0 : x**2+y**2
    >>> g(2,3)
    13
    >>> g(2)
    4
    >>> g(y=3)
    9

    注意:如果只打算給其中一部分引數設定預設值,那麼應當將其放在靠後的位置(和定義函式時一樣,避免歧義),否則會報錯。

  4. 關於可更改與不可更改型別, 以及其它語言的值型別與引用型別的介紹,一直一來感覺都不太嚴謹, 說法是否正確有待驗證。

    簡單的說就是,不可更改型別傳到函式裡重新賦值後,兩次輸出值不一樣,而可更改型別傳到函式裡對物件的"屬性" 重新賦值後輸出值一樣。

    這裡照搬一下例子:

    # 可寫函式說明
    def changeme( mylist ):
       "修改傳入的列表"
       mylist.append([1,2,3,4])
       print ("函式內取值: ", mylist)
       return
     
    # 呼叫changeme函式
    mylist = [10,20,30]
    changeme( mylist )
    print ("函式外取值: ", mylist)

    請注意:上面特意用了引號標準的部分,對可變型別或者引用的操作修改的是傳過來的物件的屬性。

    可以這麼理解(例子有點隨意):我在畫畫,小明來了說他也要畫,我讓他和我一起畫,他如果和我在同一個畫板上畫,那麼我們兩的畫就會同時改變。 而如果他說不,我要另外用一塊畫板,然後重新拿了塊畫板畫起來了,那麼我們兩的畫自然就不一樣了。

    同理可更改型別 的屬性進行操作,這只是對引用的記憶體塊裡面的值進行操作,引用並沒變,自然所有引用它的物件的值都變了。而對不可更改的物件進行操作,因為它引用的記憶體塊只是對應一個固定的值,不能進行修改,要重新複製實際上就是更新引用。

    如果我們執行下面的例子,對可更改型別的引用進行修改,結果就不一樣了。

    # 可寫函式說明
    def changeme( mylist ):
       "修改傳入的列表"
       mylist = [1,2,3,4]
       print ("函式內取值: ", mylist)
       return
     
    # 呼叫changeme函式
    mylist = [10,20,30]
    changeme( mylist )
    print ("函式外取值: ", mylist)

    結果

    函式內取值:  [1, 2, 3, 4]
    函式外取值:  [10, 20, 30]
  5. 對於變數作用域,變數的訪問以 L(Local) –> E(Enclosing) –> G(Global) –>B(Built-in) 的規則查詢,即:在區域性找不到,便會去區域性外的區域性找(例如閉包),再找不到就會去全域性找,再者去內建中找。

    觀察以下幾個例子,均從內部函式輸出變數 x:

    1. 區域性作用域

    x = int(3.3)
    
    x = 0
    def outer():
        x = 1
        def inner():
            x = 2
            print(x)
        inner()
    
    outer()

    執行結果為 2,因為此時直接在函式 inner 內部找到了變數 x。

    2.閉包函式外的函式中

    x = int(3.3)
    
    x = 0
    def outer():
        x = 1
        def inner():
            i = 2
            print(x)
        inner()
    
    outer()

    執行結果為 1,因為在內部函式 inner 中找不到變數 x,繼續去區域性外的區域性——函式 outer 中找,這時找到了,輸出 1。

    3.全域性作用域

    x = int(3.3)
    x = 0
    def outer():
        o = 1
        def inner():
            i = 2
            print(x)
        inner()
    
    outer()

    執行結果為 0,在區域性(inner函式)、區域性的區域性(outer函式)都沒找到變數 x,於是訪問全域性變數,此時找到了並輸出。

    4. 內建作用域

    x = int(3.3)
    g = 0
    def outer():
        o = 1
        def inner():
            i = 2
            print(x)
        inner()
    
    outer()

    執行結果為 3,在區域性(inner函式)、區域性的區域性(outer函式)以及全域性變數中都沒有找到變數x,於是訪問內建變數,此時找到了並輸出。

  6. 函式內可以訪問全域性變數,但不能更新(修改)其值!

    例 :

    a = 10
    def sum ( n ) :
       n += a
       print ('a = ', a, end = ' , ' )
       print ( 'n = ', n )
      
    sum(3)

    輸出 :

    a =  10 , n =  13

    如果引用了還沒更新的值則會報錯 :

    a = 10
    def sum ( n ) :
       n += a
       a = 11
       print ('a = ', a, end = ' , ' )
       print ( 'n = ', n )
      
    sum(3)

    輸出 :

    ...
    UnboundLocalError: local variable 'a' referenced before assignment

    可以加上 global 引用以更新變數值 :

    a = 10
    def sum ( n ) :
       global a
       n += a
       a = 11
       print ('a = ', a, end = ' , ' )
       print ( 'n = ', n )
    
    sum ( 3 )
    print ( '外 a = ', a )

    輸出:

    a = 11 , n = 13 外 a = 11

  7. 函式也可以以一個函式為其引數:

    def hello () :
      print ("Hello, world!")
    
    def execute(f):
      "執行一個沒有引數的函式"
      f()
    
    execute(hello)

    輸出:

    Hello, world!
  8. 可以通過 函式名.__doc__ 的方式來顯示函式的說明文件,感覺這個如果在閱讀比較大的程式時應該會有用,同時也在提示自己在寫函式時注意新增文件說明。

    def add(a,b):
        "這是 add 函式文件"
        return a+b
    
    print (add.__doc__)

    輸出結果為:

    這是 add 函式文件
  9. 函式返回值的注意事項: 不同於 C 語言,Python 函式可以返回多個值,多個值以元組的方式返回:

    def fun(a,b):    
        "返回多個值,結果以元組形式表示"
        return a,b,a+b
    print(fun(1,2))

    輸出結果為:

    (1, 2, 3)
  10. 函式的裝飾器

    在不改變當前函式的情況下, 給其增加新的功能:

    def log(pr):#將被裝飾函式傳入
    def wrapper():
    print("**********")      
    return pr()#執行被裝飾的函式
    return wrapper#將裝飾完之後的函式返回(返回的是函式名)
    @log
    def pr():
        print("我是小小洋")
    
    pr()

    回撥函式和返回函式的例項就是裝飾器。

  11. 1.內部函式,不修改全域性變數可以訪問全域性變數

    a = 10
    def test():
        b = a + 2 #僅僅訪問全域性變數 a
        print(b)
    test()

    輸出結果為:

    12

    2.內部函式,修改同名全域性變數,則python會認為它是一個區域性變數(同教程最後一個例子)

    #!/usr/bin/python3
     
    a = 10
    def test():
        a = a + 1 #修改同名的全域性變數,則認為是一個區域性變數
        print(a)
    test()

    3.在內部函式修改同名全域性變數之前呼叫變數名稱(如print sum),則引發Unbound-LocalError

  12. 關於 global 和 nonlocal 的知識:

    nonlocal 只能修改外層函式的變數而不能修改外層函式所引用的全域性變數,給一個例子如下:

    x = 0
    def outer():
        global x
        x = 1    
        def inner():
            nonlocal x
            x = 2        
            print(x)
        inner()
    
    outer()
    print(x)

    結果會報錯:

    line 6
        nonlocal x
        ^
    SyntaxError: no binding for nonlocal 'x' found
  13. global 關鍵字會跳過中間層直接將巢狀作用域內的區域性變數變為全域性變數:

    測試程式碼如下:

    num = 20
    def outer():
        num = 10
        def inner():
            global num
            print (num)
            num = 100
            print (num)
        inner()
        print(num)
    outer()
    print (num)
    結果如下:
    20
    100
    10
    100
  14. Python 定義一個 class 可以編寫一個它的建構函式 _init_() 其中形參 self 在例項化時相當於 myname:

    class demo:
        name = ""
        def _init_(self):
            self.ex()
            self.start()
        def inputName(self):
            global name
            name = input("輸入您的姓名:")
        def getFirstName(self):
            if len(name) <= 0:
                x = "別鬧!請輸入姓名!"
                return x
            else:
                x = name[0]
                return x
        def getLastName(self):
            if len(name) <= 1:
                y = "別鬧!長度不夠!"
                return y
            else:
                y = name[1:]
                return y
    myname = demo()
    myname.inputName()
    print(myname.getFirstName())
    print(myname.getLastName())
  15. 函式的引數分為形參實參

    1. 什麼是形參

    對於函式來說,形式引數簡稱形參,是指在定義函式時,定義的一個變數名。

    下面的程式碼中,x、y、z 就是形參。

    #定義函式
    
    def foo(x, y, z):
          print("x=", x)
          print("y=", y)
          print("z=", z)
    
    #呼叫函式
    foo(1,3,5)                #此處的1,3,5是實參

    輸出結果:

    x= 1
    y= 3
    z= 5

    形參的作用:是用來接收呼叫函式時輸入的值。

    2. 什麼是實參

    對於函式來說,實際引數簡稱實參。

    是指在呼叫函式時傳入的實際的資料,這會被繫結到函式的形參上。

    函式呼叫時,將值繫結到變數名上,函式呼叫結束,解除繫結,並且實參將不再存在於程式中。

    foo(5,2,0)

    上面的 5、 2 和 0 都是實參。

  16. 在編寫函式的過程中,可以顯式指定函式的引數型別及返回值型別:

    #!/usr/bin/env python3
    # -*- coding: UTF-8 -*-
    
    def function_demo(param_A: int, param_B: float, param_C: list, param_D: tuple) -> dict:
        pass

    這種 “將資料型別寫死在程式碼中” 的行為在整合開發環境/程式碼編輯器時尤為方便,通過顯式地指定函式的引數型別和返回值,能夠讓智慧補全元件提前獲知識別符號的資料型別,提供有利的輔助開發功能。

  17. 對於上面提到的向函式中傳遞函式物件的用法,我這裡進一步補充。

    1.向函式傳遞的函式本身可以是有引數的:

    def demo(*p):
        i=0
        for var in p:
            var(i)
            i+=1
    def d1(i):
        print("這裡是第一個子函式,輸入的數是",i)
    def d2(i):
        print("這裡是第二個子函式,輸入的數是",i)
    def d3(i):
        print("這裡是第三個子函式,輸入的數是",i)
    def d4(i):
        print("這裡是第四個子函式,輸入的數是",i)
    demo(d1,d2,d3,d4)

    上面的程式碼執行起來沒問題。

    2.就算你的函式是有引數的,將這個函式傳遞給另一個函式的時候也不能加引數,還是上面的例子:

    demo(d1(7),d2,d3,d4)

    這樣就會報錯,因為此時 d1(7) 就是 d1() 的返回值,是不可以在方法內部傳遞引數並且呼叫。