Python基礎(chǔ)入門

一直沒有開Python相關(guān)的文章障癌。本文從零開始,整理一下Python的基礎(chǔ)語法辩尊。其余相關(guān)內(nèi)容慢慢增加涛浙。內(nèi)容主要參考新加坡Jamie Chan編寫王磊譯的《愛上Python》和 俄羅斯Dmitry Zinoviev編寫熊子源譯的《Python數(shù)據(jù)科學(xué)入門》,以及廖雪峰網(wǎng)站上Python的教學(xué)內(nèi)容。之后會根據(jù)《python cookbook》在另一篇博客里記錄一些實(shí)際用例摄欲。

環(huán)境配置

macOS上的Python環(huán)境

macOS上自帶的Python版本是2.7.10,調(diào)用的話默認(rèn)在文件頭部加#! /usr/bin(在2018年發(fā)布的mbp上似乎自帶的就是Python3了)
然后brew install python3之后自己裝的Python3命令默認(rèn)地址是#! /usr/local/bin

更加通用的標(biāo)準(zhǔn)注釋方式是

#!/usr/bin/env python3
#coding = utf-8

然后簡單的交互調(diào)用的話轿亮,直接在終端輸入python是調(diào)用默認(rèn)的2.7.10。輸入python3是調(diào)用的Python3胸墙。

如果希望輸入python也能進(jìn)入python3我注。可以自己vim ~/.zshrc(shell是zsh的話)劳秋,加入一行alias python="python3"。之后source ~/.zshrc更新配置文件使修改生效。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/python3.png">

包管理器pip

還有就是Python自帶的包管理器pip玻淑。利用pip下載可以說很方便了嗽冒,值得注意的是Python2并沒有自帶,Python3自帶了pip补履,調(diào)用下載的jupyter note的話pip3 install jupyter添坊。

列出可升級的包:

pip list --outdate

升級一個(gè)包:

pip install --upgrade 包名

pip的用法

conda環(huán)境

安裝anaconda環(huán)境也有它的好處,多個(gè)可以創(chuàng)建不同版本的python環(huán)境箫锤,每個(gè)python環(huán)境里的包各自獨(dú)立贬蛙。不過anaconda里面預(yù)先裝了很多包,精簡一點(diǎn)可以下載miniconda谚攒。

常見指令:

  • 創(chuàng)建指定python版本的環(huán)境:
    conda create -n env_name python=3.6 -n代表name阳准。
  • 進(jìn)入與退出某個(gè)python環(huán)境:
    conda activate env_name conda deactivate
  • 列出所有的虛擬環(huán)境:
    conda env list
  • 刪除某個(gè)python環(huán)境:
    conda remove -n env_name --all
  • 列舉當(dāng)前活躍環(huán)境下的所有包:
    conda list
  • 為指定環(huán)境安裝某個(gè)包:
    conda install -n env_name package_name

cuda安裝

首先需要安裝NVIDIA的顯卡驅(qū)動,針對對應(yīng)的驅(qū)動版本安裝不同版本的cuda-toolkit馏臭,同時(shí)需要下載對應(yīng)的cuDNN野蝇。

cuda-toolkit-release-notes
https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html

非root用戶安裝

https://blog.csdn.net/txy12029047/article/details/90733643
https://blog.csdn.net/sinat_20280061/article/details/80421532

Jupyter notebook

順帶提一下這里的Jupyter notebook,十分好用的工具,不僅是編寫支持多種語言(Python,Scala,Ruby,R,Haskell,Bash)的輕便編輯器括儒,還支持Markdown和Latex語法绕沈,支持導(dǎo)出Markdown,HTML,PDF,LaTeX多種格式。最關(guān)鍵的是Jupyter Notebook 的本質(zhì)是一個(gè) Web 應(yīng)用程序帮寻,十分輕量化乍狐,你可以通過終端里調(diào)用打開也可以直接瀏覽器輸入localhost:8888訪問,便于共享程序文檔固逗。

不過個(gè)人習(xí)慣是使用終端運(yùn)行Python浅蚪,然后編輯代碼使用vscode編輯器。

Jupyter notebook相關(guān)

基礎(chǔ)語法

基礎(chǔ)語法里只挑選比較重要和有趣的一筆帶過

操作符

x=5,y=2
整除:x//y=2
指數(shù):x**y=25

類型轉(zhuǎn)換

三個(gè)內(nèi)建的類型轉(zhuǎn)化函數(shù)int();float();str();

輸入輸出

input()和print()
message=input("Please enter the text")
顯示提示信息并把用戶輸入信息存入message抒蚜。在python3掘鄙,input()默認(rèn)讀入的元素是string類型,需要自己轉(zhuǎn)換成需要的數(shù)據(jù)類型嗡髓。

或者使用sys.stdin.readline()或者sys.stdin.readlines()

import sys

if __name__ == '__main__':
    try:
        line = sys.stdin.readline()
        n = int(line)
        nums = [int(t) for t in sys.stdin.readline().split()]
    except:
        pass

字符串

1.Python和swift一樣都支持用+來連接字符串:
"James"+"Lee"="JamesLee"
2.對于字符大小寫:
upper()把字符串小寫轉(zhuǎn)大寫操漠,如 'Peter'.upper()得到'PETER'。 相對應(yīng)的還有l(wèi)ower()饿这。
capitalize()把第一個(gè)字符轉(zhuǎn)大寫浊伙,其余字符換小寫。
3.isalnum()
如果字符串中的所有字符都是字母和數(shù)字长捧,并至少存在一個(gè)字符嚣鄙,返回True,否則False串结。
空格不包含于數(shù)字和字母中
'a b'.isalum() => False
類似的還有isupper()哑子、islower()舅列、isalpha()、isspace()卧蜓、isdigit()帐要、istitle()
4.count(sub,start,end)計(jì)算子字符串sub在字符串中出現(xiàn)的次數(shù),后面兩個(gè)是可選參數(shù)。(count函數(shù)對于大小寫是敏感的,Python的內(nèi)建字符串函數(shù)基本都是大小寫敏感的弥奸,后面默認(rèn))

'This is a test'.count('s')會返回?cái)?shù)字3

'This is a test'.count('s',4)計(jì)算從第四位到尾的出現(xiàn)次數(shù)榨惠,會返回?cái)?shù)字2

5.endswith(suffix,start,end)如果字符串以指定的后綴suffix結(jié)尾,返回True盛霎,否則False赠橙。suffix也可以是要尋找的多個(gè)后綴的元組。相反的還有startswith()re

'Prettygirl'.endswith('girl') =>true
'Prettygirl'.endswith('rl') =>true
'Prettygirl'.endswith('r') =>false
'Prettygirl'.endswith(('r','rl')) =>true

6.find/index(sub,start,end)

返回字符串中子字符串sub首次出現(xiàn)的位置愤炸。

find()如果沒有在這個(gè)字符串中找到子串期揪,返回-1。如果是index()返回ValueError

7.decode()和encode()

decode()二進(jìn)制轉(zhuǎn)字符摇幻。encode()字符轉(zhuǎn)二進(jìn)制横侦。

8.split()和join()
字符串的分割和合并

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/string.join.png" width="300">

9.replace(old,new,count)把字符串中所有的old字符串替換為new字符串。count是可選參數(shù)绰姻。
<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/replace.png" width="300">

10.splitlines([keepends])返回字符串所有行的列表枉侧。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/splitlines.png" >

11.strip([chars])復(fù)制一個(gè)字符串,返回該字符串首尾位置移除字符串char的結(jié)果狂芋。
如果沒有指定榨馁,默認(rèn)首尾的空格會被移除。

12.format()格式化字符串

指定格式有點(diǎn)像c語言里面的形式,{0:s}前面代表位置帜矾,后面代表數(shù)據(jù)類型翼虫。當(dāng)然簡化寫法也可以不指定位置或者不標(biāo)明數(shù)據(jù)類型。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/format.png" >

也可以用這一種方式:

>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'

內(nèi)聯(lián)if

num = 12 if myInt==10 else 13當(dāng)myInt等于10時(shí)候屡萤,num被賦值為13.

for以及while循環(huán)

簡單舉個(gè)例子演示下:

numbers = [12, 37, 5, 42, 8, 3]
even = []
odd = []
while len(numbers) > 0 :
    number = numbers.pop()
    if(number % 2 == 0):
        even.append(number)
    else:
        odd.append(number)
        
for item in numbers:
    print(item)

然后Python里跳出循環(huán)的方式和C++一樣珍剑,都是看需要用break或者continue。

自定義的模塊的導(dǎo)入

在同一個(gè)文件夾下死陆,例如這個(gè)文件名是prime.py只需要import prime
如果不在一個(gè)文件夾下sys.path.append(絕對路徑)即可

命令行參數(shù)

import sys 之后再 sys.argv獲得參數(shù)列表招拙,list形式存儲

文件的讀取

主要函數(shù)有

  • f.read()以字符串或者二進(jìn)制方式讀取所有數(shù)據(jù)
  • f.read(n)讀入前n字節(jié)的數(shù)據(jù)
  • f.readline()以字符串方式讀取下一行
  • f.readlines()以字符串方式讀取所有行
    對應(yīng)的
  • f.write(line)
  • f.writelines(lines)
f = open('myfile.txt','r')
firstline = f.readline()
print(firstline)
f.close()

還有

f = open('myfile.txt','r')
for line in f:
    print (line,end='')//end=''使得讀取出的文件末尾不含\n換行
f.close()

read()可以規(guī)定每次讀取的緩存大小

input = open ('myfile.txt','r')
output = open ('myoutfile.txt','w')

msg=input.read(10)

while len(msg):
    output.write(msg)
    msg = input.read(10)
input.close()
output.close()

文件開啟模式參數(shù):

r: 只讀
w:只寫
a:用于添加,文件不存在會創(chuàng)建
r+:用于讀寫
rb:二進(jìn)制讀
wb:二進(jìn)制寫

三個(gè)主要數(shù)據(jù)容器

列表(list)--使用方括號[]

test=[12,13,14,15]
基本和STL庫里的list沒有太多區(qū)別。值得在意的是索引可以取負(fù)值test[-1]=15同時(shí)和STL里面一樣test2=test[1:3]輸出test2會得到結(jié)果[13,14]也是[...)包括開始元素不包括結(jié)尾元素措译。

還有就是list的一些基礎(chǔ)操作别凤,append()、del 领虹、extend() 规哪、in 、not in塌衰、insert()诉稍、len()蝠嘉、remove()等。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/list.png" width="300">

初始化部分:

1.初始化遞增的list:

list1 = range(10)
print list1
[0,1,2,...,9]

2.初始化每項(xiàng)為0的一維數(shù)組:

list2 = [0] * 5
print list2
[0,0,0,0,0]

3.初始化固定值的一維數(shù)組:

initVal = 1
listLen = 5
list3 = [ initVal for i in range(5)]
print list3
[1,1,1,1,1]
list4 = [initVal] * listLen
print list4
[1,1,1,1,1]

4.初始化一個(gè)5x6每項(xiàng)為0(固定值)的數(shù)組(推薦使用):

multilist = [[0 for col in range(5)] for row in range(6)]

其他函數(shù)包括

pop(count)得到列表中倒數(shù)第count個(gè)元素的值杯巨,默認(rèn)是取出list末尾的元素是晨,并把它從列表中刪除。

reverse()逆轉(zhuǎn)列表里的元素

統(tǒng)計(jì)一個(gè)數(shù)值在列表里的出現(xiàn)次數(shù)

a_list.count('a')

查看指定數(shù)值在列表里出現(xiàn)的位置

a_list.index('a')

sort()和sorted()兩者的區(qū)別在于sorted()會返回一個(gè)新的排序后的列表舔箭,不對原始的list進(jìn)行排序。

例子:字符串List按照元素長度排序

myList = ['青海省','內(nèi)蒙古自治區(qū)','西藏自治區(qū)','新疆維吾爾自治區(qū)','廣西壯族自治區(qū)'] 
myList.sort(key = lambda i:len(i),reverse=True) 

+和*

+號就是連接符號蚊逢,*號代表復(fù)制

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/list2.png" width="300">

元組(tuple)--使用圓括號()

元組的定義和訪問和list基本一致层扶。tuple_test = (1,2,3,4)創(chuàng)建之后tuple_test[1]就會返回?cái)?shù)值2.

訪問元組里定下初始值之后里面的值無法修改。如果出現(xiàn)元組里包含list元素的情況烙荷,這個(gè)list內(nèi)部的值是可以修改的镜会。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/tuple.png" width="300">

其他的tuple用法如del、in终抽、len戳表、+、*都和list提到的用法一致昼伴。

字典(dictionary)--使用花括號{}

基本和STL里的map很像匾旭。存儲映射并且關(guān)鍵字唯一。和上面tuple可以放入可變對象list一樣圃郊,dict里面你也可以放入list或者tuple价涝。

相關(guān)函數(shù)包括clear(),get(),items(),keys(),values(),update()等。和list與tuple一樣也可以直接索引訪問持舆,如下面的dic.get(1)也可以直接用dic[1]替換色瘩。

get() 函數(shù)返回指定鍵的值,如果值不在字典中返回默認(rèn)值逸寓。dict.get(key,default=None)

當(dāng)然可以自定義dic.get(key, 0) 找不到對應(yīng)的鍵就會返回0居兆。也可以返回字符串,如下圖示例里面的的“not found”竹伸。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/dic.png" width="450">

和tuple不一樣的是泥栖,dic和list一樣可以改變字典里的映射關(guān)系,如dic[1] = 20。并且添加新的字典映射時(shí)候直接對新項(xiàng)賦值即可佩伤。

確定字典里是否含有某個(gè)值聊倔,可以用in確定。如果希望刪除某個(gè)映射生巡,直接pop耙蔑。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/dic2.png" width="450">


除了這三種容器之外其實(shí)還有個(gè)set,跟dict很像孤荣,不過只是一組key的集合甸陌,不存儲value须揣。創(chuàng)建,添加和刪除的過程如下钱豁。值得在意的是創(chuàng)建時(shí)候如果含有重復(fù)的鍵值會自動把重復(fù)的過濾耻卡。set可以看成數(shù)學(xué)意義上的無序和無重復(fù)元素的集合,因此牲尺,兩個(gè)set一般用來做數(shù)學(xué)意義上的交集卵酪、并集等操作。
<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/set.png" width="450">

Python函數(shù)

調(diào)用函數(shù)

簡單的調(diào)用函數(shù)如abs(-20),在Python中函數(shù)名其實(shí)就是指向一個(gè)函數(shù)對象的引用谤碳,完全可以把函數(shù)名賦給一個(gè)變量溃卡,a=abs。使用時(shí)候a(-20)也是和上面的abs(-20)一樣的作用蜒简。

定義函數(shù)

舉個(gè)例子就行瘸羡,Python的函數(shù)返回多個(gè)返回值也比較容易。設(shè)定參數(shù)默認(rèn)值的時(shí)候在該參數(shù)后面加 = 就行搓茬,如下面的angle=0犹赖。

import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny

使用時(shí)候用多個(gè)變量接收多個(gè)返回值即可,如x, y = move(100, 100, 60, math.pi / 6)

特別的卷仑,定義一個(gè)空函數(shù)峻村,暫時(shí)沒想好怎么寫,但希望順利運(yùn)行锡凝。

def null_func():
    pass

Python的一些特性

切片

對于list或者tuple以及字符串都能使用切片的方法快速提取其中的部分內(nèi)容雀哨。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/qiepian.png" width ='400'>

更普遍的,能夠指定切片的step和方向:

object[start_index:end_index:step]

step:正負(fù)數(shù)均可私爷,其絕對值大小決定了切取數(shù)據(jù)時(shí)的‘‘步長”雾棺,而正負(fù)號決定了“切取方向”,正表示“從左往右”取值衬浑,負(fù)表示“從右往左”取值捌浩。當(dāng)step省略時(shí),默認(rèn)為1工秩,即從左往右以步長1取值尸饺。

例如從右到左切片:a[::-1] 取偶數(shù)位置的切片 b = a[::2]

[:]和.copy()都屬于“淺拷貝”,只拷貝最外層元素助币,內(nèi)層嵌套元素則通過引用方式共享浪听,而非獨(dú)立分配內(nèi)存。


>>>a = [1,2,['A','B']]
>>>print('a={}'.format(a))
a=[1, 2, ['A', 'B']] #原始a
>>>b = a[:]
>>>b[0] = 9 #修改b的最外層元素眉菱,將1變成9
>>>b[2][0] = 'D' #修改b的內(nèi)嵌層元素
>>>print('a={}'.format(a))
a=[1, 2, ['D', 'B']] #b修改內(nèi)部元素A為D后迹栓,a中的A也變成了D,說明共享內(nèi)部嵌套元素俭缓,但外部元素1沒變克伊。
>>>print('b={}'.format(b))
b=[9, 2, ['D', 'B']] #修改后的b
>>>print('id(a)={}'.format(id(a)))
>>>print('id(b)={}'.format(id(b)))
id(a)=38669128
id(b)=38669192

更多用法

迭代

對于list和tuple我們可以通過下標(biāo)訪問和for循環(huán)來遍歷酥郭,問題是很多其他數(shù)據(jù)類型是沒有下標(biāo)的。但是愿吹,只要是可迭代對象不从,無論有無下標(biāo),都可以迭代犁跪,比如dict就可以迭代:

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/diedai.png" width = '400'>

列表生成式

用來創(chuàng)建list的生成式椿息。形式多樣,甚至支持條件判斷和兩重循環(huán)。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/tuidaoshi.png" >

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/liebiao.png" width = '400'>

可迭代對象中分解元素

這里有個(gè)*號的運(yùn)用坷衍,和正則表達(dá)中的*號含義類似撵颊。例如在期末成績中去掉第一個(gè)和最后一個(gè)。

def drop_first_last(grades):
    first, *middle, last = grades
    return avg(middle)

生成器

通過列表生成式惫叛,我們可以直接創(chuàng)建一個(gè)列表。但是逞刷,受到內(nèi)存限制嘉涌,列表容量肯定是有限的。而且夸浅,開辟過多的list很浪費(fèi)空間仑最。

所以,如果列表元素可以按照某種算法推算出來帆喇,那我們是否可以在循環(huán)的過程中不斷推算出后續(xù)的元素呢警医?這樣就不必創(chuàng)建完整的list,從而節(jié)省大量的空間坯钦。在Python中预皇,這種一邊循環(huán)一邊計(jì)算的機(jī)制,稱為生成器:generator婉刀。要?jiǎng)?chuàng)建一個(gè)generator吟温,有很多種方法。第一種方法很簡單突颊,只要把一個(gè)列表生成式的[]改成()鲁豪,就創(chuàng)建了一個(gè)generator÷赏海可以通過next()函數(shù)獲得generator的下一個(gè)返回值爬橡,或者用上面提到的迭代特性。

<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/python/generator.png' width ='400'>

把一個(gè)函數(shù)變成生成器棒动,以斐波那契數(shù)列為例:

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        print(b)
        a, b = b, a + b
        n = n + 1
    return 'done'
    
print(fib(4))

輸出:
1
1
2
3
done

變成一個(gè)generator糙申,需要把print(b)變成yield b, 然后修改一下調(diào)用方式

def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1

for n in fib(4):
    print(n)

之前的函數(shù)是順序執(zhí)行船惨,遇到return語句或者最后一行函數(shù)語句就返回郭宝。而變成generator的函數(shù)辞槐,在每次調(diào)用next()或者send()的時(shí)候執(zhí)行,遇到y(tǒng)ield語句返回粘室,再次執(zhí)行時(shí)從上次返回的yield語句處繼續(xù)執(zhí)行榄檬。使用for n in fib(4)進(jìn)行迭代調(diào)用,本質(zhì)上相當(dāng)于不斷調(diào)用next()衔统。下面再看一個(gè)例子:

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print(next(g))

輸出結(jié)果:

starting...
4
res: None
4

如果使用send(),send是發(fā)送一個(gè)參數(shù)給res的鹿榜。

def foo():
    print("starting...")
    while True:
        res = yield 4
        print("res:",res)
g = foo()
print(next(g))
print(g.send(7))

輸出結(jié)果

starting...
4
res: 7
4

yield相關(guān)參考

Python中的一些高階函數(shù)

sorted

Python的內(nèi)置函數(shù)sorted可以接受一個(gè)key來指定排序的方法。

>>> sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]

默認(rèn)從小到大排序锦爵,如果想從大到小舱殿,加入額外參數(shù)reverse。

sorted([36, 5, -12, 9, -21], key=abs , reverse=True)

key的運(yùn)作方式是將key指定的函數(shù)將作用于list的每一個(gè)元素上险掀,并根據(jù)key函數(shù)返回的結(jié)果進(jìn)行排序沪袭。

例如對部分學(xué)生的按名字和按成績分別進(jìn)行排序:

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

def by_name(t):
    return t[0]

def by_score(t):
    return t[1]

l2 = sorted(L, key = by_name)
l3 = sorted(L, key = by_score)

map/reduce

關(guān)于map和reduce的概念,在MapReduce: Simplified Data Processing on Large Clusters這篇論文具體提及樟氢。其實(shí)在并行計(jì)算上map和reduce也是基礎(chǔ)的概念冈绊,在并行計(jì)算上map負(fù)責(zé)把大規(guī)模的數(shù)據(jù)量和運(yùn)算量任務(wù)分給多個(gè)核心。reduce負(fù)責(zé)把多個(gè)運(yùn)算結(jié)果總和成一個(gè)埠啃。

<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/python/map.png' width ='400'>

map()傳入的第一個(gè)參數(shù)是f死宣,即函數(shù)對象本身。由于結(jié)果r是一個(gè)Iterator碴开,Iterator是惰性序列毅该,因此通過list()函數(shù)讓它把整個(gè)序列都計(jì)算出來并返回一個(gè)list。

<img src='http://breezepicture.oss-cn-beijing.aliyuncs.com/python/reduce.png' width ='400'>

reduce在使用前需要from functools import reduce潦牛,然后reduce后面跟的函數(shù)需要是一個(gè)含兩個(gè)參數(shù)的眶掌。

filter

Python內(nèi)建的filter()函數(shù)用于過濾序列。filter()把傳入的函數(shù)依次作用于每個(gè)元素巴碗,然后根據(jù)返回值是True還是False決定保留還是丟棄該元素畏线。和map()一樣filter()函數(shù)返回的是一個(gè)Iterator,也就是一個(gè)惰性序列良价,所以需要用list()函數(shù)獲得所有結(jié)果并返回list寝殴。

把一個(gè)序列中的空字符串刪掉,可以這么寫:

def not_empty(s):
    return s and s.strip()

list(filter(not_empty, ['A', '', 'B', None, 'C', '  ']))
# 結(jié)果: ['A', 'B', 'C']

用filter求素?cái)?shù)的方法

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

def main():
    for n in primes():
        if n < 1000:
            print(n)
        else:
            break

def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n

def _not_divisible(n):
    return lambda x: x % n > 0

def primes():
    yield 2
    it = _odd_iter()
    while True:
        n = next(it)
        yield n
        it = filter(_not_divisible(n), it)

if __name__ == '__main__':
    main()

這個(gè)方法是埃氏篩法明垢,具體思路是蚣常,2是唯一的偶數(shù)素?cái)?shù)優(yōu)先輸出,然后接下來就從奇數(shù)序列里找素?cái)?shù)痊银,_odd_iter構(gòu)建了一個(gè)生成奇數(shù)的generator抵蚊。然后從3,5,7不斷增加這個(gè)generator的長度贞绳,之后到9的時(shí)候用filter看看9會不會被目前it這個(gè)生成器里已經(jīng)有的元素整除谷醉,發(fā)現(xiàn)3能,所以會被_not_divisible篩除掉冈闭。這樣不斷往后推進(jìn)俱尼,就可以得到1000以內(nèi)的所有素?cái)?shù)。

這個(gè)代碼里值得注意的地方:
對于if __name__ == '__main__'的理解
首先函數(shù)對象有一個(gè)__name__屬性萎攒,其次簡單來講if __name__ == '__main__'的意思是:當(dāng).py文件被直接運(yùn)行時(shí)遇八,if __name__ == '__main__'之下的代碼塊將被運(yùn)行;當(dāng).py文件以模塊形式被導(dǎo)入時(shí)耍休,if __name__ == '__main__'之下的代碼塊不被運(yùn)行刃永。參考
lambda的理解
lambda其實(shí)是創(chuàng)建了一個(gè)匿名函數(shù)。當(dāng)你需要用到的函數(shù)不是很復(fù)雜羊精,你又懶得單獨(dú)另起名字和另寫一個(gè)def的時(shí)候斯够,就可以用。這塊在下面的匿名函數(shù)里會提及喧锦。

匿名函數(shù)读规、裝飾器與偏函數(shù)

匿名函數(shù)

接著上面的filter求素?cái)?shù)的程序來看:關(guān)鍵字lambda表示匿名函數(shù),冒號前面的x表示函數(shù)參數(shù)裸违。

舉個(gè)例子理解下上面的_not_divisible的運(yùn)行方式:

def get_y(a,b):
     return lambda x:ax+b //x作為傳入的參數(shù)
y1 = get_y(1,1)
y1(1) # 結(jié)果為2

當(dāng)然,也可以用常規(guī)函數(shù)實(shí)現(xiàn)本昏,如下:

def get_y(a,b):
    def func(x):
        return ax+b
    return func
y1 = get_y(1,1)
y1(1) # 結(jié)果為2

那么如果匿名函數(shù)不用傳入?yún)?shù)呢供汛,純粹就是變成求a+b的和可以寫為
def get_y(a,b):
     return lambda:a+b 

匿名函數(shù)有個(gè)限制,就是只能有一個(gè)表達(dá)式涌穆,不用寫return怔昨,返回值就是該表達(dá)式的結(jié)果。

用匿名函數(shù)有個(gè)好處宿稀,因?yàn)楹瘮?shù)沒有名字趁舀,不必?fù)?dān)心函數(shù)名沖突。此外祝沸,匿名函數(shù)也是一個(gè)函數(shù)對象矮烹,也可以把匿名函數(shù)賦值給一個(gè)變量,再利用變量來調(diào)用該函數(shù)罩锐。

對于這一點(diǎn)奉狈,有個(gè)例子:

def count():
    def f(j):
        return lambda:j*j
    fs = []
    for i in range(1, 4):
        fs.append(f(i))
    return fs

f1, f2, f3 = count()

print(count())
print(f1())
print(f2())
print(f3())

在這個(gè)測試?yán)锩孢\(yùn)行完count之后fs這個(gè)list里存的其實(shí)是三個(gè)函數(shù),只有在用f1()調(diào)用這個(gè)函數(shù)的時(shí)候才會輸出值涩惑。

<img src="http://breezepicture.oss-cn-beijing.aliyuncs.com/python/lambda.png" >

裝飾器

裝飾器的詳細(xì)講解

裝飾器本質(zhì)上是一個(gè) Python 函數(shù)或類仁期,它可以讓其他函數(shù)或類在不需要做任何代碼修改的前提下增加額外功能,裝飾器的返回值也是一個(gè)函數(shù)/類對象。它經(jīng)常用于有切面需求的場景跛蛋,比如:插入日志熬的、性能測試、事務(wù)處理赊级、緩存押框、權(quán)限校驗(yàn)等場景,裝飾器是解決這類問題的絕佳設(shè)計(jì)此衅。有了裝飾器强戴,我們就可以抽離出大量與函數(shù)功能本身無關(guān)的雷同代碼到裝飾器中并繼續(xù)重用。對于裝飾器用廖雪峰網(wǎng)站的一個(gè)例子:

我們先定義一個(gè)很簡單的函數(shù)挡鞍。

def now():
    print('2019-1-1')

如果我們在之后想要增強(qiáng)now()函數(shù)的功能骑歹,又不希望改變now()函數(shù)的定義,這時(shí)候就需要用到裝飾器的概念墨微。

本質(zhì)上道媚,decorator就是一個(gè)返回函數(shù)的高階函數(shù)。譬如我們寫一個(gè)打印函數(shù)調(diào)用日志的函數(shù)翘县。

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

之后我們在原來的now()函數(shù)的def前加上@log,也就是

@log
def now():
    print('2019-1-1')

這一步相當(dāng)于執(zhí)行now = log(now)最域。所以,調(diào)用now()函數(shù)時(shí)候需要先進(jìn)入log函數(shù)锈麸,然后先print('call %s():' % func.__name__)之后return return func(*args, **kw)回到初始的now()函數(shù)镀脂,輸出'2019-1-1'。

所以調(diào)用now()的輸出為:

>>> now()
call now():
2019-1-1

wrapper()函數(shù)的參數(shù)定義是(*args, **kw)忘伞,因此薄翅,wrapper()函數(shù)可以接受任意參數(shù)的調(diào)用。在wrapper()函數(shù)內(nèi)氓奈,首先打印日志翘魄,再緊接著調(diào)用原始函數(shù)。

@wraps(view_func)的作用: 不改變使用裝飾器原有函數(shù)的結(jié)構(gòu)(如__name__, __doc__)舀奶。如果不帶這個(gè)的話暑竟,加了修飾器之后now.__name__會變成wrapper,但是我們其實(shí)不希望改動原函數(shù)的這些熟悉育勺。所以需要加@wraps但荤。

對于帶參數(shù)的decorator,舉一個(gè)完整的輸入日志的例子涧至。其實(shí)就是你可以在所有你需要記錄調(diào)用記錄的函數(shù)上加上這個(gè)修飾器纱兑,然后每次調(diào)用都會輸出相關(guān)信息到日志文件。

from functools import wraps
 
def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打開logfile化借,并寫入內(nèi)容
            with open(logfile, 'a') as opened_file:
                # 現(xiàn)在將日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator
 
@logit()
def myfunc1():
    pass
 
myfunc1()
# Output: myfunc1 was called
# 現(xiàn)在一個(gè)叫做 out.log 的文件出現(xiàn)了潜慎,里面的內(nèi)容就是上面的字符串
 
@logit(logfile='func2.log')
def myfunc2():
    pass
 
myfunc2()
# Output: myfunc2 was called
# 現(xiàn)在一個(gè)叫做 func2.log 的文件出現(xiàn)了屑宠,里面的內(nèi)容就是上面的字符串
    

偏函數(shù)

int函數(shù)還提供額外的base參數(shù)足删,默認(rèn)值為10,也就是十進(jìn)制。傳入8也就是八進(jìn)制。
int('12345', base=8)

>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85

理解運(yùn)行過程可以舉個(gè)例子勃救,如max2 = functools.partial(max, 10)相當(dāng)于會把附帶的參數(shù)自動放到最左邊单刁。

max2(2,5,6)相當(dāng)于

args = (10,5,6,7)
max(*args)

所以運(yùn)行結(jié)果為10钳踊。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末资溃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鳖悠,更是在濱河造成了極大的恐慌榜掌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乘综,死亡現(xiàn)場離奇詭異憎账,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)卡辰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門胞皱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人九妈,你說我怎么就攤上這事反砌。” “怎么了萌朱?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵宴树,是天一觀的道長。 經(jīng)常有香客問我晶疼,道長酒贬,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任冒晰,我火速辦了婚禮同衣,結(jié)果婚禮上竟块,老公的妹妹穿的比我還像新娘壶运。我一直安慰自己,他們只是感情好浪秘,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布蒋情。 她就那樣靜靜地躺著,像睡著了一般耸携。 火紅的嫁衣襯著肌膚如雪棵癣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天夺衍,我揣著相機(jī)與錄音狈谊,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛河劝,可吹牛的內(nèi)容都是我干的壁榕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼赎瞎,長吁一口氣:“原來是場噩夢啊……” “哼牌里!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起务甥,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤牡辽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后敞临,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體态辛,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年哟绊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了因妙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡票髓,死狀恐怖攀涵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情洽沟,我是刑警寧澤以故,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站裆操,受9級特大地震影響怒详,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踪区,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一昆烁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缎岗,春花似錦静尼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至眷细,卻和暖如春拦盹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背溪椎。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工普舆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恬口,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓沼侣,卻偏偏與公主長得像楷兽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子华临,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355