python基礎(7):變量、參數、函數式編程

一、使用glob模塊通配符過濾文件

使用glob模塊能夠用通配符的方式搜索某個目錄下的特定文件,返回結果是一個list html

import glob
flist=glob.glob('*.jpeg')

使用os.getcwd()能夠獲得當前目錄,若是想切換到其餘目錄,可使用os.chdir('str/to/path'),若是想執行Shell腳本,可使用os.system('mkdir newfolder')。 java

對於平常文件和目錄的管理, shutil模塊提供了更便捷、更高層次的接口 node

import shutil
shutil.copyfile('data.db', 'archive.db')
shutil.move('/build/executables', 'installdir')

使用PyCharm中,在一個Project中新建一個Directory和新建一個Package以後,IDE都會建立對應的目錄,並添加默認的__init__.py文件,可是,二者仍是不同的。 若是在它們的目錄下各新建一個python腳本測試輸出os.getcwd(),若是是在Directory中獲得的是Project的根目錄’/Users/hujiawei/PycharmProjects/leetcodeoj’;若是是在Package中獲得的是Package的根目錄,如’/Users/hujiawei/PycharmProjects/leetcodeoj/pypackage’。 python

二、代碼支持中文註釋

若是要在代碼中添加中文註釋的話,最好在文檔開頭加上下面的編碼聲明語句。關於Python中的字符串編碼可見廖雪峯的python教程。若代碼打算用在國際化的環境中, 那麼不要使用奇特的編碼。Python 默認的 UTF-8, 或者甚至是簡單的 ASCII 在任何狀況下工做得最好。一樣地,若是代碼的讀者或維護者只有很小的機率使用不一樣的語言,那麼不要在標識符裏使用非 ASCII 字符。 git

# coding=utf-8 
或者
# -*- coding: utf-8 -*-

三、關於Python中的變量命名規則

摘自廖雪峯的python教程 github

在Python中,變量名相似__xxx__的,也就是以雙下劃線開頭,而且以雙下劃線結尾的,是特殊變量,特殊變量是能夠直接訪問的,不是private變量,因此,不能用__name__、__score__這樣的變量名。 算法

有些時候,你會看到以一個下劃線開頭的實例變量名(兩個下劃線開頭的也同樣算,其實任何如下劃線開頭的都算),好比_name,這樣的實例變量外部是能夠訪問的,可是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,「雖然我能夠被訪問,可是,請把我視爲私有變量,不要隨意訪問」 spring

雙下劃線開頭的實例變量是否是必定不能從外部訪問呢?其實也不是。不能直接訪問__name是由於Python解釋器對外把__name變量改爲了_Student__name,因此,仍然能夠經過_Student__name來訪問__name變量。可是強烈建議你不要這麼幹,由於不一樣版本的Python解釋器可能會把__name改爲不一樣的變量名。 編程

總的來講就是,Python自己沒有任何機制阻止你幹壞事,一切全靠自覺。 app

上面說的有點繞,下面我寫了兩個python腳本,你們能夠對照看下哪些可以訪問,哪些不能,不能的狀況下如何操做變得能夠訪問(註釋後面的yes和no表示能不能被訪問)。

也就是說,默認呢,以一個下劃線開始(不論結尾有沒有下劃線)的變量在外部都是能夠直接訪問的,可是不推薦這麼作;以兩個下劃線開始和兩個下劃線結束的變量屬於特殊變量,能夠直接訪問;而以兩個下劃線開始且結尾不是兩個下劃線(能夠沒有也能夠有一個下劃線)的變量屬於私有變量,不能直接訪問,雖然能夠經過其餘方式訪問,但最好不要在外部訪問。

文件    APythonTestA.py

# coding=utf-8

class ListNode:

    _class_field10 = 'node class field 1-0'
    _class_field11_ = 'node class field 1-1'
    _class_field12__ = 'node class field 1-2'

    __class_field20 = 'node class field 2-0'
    __class_field21_ = 'node class field 2-1'
    __class_field22__ = 'node class field 2-2'

    def __init__(self, x):
        self.val = x
        self.next = None

_class_field10 = 'node class field 1-0'
_class_field11_ = 'node class field 1-1'
_class_field12__ = 'node class field 1-2'

__class_field20 = 'node class field 2-0'
__class_field21_ = 'node class field 2-1'
__class_field22__ = 'node class field 2-2'

文件    APythonTestB.py

# coding=utf-8
__author__ = 'hujiawei'
__doc__ = 'for python test 2'

import APythonTestA

if __name__ == '__main__':
    print(dir(APythonTestA.ListNode))
    node = APythonTestA.ListNode(4)
    # print(node._ListNode__class_field20) #yes
    print(node._class_field10) #yes
    print(node._class_field11_) #yes
    print(node._class_field12__) #yes
    # print(node.__class_field20) #no
    print(node._ListNode__class_field20)#yes
    # print(node.__class_field21_) #no
    print(node._ListNode__class_field21_)#yes
    print(node.__class_field22__) #yes

    print(dir(APythonTestA))
    print(APythonTestA._class_field10) #yes
    print(APythonTestA._class_field11_) #yes
    print(APythonTestA._class_field12__) #yes
    print(APythonTestA.__class_field20) #yes
    print(APythonTestA.__class_field21_) #yes
    print(APythonTestA.__class_field22__) #yes

# ['_ListNode__class_field20', '_ListNode__class_field21_', '__class_field22__', '__doc__', '__init__', '__module__', '_class_field10', '_class_field11_', '_class_field12__']
# node class field 1-0
# node class field 1-1
# node class field 1-2
# node class field 2-0
# node class field 2-1
# node class field 2-2
# ['ListNode', '__builtins__', '__class_field20', '__class_field21_', '__class_field22__', '__doc__', '__file__', '__name__', '__package__', '_class_field10', '_class_field11_', '_class_field12__']
# node class field 1-0
# node class field 1-1
# node class field 1-2
# node class field 2-0
# node class field 2-1
# node class field 2-2

四、關於Python中函數的參數

摘自廖雪峯的python教程

Python的函數具備很是靈活的參數形態,既能夠實現簡單的調用,又能夠傳入很是複雜的參數。 默認參數必定要用不可變對象,若是是可變對象,運行會有邏輯錯誤!

要注意定義可變參數和關鍵字參數的語法:

*args是可變參數,args接收的是一個tuple;

**kw是關鍵字參數,kw接收的是一個dict。

以及調用函數時如何傳入可變參數和關鍵字參數的語法:

可變參數既能夠直接傳入:func(1, 2, 3),又能夠先組裝list或tuple,再經過*args傳入:func(*(1, 2, 3));

關鍵字參數既能夠直接傳入:func(a=1, b=2),又能夠先組裝dict,再經過**kw傳入:func(**{'a': 1, 'b': 2})。

使用*args和**kw是Python的習慣寫法,固然也能夠用其餘參數名,但最好使用習慣用法。

五、關於Python的高級特性

參見廖雪峯的python教程

切片,迭代,列表生成式,生成器

除非特殊的緣由,應該常常在代碼中使用生成器表達式。但除非是面對很是大的列表,不然是不會看出明顯區別的。

使用生成器獲得當前目錄及其子目錄中的全部文件的代碼,下面代碼來自伯樂在線-python高級編程技巧

import os
def tree(top):
    #path,folder list,file list
    for path, names, fnames in os.walk(top):
        for fname in fnames:
            yield os.path.join(path, fname)

for name in tree(os.getcwd()):
    print name

另外一個使用生成器的代碼示例:

num = [1, 4, -5, 10, -7, 2, 3, -1]

def square_generator(optional_parameter):
    return (x ** 2 for x in num if x > optional_parameter)

print square_generator(0)
# <generator object <genexpr> at 0x004E6418>

# Option I
for k in square_generator(0):
    print k
# 1, 16, 100, 4, 9

# Option II
g = list(square_generator(0))
print g
# [1, 16, 100, 4, 9]

六、關於Python的函數式編程

參見廖雪峯的python教程,講解得很好

高階函數(使用函數做爲參數或者返回一個函數的函數稱爲高階函數),匿名函數(lambda),裝飾器(decorator)和偏函數

用來測試一個函數花費的運行時間的裝飾器,固然你也可使用其餘的方式,好比Timer來獲得運行時間。下面代碼來自伯樂在線-python高級編程技巧

def timethis(func):
    '''
    Decorator that reports the execution time.
    '''
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(func.__name__, end-start)
        return result
    return wrapper

@timethis
def countdown(n):
    while n > 0:
        n -= 1

其中代碼

@timethis
def countdown(n):

就至關於:

def countdown(n):
...
countdown = timethis(countdown)

裝飾器除了可使用函數實現,也可使用類來實現。

對裝飾器的類實現的惟一要求是它必須能如函數通常使用,也就是說它必須是可調用的。因此,若是想這麼作這個類必須實現__call__方法。

class decorator(object):

    def __init__(self, f):
        print("inside decorator.__init__()")
        f() # Prove that function definition has completed

    def __call__(self):
        print("inside decorator.__call__()")

@decorator
def function():
    print("inside function()")

print("Finished decorating function()")

function()

# inside decorator.__init__()
# inside function()
# Finished decorating function()
# inside decorator.__call__()

  1. 語法糖@decorator至關於function=decorator(function),在此調用decorator的__init__打印「inside decorator.__init__()」

  2. 隨後執行f()打印「inside function()」

  3. 隨後執行「print(「Finished decorating function()」)」

  4. 最後再調用function函數時,因爲使用裝飾器包裝,所以執行decorator的__call__打印 「inside decorator.__call__()」。

==個人批註:我以爲上面代碼不是通常的使用方式,實際裝飾器類應該是在__init__方法中設置好本身內部的函數f,而後在方法__call__中調用函數f,幷包含一些其餘的方法調用,大概以下:

class decorator(object):

    def __init__(self, f):
        print("inside decorator.__init__()")
        # f() # Prove that function definition has completed
        self.f=f

    def __call__(self):
        print("inside decorator.__call__() begin")
        self.f()
        print("inside decorator.__call__() end")

@decorator
def function():
    print("inside function()")

print("Finished decorating function()")

function()

# inside decorator.__init__()
# Finished decorating function()
# inside decorator.__call__() begin
# inside function()
# inside decorator.__call__() end

在提供一個裝飾器的例子,實現自頂向下的帶備忘錄的DP算法來解決斐波那契數列求值,來源於Python Algorithms- Mastering Basic Algorithms in the Python Language

from functools import wraps

def memo(func):
    cache={}
    @wraps(func)
    def wrap(*args):
        if args not in cache:
            cache[args]=func(*args)
        return cache[args]
    return wrap

@memo
def fib(i):
    if i<2: return 1
    return fib(i-1)+fib(i-2)

print(fib(100))

七、Python中的值傳遞和引用傳遞

參考閱讀資料

python函數傳遞的是對象的引用值,非傳值或傳引用。可是若是對象是不可變的,感受和c語言中傳值差很少。若是對象是可變的,感受和c語言中傳引用差很少。

運行下面的代碼就清楚了

def foo(a):
    print "傳來是對象的引用對象地址爲{0}".format(id(a))
    a = 3 #形式參數a是局部變量,a從新綁定到3這個對象。
    print "變量a新引用對象地址爲{0}".format(id(a))
    # print a

x = 5
print "全局變量x引用的對象地址爲{0}".format(id(x))
foo(x)
print "變量x新引用對象地址爲{0}".format(id(x))
print x
#因爲函數內部a綁定到新的對象,也就修改不了全局變量x引用的對象5
# 全局變量x引用的對象地址爲140462615725816
# 傳來是對象的引用對象地址爲140462615725816
# 變量a新引用對象地址爲140462615725864
# 變量x新引用對象地址爲140462615725816
# 5


def foo(a):
    """在函數內部直接修改了同一個引用指向的對象。
    也就修改了實際參數傳來的引用值指向的對象。
    """
    a.append("can change object")
    return a

lst = [1,2,3]
print foo(lst)
print lst
#[1, 2, 3, 'can change object']
#[1, 2, 3, 'can change object']


def foo(a):
    """實際參數傳來一個對象[1,2,3]的引用,當時形式參數
    (局部變量a從新引用到新的對象,也就是說保存了新的對象)
    固然不能修改原來的對象了。
    """
    a = ["python","java"]
    return a

lst = [1,2,3]
for item in foo(lst):
    print item
print lst
# python
# java

# coding=utf-8
# 測試utf-8編碼
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

list_a = []

def a():
    # list_a = [1]      ## 語句1  []
    list_a.append(1)    ## 語句2  [1]

a()
print list_a

八、Refer:

http://hujiaweibujidao.github.io/blog/2014/05/10/python-tips1/

Python Algorithms - Dynamic Programming

http://hujiaweibujidao.github.io/blog/2014/05/08/python-algorithms-dynamic-programming/

相關文章
相關標籤/搜索