1. 程式人生 > >python學習第五天

python學習第五天

func python程序 找到 即使 內置函數 star d+ 腳本 ttr

  

一、遞歸調用

  遞歸調用是函數嵌套調用的一種特殊形式,函數在調用時,直接或間接調用了自身,就是遞歸調用;遞歸調用分為遞歸和回溯兩個階段

#示例:
#場景:已知A的工資比B的工資多200;B的工資比C的工資多200;C的工資比D的工資多200;D的工資比E的工資多200;E的工資為8000;求A的工資
def salary(n):
    if n==1:
        return 8000
    else:
        return salary(n-1)+200
salary_A=salary(5)
print(salary_A)

  #註意事項:
  python中的遞歸效率低,需要在進入下一次遞歸時保留當前的狀態,在其他語言中可以有解決方法:尾遞歸優化,即在函數的最後一步(而非最後一行)調用自己,尾遞歸優化; 但是python又沒有尾遞歸,且對遞歸層級做了限制

  #總結遞歸的使用:
  1. 必須有一個明確的結束條件 2. 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少 3. 遞歸效率不高,遞歸層次過多會導致棧溢出(在計算機中,函數調用是通過棧(stack)這種數據結構實現的,每當進入一個函數調用,棧就會加一層棧幀,每當函數返回,棧就會減一層棧幀。由於棧的大小不是無限的,所以,遞歸調用的次數過多,會導致棧溢出)

  #修改遞歸的最大深度

import sys
sys.getrecursionlimit()
sys.setrecursionlimit(2000)
n=1
def test():
    global n
    print(n)
    n
+=1 test() test() #雖然可以設置,但是因為不是尾遞歸,仍然要保存棧,內存大小一定,不可能無限遞歸

二、二分法

#場景:
#要求查看某一列表中是否有有某個值,該列表中數值由小到大的順序排列(即實現類似與in的功能)
num_list=[1,2,3,10,30,45,66,80,200,300,500,770]
def get_num(num,num_list):
    mid=len(num_list)//2
    if num_list:
        if num_list[mid] > num:
            num_list=num_list[:mid]
        
elif num_list[mid] < num: num_list=num_list[mid+1:] else: print(find it) return get_num(num,num_list) else: print(not find) return get_num(210,num_list)

三、匿名函數

  沒有名字的函數;只能使用一次

lambda x,y,z:x+y+z
#作用同下列有名函數:
def func(x,y,z):
    return x+y+z

  #有名函數與匿名函數的對比
  有名函數:循環使用,保存了名字,通過名字就可以重復引用函數功能 匿名函數:一次性使用,隨時隨時定義 應用:max,min,sorted,map,reduce,filter

#員工工資信息如下列字典,求最大工資# ,最小工資,和排序
salaries={
    egon:3000,
    alex:100000000,
    wupeiqi:10000,
    yuanhao:2000
}
# 用匿名函數
print(max(salaries,key=lambda k:salaries[k]))
print(min(salaries,key=lambda k:salaries[k]))
print(sorted(salaries,key=lambda k:salaries[k]))

# 用zip拉鏈
salaries_and_name=zip(salaries.values(),salaries.keys())#叠代器,只能訪問一次
print(max(salaries_and_name))
salaries_and_name=zip(salaries.values(),salaries.keys())
print(min(salaries_and_name))
salaries_and_name=zip(salaries.values(),salaries.keys())
print(sorted(salaries_and_name))

四、內置函數

#優先掌握
#max、#min、#sorted--->示例參見上文匿名函數中的應用示例內容

#map
#map()是 Python 內置的高階函數,它接收一個函數 f 和一個 list,並通過把函數 f 依次作用在 list 的每個元素上,得到一個新的 list 並返回。
#例如,對於list [1, 2, 3, 4, 5, 6, 7, 8, 9] ;如果希望把list的每個元素都作平方,就可以用map()函數;map返回的是一個生成器,可以用list轉為列表
num_list=[i for i in range(1,10)]
new=map(lambda i:i*i,num_list)
print(list(new),type(new))

#  reduce
# reduce()函數也是Python內置的一個高階函數。
# reduce()函數接收的參數和 map()類似,一個函數 f,一個list,但行為和 map()不同,reduce()傳入的函數 f 必須接收兩個參數,
# reduce()對list的每個元素反復調用函數f,並返回最終結果值。
# 例如,編寫一個f函數,接收x和y,返回x和y的和:
# 求和,依次相加如[0,1,2,3,4,5,6,7,8,9]
# 0+1=1
# 1+2=3
# 3+3=6
# 6+4=10
# ......
from _functools import reduce
num_list=[i for i in range(1,10)]
num=reduce(lambda x,y:x+y,num_list)
num2=reduce(lambda  x,y:x+y,num_list,100)#第三個參數作為計算的初始值
print(num,num2)

# filter
#filter()函數是 Python 內置的另一個有用的高階函數,filter()函數接收一個函數 f 和一個list,
# 這個函數 f 的作用是對每個元素進行判斷,返回 True或 False,filter()根據判斷結果自動過濾掉不符合條件的元素,
# 返回由符合條件元素組成的新list。
#要從一個list [1, 4, 6, 7, 9, 12, 17]中刪除偶數,保留奇數,首先,要編寫一個判斷奇數的函數:
num_list=[1,4,6,7,9,12,17]
new=filter(lambda i:i%2,num_list)
print(list(new),type(new))

# sum
print(sum([i for i in range(1,11)]))

# bool
print(bool([]),bool(‘‘),bool(None),bool(0))

# chr #將ascii碼轉換為對應的字符
print(chr(65))

#ord #將字符轉為對應的ascii碼
print(ord(A))

# divmod #取商和余數
print(divmod(7,2))

# enumerate #enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合為一個索引序列,
# 同時列出數據和數據下標,一般用在 for 循環當中。
seasons = [Spring, Summer, Fall, Winter]
print(list(enumerate(seasons)),type(enumerate(seasons)))
print(list(enumerate(seasons,start=2)))#start指定起始以序號值

# id
#內置函數id()可以返回一個對象的身份,返回值為整數。這個整數通常對應與該對象在內存中的位置,
#但這與python的具體實現有關,不應該作為對身份的定義,即不夠精準,最精準的還是以內存地址為準。
#is運算符用於比較兩個對象的身份,等號比較兩個對象的值,內置函數type()則返回一個對象的類型

# input

# print

#isinstance #判斷對象類型,返回bool值
l=[1,2,q]
print(isinstance(l,list))

# iter #將叠代器轉換為生成器
l=[1,2,3]
new_l=iter(l)
print(next(new_l))
print(next(new_l))

# len

# open

# pow
print(pow(10,2,3)) #10**2%3

# type

# zip
#使用zip()函數來可以把列表合並,並創建一個元組對的列表。
l1=[1,2,3,4]
l2=[q,a]
new=zip(l1,l2)
print(list(new),type(new))

五、模塊與包

  5.1模塊

    5.1.1模塊的定義

      一個模塊就是一個包含了python定義和聲明的文件(文件名就是模塊名字加上.py的後綴),模塊可以被導入使用。

      import加載的模塊分為四個通用類別:

                    1 使用python編寫的.py文件   

                    2 已被編譯為共享庫或DLL的C或C++擴展   

                    3 把一系列模塊組織到一起的文件夾(註:文件夾下有一個__init__.py文件,該文件夾稱之為包)

                    4 使用C編寫並鏈接到python解釋器的內置模塊
   5.1.2模塊的使用

#模塊可以包含可執行的語句和函數的定義,這些語句的目的是初始化模塊,它們只在模塊名第
#一次遇到導入import語句時才執行(import語句是可以在程序中的任意位置使用的,且針對同
#一個模塊很import多次,為了防止你重復導入,python的優化手段是:第一次導入後就將模塊
#名加載到內存了,後續的import語句僅是對已經加載大內存中的模塊對象增加了一次引用,
#不會重新執行模塊內的語句),如下 

#test.py
import spam
 #只在第一次導入時才執行spam.py內代碼,此處的顯式效果是只打印一次‘from the spam.py‘,當然其他的頂級代碼也都被執行了,只不過沒有顯示效果.
import spam
import spam
import spam

‘‘‘
執行結果:
from the spam.py
‘‘‘
#ps:我們可以從sys.module中找到當前已經加載的模塊,sys.module是一個字典,內部包含模塊名與模塊對象的映射,該字典決定了導入模塊時是否需要重新導入。

#首次import時做了三件事
#1.為源文件(spam模塊)創建新的名稱空間,在spam中定義的函數和方法若是使用到了global時訪問的就是這個名稱空間。

#2.在新創建的命名空間中執行模塊中包含的代碼,見初始導入import spam
    提示:導入模塊時到底執行了什麽?
    In fact function definitions are also ‘statements’ that are 
    ‘executed’; the execution of a module-level function definition 
    enters the function name in the module’s global symbol table.
    事實上函數定義也是“被執行”的語句,模塊級別函數定義的執行將函數名放
    入模塊全局名稱空間表,用globals()可以查看

#3.創建名字spam來引用該命名空間
    這個名字和變量名沒什麽區別,都是‘第一類的’,且使用spam.名字的方式
    可以訪問spam.py文件中定義的名字,spam.名字與test.py中的名字來自
    兩個完全不同的地方。

#每個模塊都是一個獨立的名稱空間,定義在這個模塊中的函數,把這個模塊的名稱空間當
#做全局名稱空間,這樣我們在編寫自己的模塊時,就不用擔心我們定義在自己模塊中全局
#變量會在被導入時,與使用者的全局變量沖突

#4、為模塊名起別名
#為已經導入的模塊起別名的方式對編寫可擴展的代碼很有用
import spam as sm
print(sm.money)

#5、在一行導入多個模塊
import sys,os,re


#6、from...import 與import的對比
#唯一的區別就是:使用from...import...則是將spam中的名字直接導入到當前的名稱空間中,所以在當前名稱空間中,直接使用名字就可以了、無需加前綴:spam.

#6from...import...的方式有好處也有壞處
    好處:使用起來方便了
    壞處:容易與當前執行文件中的名字沖突

    #也支持as
from spam import read1 as read

    #也支持導入多行
from spam import (read1,
                   read2,
                   money)
    #from...import *
#from spam import * 把spam中所有的不是以下劃線(_)開頭的名字都導入到當前位置

#大部分情況下我們的python程序不應該使用這種導入方式,因為*你不知道你導入什麽名字,很有可能會覆蓋掉你之前已經定義的名字。而且可讀性極其的差,在交互式環境中導入時沒有問題。
#可以使用__all__來控制*(用來發布新版本),在spam.py中新增一行
__all__=[money,read1] #這樣在另外一個文件中用from spam import *就這能導入列表中規定的兩個名字  

  5.1.3 模塊重載

  python 重載模塊必須重啟程序,python不支持重新加載或卸載之前導入的模塊;如果只是你想交互測試的一個模塊,使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename),這只能用於測試環境。

  5.1.4 模塊的搜索路徑

  1)查看內存中是否已經加載相應模塊,

  2)1中沒有則,查找同名的內建模塊,

  3)2中沒有則在sys.path給出的目錄列表中依次尋找相應文件

    ps:#在初始化後,python程序可以修改sys.path,路徑放到前面的優先於標準庫被加載。
    >>> import sys 2

    >>> sys.path.append(‘/a/b/c/d‘)

    >>> sys.path.insert(0,‘/x/y/z‘)
    註意:搜索時按照sys.path中從左到右的順序查找,位於前的優先被查找,sys.path中還可能包含.zip歸檔文件和.egg文件,python會把.zip歸檔文件當成一個目錄去處理,

    #首先制作歸檔文件:zip module.zip foo.py bar.py
    import sys sys.path.append(‘module.zip‘) import foo,bar #也可以使用zip中目錄結構的具體位置
    sys.path.append(‘module.zip/lib/python‘) #windows下的路徑不加r開頭,會語法錯誤
    sys.path.insert(0,r‘C:\Users\Administrator\PycharmProjects\a‘) #至於.egg文件是由setuptools創建的包,這是按照第三方python庫和擴展時使用的一種常見格式,.egg文件實際上只是添    加了額外元數據(如版本號,依賴項等)的.zip文件。

    #需要強調的一點是:只能從.zip文件中導入.py,.pyc等文件。使用C編寫的共享庫和擴展塊無法直接從.zip文件中加載(此時setuptools等打包系統有時能提供一種規避方法),且從.zip中加載文件不會創建.pyc或者.pyo文件,因此一定要事先創建他們,來避免加載模塊是性能下降。

ps:python中.py文件的兩種應用

#編寫好的一個python文件可以有兩種用途:
    一:腳本,一個文件就是整個程序,用來被執行
    二:模塊,文件中存放著一堆功能,用來被導入使用


#python為我們內置了全局變量__name__,
    當文件被當做腳本執行時:__name__ 等於__main__
    當文件被當做模塊導入時:__name__等於模塊名

#作用:用來控制.py文件在不同的應用場景下執行不同的邏輯
    if __name__ == __main__:


#fib.py

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while b < n:
        print(b, end= )
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while b < n:
        result.append(b)
        a, b = b, a+b
    return result

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))


#執行:python fib.py <arguments>
python fib.py 50 #在命令行

  5.2 包

  5.2.1包的定義

  包就是一個包含有__init__.py文件的文件夾,所以其實我們創建包的目的就是為了用文件夾將文件/模塊組織起來

  5.2.2包的使用
  1) 在python3中,即使包下沒有__init__.py文件,import 包仍然不會報錯,而在python2中,包下一定要有該文件,否則import 包報錯

  2) 創建包的目的不是為了運行,而是被導入使用,記住,包只是模塊的一種形式而已,包的本質就是一種模塊\

  3)關於包相關的導入語句也分為import和from ... import ...兩種,但是無論哪種,無論在什麽位置,在導入時都必須遵循一個原則:凡是在導入時帶點的,點的左邊都必須是一個包,否則非法。可以帶有一連串的點,如item.subitem.subsubitem,但都必須遵循這個原則。但對於導入後,在使用時就沒有這種限制了,點的左邊可以是包,模塊,函數,類(它們都可以用點的方式調用自己的屬性)。
  4)import導入文件時,產生名稱空間中的名字來源於文件,import 包,產生的名稱空間的名字同樣來源於文件,即包下的__init__.py,導入包本質就是在導入該文件
  5)包A和包B下有同名模塊也不會沖突,如A.a與B.a來自倆個命名空間

#文件內容

#policy.py
def get():
    print(from policy.py)

#versions.py
def create_resource(conf):
    print(from version.py: ,conf)

#manage.py
def main():
    print(from manage.py)

#models.py
def register_models(engine):
    print(from models.py: ,engine)
#import
import glance.db.models
glance.db.models.register_models(mysql)
#單獨導入包名稱時不會導入包中所有包含的所有子模塊,如
#在與glance同級的test.py中
import glance
glance.cmd.manage.main()

‘‘‘
執行結果:
AttributeError: module ‘glance‘ has no attribute ‘cmd‘

‘‘‘ 
#解決方法:
#glance/__init__.py#在此文件中寫入如下內容
from . import cmd 
#glance/cmd/__init__.py
from . import manage

##from ... import ...
#需要註意的是from後import導入的模塊,必須是明確的一個不能帶點,否則會有語法錯誤,如:from a import b.c是錯誤語法
from glance.db import models
models.register_models(mysql)

from glance.db.models import register_models
register_models(mysql)

##from glance.api import *
在講模塊時,我們已經討論過了從一個模塊內導入所有*,此處我們研究從一個包導入所有*。
此處是想從包api中導入所有,實際上該語句只會導入包api下__init__.py文件中定義的名字,我們可以在這個文件中定義__all___:

#在__init__.py中定義
x=10
 
def func():
    print(from api.__init.py)
 

 __all__=[x,func,policy]

此時我們在於glance同級的文件中執行from glance.api import *就導入__all__中的內容(versions仍然不能導入)。


##絕對導入和相對導入
我們的最頂級包glance是寫給別人用的,然後在glance包內部也會有彼此之間互相導入的需求,這時候就有絕對導入和相對導入兩種方式:
絕對導入:以glance作為起始
相對導入:用.或者..的方式最為起始(只能在一個包中使用,不能用於不同目錄內)
例如:我們在glance/api/version.py中想要導入glance/cmd/manage.py

在glance/api/version.py
 
#絕對導入
from glance.cmd import manage
manage.main()

#相對導入
from ..cmd import manage
manage.main()




###註意###
包以及包所包含的模塊都是用來被導入的,而不是被直接執行的。而環境變量都是以執行文件為準的
比如我們想在glance/api/versions.py中導入glance/api/policy.py,有的同學一抽這倆模塊是在同一個目錄下,十分開心的就去做了,它直接這麽做
#在version.py中
 
import policy
policy.get()
沒錯,我們單獨運行version.py是一點問題沒有的,運行version.py的路徑搜索就是從當前路徑開始的,於是在導入policy時能在當前目錄下找到
但是你想啊,你子包中的模塊version.py極有可能是被一個glance包同一級別的其他文件導入,比如我們在於glance同級下的一個test.py文件中導入version.py,如下

 from glance.api import versions
  
 ‘‘‘
 執行結果:
 ImportError: No module named ‘policy‘
 ‘‘‘
  
 ‘‘‘
#分析:
此時我們導入versions在versions.py中執行
import policy需要找從sys.path也就是從當前目錄找policy.py,
這必然是找不到的
‘‘‘

  

python學習第五天