1. 程式人生 > >Python 函數式編程和面向對象編程

Python 函數式編程和面向對象編程

cti get 函數名 self. string 結果 沒有 當前 ade

函數式編程

函數:function。
函數式:functional,一種編程範式。函數式編程是一種抽象計算機的編程模式。
函數!= 函數式(如計算!=計算機)

如下是不同語言的抽象 層次不同

技術分享圖片
  • 高階函數

能接收函數做參數的函數:

1.變量可以指向函數
2.函數的參數可以接收變量
3.一個函數可以接收另一個函數作為參數

例子

接收abs函數,定義一個函數,接收x,y,z三個參數。其中x,y是數值,z是函數 。

def add(x,y,z):
    return z(x)+z(y)
print add(-2,-3,abs)

其他高階函數:map()函數、reduce()函數、filter()函數

PS:Python的函數不但可以返回int、str、list、dict等數據類型,還可以返回函數!

閉包

像這種內層函數引用了外層函數的變量(參數也算變量),然後返回內層函數的情況,稱為閉包(Closure)。

特點是返回的函數還引用了外層函數的局部變量,所以,要正確使用閉包,就要確保引用的局部變量在函數返回後不能變。舉例如下:

# 希望一次返回3個函數,分別計算1x1,2x2,3x3:
def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    
return fs f1, f2, f3 = count()

你可能認為調用f1(),f2()和f3()結果應該是1,4,9,但實際結果全部都是 9(請自己動手驗證)。

原因就是當count()函數返回了3個函數時,這3個函數所引用的變量 i 的值已經變成了3。由於f1、f2、f3並沒有被調用,所以,此時他們並未計算 i*i,當 f1 被調用時:

>>> f1()
9     # 因為f1現在才計算i*i,但現在i的值已經變為3

因此,返回函數不要引用任何循環變量,或者後續會發生變化的變量。

匿名函數(lambda )

>>> map(lambda
x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]) [1, 4, 9, 16, 25, 36, 49, 64, 81]

通過對比可以看出,匿名函數lambda x: x * x 實際上就是:

def f(x):
    return x * x

關鍵字lambda 表示匿名函數,冒號前面的 x 表示函數參數(匿名函數有個限制,就是只能有一個表達式,不寫return,返回值就是該表達式的結果,返回函數的時候,也可以返回匿名函數。)

裝飾器 decorator

Python 的 decorator 本質上就是一個高階函數,它接收一個函數作為參數,然後,返回一個新函數。

使用 decorator 用 Python 提供的 @ 語法,這樣可以避免手動編寫 f = decorate(f) 這樣的代碼,極大簡化Python代碼。

技術分享圖片

模塊

導入系統自帶的模塊 math:

import math

如果我們只希望導入用到的 math 模塊的某幾個函數,而不是所有函數,可以用下面的語句:

 from math import pow, sin, log

如果遇到名字沖突怎麽辦?

如果使用 import 導入模塊名,由於必須通過模塊名引用函數名,因此不存在沖突;

如果使用from...import 導入log函數,勢必引起沖突。這時,可以給函數起個“別名”來避免沖突:

from math import log
from logging import log as logger   # logging的log現在變成了logger

print log(10)   # 調用的是math的log
logger(10, import from logging)   # 調用的是logging的log

動態導入模塊

下面代碼先嘗試從cStringIO導入,如果失敗了(比如cStringIO沒有被安裝),再嘗試從StringIO導入。

try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

利用import ... as ...,還可以動態導入不同名稱的模塊

try:
    import json
except ImportError:
    import simplejson as json

PS:

  1. Python的新版本會引入新的功能,但是實際上這些功能在上一個老版本中就已經存在了。要“試用”某一新的特性,就可以通過導入__future__模塊的某些功能來實現。
  2. 如何區分包和普通目錄:包下面有個__init__.py每層都有。

面向對象編程

定義類並創建實例

定義一個Person類如下

class Person(object):
    pass

(object),表示該類是從哪個類繼承下來的。

創建實例

xiaoming = Person()

如何讓每個實例擁有各自不同的屬性?

由於Python是動態語言,對每一個實例,都可以直接給他們的屬性賦值,例如,給xiaoming這個實例加上name、gender和birth屬性:

xiaoming = Person()
xiaoming.name = Xiao Ming
xiaoming.gender = Male
xiaoming.birth = 1990-1-1

xiaohong加上的屬性不一定要和xiaoming相同:

xiaohong = Person()
xiaohong.name = Xiao Hong
xiaohong.school = No. 1 High School
xiaohong.grade = 2

`實例的屬性可以像普通變量一樣進行操作:

xiaohong.grade = xiaohong.grade + 1

初始化實例屬性

class Person(object):
    def __init__(self, name, gender, birth):
        self.name = name
        self.gender = gender
        self.birth = birth

__init__()方法的第一個參數必須是 self(也可以用別的名字,但建議使用習慣用法)。後續參數則可以自由指定,和定義函數沒有任何區別。

相應地,創建實例時,就必須要提供除 self 以外的參數:

xiaoming = Person(Xiao Ming, Male, 1991-1-1)
xiaohong = Person(Xiao Hong, Female, 1992-2-2)

定義實例方法

class Person(object):
    def __init__(self, name):
        self.__name = name
  
    def get_name(self): #它的第一個參數永遠是 self,指向調用該方法的實例本身
        return self.__name

定義類方法(類似Java的靜態方法)

class Person(object):
    count = 0
    @classmethod
    def how_many(cls): #類方法
        return cls.count
    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1
 
print Person.how_many()
p1 = Person(Bob)
print Person.how_many()

訪問限制

如果一個屬性由雙下劃線開頭(__),該屬性就無法被外部訪問(相當於private)。但是,如果一個屬性以"__xxx__"的形式定義,那它又可以被外部訪問了,以"__xxx__"定義的屬性在 Python 的類中被稱為特殊屬性,有很多預定義的特殊屬性可以使用,通常我們不要把普通屬性用"__xxx__"定義。

  • 題目

請定義Person類的__init__方法,除了接受 name、gender 和 birth外,還可接受任意關鍵字參數,並把他們都作為屬性賦值給實例。
要定義關鍵字參數,使用**kw
除了可以直接使用self.name = ‘xxx‘設置一個屬性外,還可以通過 setattr(self, ‘name‘, ‘xxx‘)設置屬性。

  • 參考代碼:
class Person(object):
    def __init__(self, name, gender, birth, **kw):
        self.name = name
        self.gender = gender
        self.birth = birth
        for k, v in kw.iteritems():
            setattr(self, k, v)
xiaoming = Person(Xiao Ming, Male, 1990-1-1, job=Student)
print xiaoming.name
print xiaoming.job

類的繼承

繼承一個類

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

定義 Student 類時,只需要把額外的屬性加上,例如score:

class Student(Person):
    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

一定要用super(Student, self).__init__(name, gender)去初始化父類,否則,繼承自PersonStudent將沒有name 和 gender。函數super(Student, self)將返回當前類繼承的父類,即 Person,然後調用__init__()方法,註意self參數已在super()中傳入,在__init__()中將隱式傳遞,不需要寫出(也不能寫)

判斷類型

函數isinstance()可以判斷一個變量的類型

>>> isinstance(p, Person)

獲取對象信息

除了用isinstance()判斷它是否是某種類型的實例外,type() 函數獲取變量的類型,它返回一個 Type 對象。可以用dir()函數獲取變量的所有屬性: dir(s)

Python 函數式編程和面向對象編程