提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
- 一、函數
- 1.高階函數
- 2.返回函數
- 3.匿名函數
- 4.裝飾器
- 二、實例
- 1.類和實例
- 2.限制訪問
- 3. 繼承和多態
- 4.實例屬性和類屬性
一、函數
1.高階函數
- 1.1 map
- 1.2 reduce
- 1.3 filter
- 1.4 sorted
# 1.1 map()函數:把一個函數作用到一個Iterable的東西上
# 參數:1.函數 2.Iterable
# 返回值類型:map object
# 舉例:把平方作用到列表的每個值中
def f(x):return x * x
r = map(f,[1,2,3,4,5,6,7,8,9])
list(r)
>>>[1, 4, 9, 16, 25, 36, 49, 64, 81]
# map()函數實際上就是不是運算規則抽象化了
# 把list的每個數字變成str
list(map(str,[1,2,3,4,5,6,7,8,9]))
>>>[‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’]
# 1.2 reduce()函數:把一個函數累計作用到序列的下一個元素中
# reduce(f,[x1,x2,x3]) == f(f(x1,x2),x3)
# 舉例,把[1,2,3]變成123
from functools import reduce
def fn(x,y):return x*10+y
reduce(fn,[1,2,3])
>>> 123
# 1.3 filter函數:接收函數和序列,根據函數作用在序列的每個元素返回的True和False決定是否保留該元素
# 返回類型:Iterator
# 舉例:只保留序列中的奇數
def is_odd(n):return n%2==1
list(filter(is_odd,[1,3,5,7,2,4,6,8]))
>>>[1, 3, 5, 7]
# 把一個序列中的空字符去掉
def not_empty(s):return s.strip()
list(filter(not_empty, ['A', '', 'B', 'C', ' ']))
>>>[‘A’, ‘B’, ‘C’]
# sorted對list進行排序
sorted([32,12,-19,55,3])
>>>[-19, 3, 12, 32, 55]
# 參數:key,接收自定義排序函數
# 舉例:按照絕對值大小排序
sorted([32,12,-19,55,3],key=abs)
>>>[3, 12, -19, 32, 55]
# 對于字符 是按照ASCII碼進行排序
sorted(['sb','Sb','SB'])
>>>[‘SB’, ‘Sb’, ‘sb’]
2.返回函數
- 2.1 函數作為返回值
- 2.2 閉包
# 2.1 高階函數出了可以接收函數作為參數,還可以把函數作為結果返回
# 一個可變參數的求和,如果不需要立刻求和,而是在后面的代碼中,根據需要再計算
def lazy_sum(*args):def sum():ax = 0for n in args:ax = ax + nreturn axreturn sum
# 調用的時候返回的是求和函數
f = lazy_sum(1,2,3,4)
f>>> <function __main__.lazy_sum.<locals>.sum()># 調用函數f的時候,才是返回真正的求和結果
f()
>>>10
# 在函數lazy_sum里面又定義了函數sum,內部函數可以引用外部函數的參數和局部變量
# lazy_sum返回了sum的時候,相關的參數和變量都保存在了返回函數中,就是閉包
# 每一次調用 返回的都是新的函數 但是傳入的是相同的參數
f1 = lazy_sum(1,2,3,4)
f2 = lazy_sum(1,2,3,4)
f1 == f2
>>>False
# 2.2 閉包
# 要注意返回的函數沒有立刻執行,要再一次的調用才會執行
def count():fs = []for i in range(1,4):def f():return i * ifs.append(f)return fs
count()
f1,f2,f3 = count()
print(f1(),f2(),f3())
# 因為返回函數引用了i,并且并非立刻執行,3個函數都返回時,所以它引用的變量i已經變成3
>>>9 9 9
# 如果一定要引用循環的變量,就應該再創建一個函數,綁定循環變量
def count():def f(j):def g():return j*jreturn gfs = []for i in range(1,4):fs.append(f(i))return fs
count()
f1,f2,f3 = count()
print(f1(),f2(),f3())
>>>1 4 9
3.匿名函數
list(map(lambda x: x*x,[1,2,3]))
>>>[1, 4, 9]
# 相當于
def f(x):return x * x
4.裝飾器
# 函數也是對象,所以可以賦值給變量,通過變量來調用函數
def now():print('2020-01-01')
f = now
f()
>>>2020-01-01
# 想要增強now()的功能,在調用的前打印日志,有不改變函數本身的定義,這樣動態增加功能的方法叫做裝飾器
# 本質上是一個返回函數的高階函數
def log(func):def wrapper(*args,**kw):print('call %s:'%func.__name__)return func(*args,**kw)return wrapper
# %%
@log
def now(x):print('2020-01-01')
now(1)
# %%
>>>
call now:
2020-01-01
# @log 放在now函數之前 相當于
now = log(now)
# decorator也要傳入參數,需要編寫一個decorator的高階函數
def log(text):def decorator(func):def wrapper(*args,**kw):print('%s %s:'%(text,func.__name__))return func(*args,**kw)return wrapperreturn decorator
# %%
@log('execute')
def now():print('2020-01-01')
# %%
now()
>>>
execute now:
2020-01-01
# 相當于
now = log('execute')(now)
# 先執行了log('execute'),返回了decorator函數,再調用返回函數,參數是now,返回的是wrapper
# 也就是原來的now函數變成了現在的wrapper函數了
now.__name__
>>>‘wrapper’
# 想要保持now的name的話 wrapper.__name__ = func.__name__
# 可以用裝飾器 @functools.wraps(func)
import functools
def log(func):@functools.wraps(func)def wrapper(*args,**kw):print('call %s():' % func.__name__)return func(*args,**kw)return wrapper# %%
@log
def now():print('2020-01-01')
# %%
now.__name__
>>>‘now’
二、實例
1.類和實例
- 1.1 基本定義
- 1.2 創建實例
- 1.3 綁定屬性
- 1.4 _init_
- 1.5 數據封裝
# 1.1 基本定義
# class + 類名 + (object) 即從哪個類繼承下來的
class student(object):pass
# 1.2 創建實例
# 類名+()
bart = student()
# 變量bart指向student類的實例,0x1064b1128是內存地址
bart
student
>>>
<main.student at 0x1064b1128>
main.student
# 1.3 綁定屬性
# 可以自由的給實例變量綁定屬性
bart.name = 'sb'
bart.name
>>>‘sb’
# 1.4 __init__
# 類就像是模版 當我們想創建實例的時候就把一些屬性寫進去 可以用__init
class student(object):# self 就是實例本身def __init__(self,name,score):self.name = nameself.score = scorebart = student('sb',0)
bart.name
bart.score
>>> ‘sb’ 0
# 1.5 數據封裝
# 比如一個函數本來就要用到學生類里面的數據,那當然就把函數放在類里面多好嘛
class student(object):def __init__(self,name,score):self.name = nameself.score = scoredef print_score(self):print('%s:%s'%(self.name,self.score))bart = student('sb',0)
bart.print_score()
>>>sb:0
2.限制訪問
# 按照上述的定義,外部代碼還可以自由修改實例的屬性
bart.score
bart.score = 100
bart.score
>>>
0
100
# 我們更希望這些屬性是私有的,不能被外部代碼修改的
class student(object):def __init__(self,name,score):self.__name = nameself.__score = scoredef print_score(self):print('%s: %s' % (self.__name, self.__score))bart = student('sb',0)
bart.__name
>>>
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-24-1e120ece361e> in <module>
----> 1 bart.__nameAttributeError: 'student' object has no attribute '__name'
# 這么做又有一個問題,雖然外部代碼不能修改實例的屬性了。但是我們還是希望外部代碼可以獲得他的值
class student(object):def __init__(self,name,score):self.__name = nameself.__score = score# 讓外部可以獲得屬性的值def get_name(self):return self.__namedef get_score(self):return self.__score# 讓外部可以改變屬性的值def set_name(self,name):self.__name = name# 可以通過這樣改變屬性的方法來做參數檢查,避免傳入無效參數def set_score(self,score):if 0 <= score < 100:self.__score = scoreelse:raise ValueError('bad score')bart = student('sb',0)
bart.get_name()
bart.set_name('SB')
bart.get_name()
>>>
‘sb’
‘SB’
bart.set_score(50)
bart.get_score()
>>>50bart.set_score(250)
>>>
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-40-6cf87971f6eb> in <module>
----> 1 bart.set_score(250)<ipython-input-31-e38b3fe7e472> in set_score(self, score)20 self.__score = score21 else:
---> 22 raise ValueError('bad score')ValueError: bad score
3. 繼承和多態
- 3.1 繼承
- 3.2 子類的特性
- 3.3 理解多態
# 現在我們已經有一個動物class,一個run()方法打印
class Animal(object):def run(self):print("Animal is running...")
# 3.1 繼承
# 當我們需要具體的動物類時,可以從Animal繼承
class cat(Animal):passclass Dog(Animal):pass
# 繼承最大的好處就是子類有了父類的全部功能
dog = Dog()
dog.run()
>>>Animal is running…
# 3.2 子類的特性
# 子類可以增加新的方法也可以對父類的方法進行改進
class Dog(Animal):# 改進父類方法def run(self):print('Dog is running...')# 新的方法def eat(self):print('Dog is eating...')dog = Dog()
dog.run()
dog.eat()
>>>
Dog is running…
Dog is eating…
# 3.3 理解多態
# 定義一個class,實際上就是定義了一種數據類型
a = list() # a是list類型
b = Animal() # b是Animal類型
c = Dog() # c是Dog類型
# c既是Dog也是Animal
# 就是說Dog可以看成是一個Animal
isinstance(c,Animal)
isinstance(c,Dog)
>>>
True
True
# 理解多態的好處
class Animal(object):def run(self):print("Animal is running...")def eat(self):print('Anumal is eating...')class Dog(Animal):def run(self):print('Dog is running...')def eat(self):print('Dog is eating...')def run_eat(a):a.run()a.eat()
run_eat(Animal())
>>>
Animal is running…
Anumal is eating…
run_eat(Dog())
# 多態的好處:傳入的只要是Animal或者他的子類,就會自動調用實際類型的run()
# 調用的時候只管調用,新加一個子類的時候只要保證他繼承的方法沒寫錯
# 開閉原則:
# 對擴展開放:允許增加子類
# 對修改封閉:不需要修改類的run_eat()函數
>>>
Dog is running…
Dog is eating…
- 靜態語言:利用多態特性的時候,傳入的對象必須嚴格的是Animal類或者他的子類
- 動態語言:不要求嚴格的繼承體系
- 鴨子類型:一個對象只要看起來像鴨子,走路也像鴨子,就能被看作是鴨子
- python:“file-like object”就是一種鴨子類型,某個對象有當前的這個函數方法,就可以當作是這個函數的對象了。
4.實例屬性和類屬性
# 給實例綁定屬性
# 1.通過實例變量 2.通過self變量
class student(object):def __init__(self,name):self.name = names = student('sb')
s.score = 0
# 直接給類綁定一個類屬性
class student(object):name = 'student'# 創建實例
s = student()
# 這個時候實例沒有name,所以會向上找類的name
s.name
>>>‘student’
# 打印類的屬性
print(student.name)
>>>student# 給實例綁定屬性
s.name = 'sb'
print(s.name)
>>>sbprint(student.name)
>>>student