python基礎語法

--Python:  基本運算、基本函數(包括複數)、Math模塊、NumPy模塊

--基本運算


x**2 : x^2 若x是mat矩陣,那就表示x內每個元素求平方

inf:  表示正無窮

邏輯運算符:  and,or,not

--基本函數


字典的get方法


a.get(k,d)

1

get相當於一條if…else…語句。若k在字典a中,則返回a[k];若k不在a中,則返回參數d。


l = {5:2,3:4}

l.get(3,0)  返回值是4;

l.get(1,0)  返回值是0;

1

2

3

type函數:  返回數據類型


type(x):返回x的類型

type(x)._name_:  返回該類型的字符串表示

1

2

len函數:  獲得list或str的長度


reload函數:  將之前導入過的模塊重新加載進來


next函數    本函數是返回迭代器的下一個元素的值。

在Python 3中,只能使用next()函數(試圖調用.next()方法會觸發AttributeError)。


my_generator = (letter for letter in 'abcdefg')

next(my_generator)


>>>'a'








--2-----------Python 編碼格式-----中文編碼---------------------------------------------------------------------------------------------------------------

Python中默認的編碼格式是 ASCII 格式,在沒修改編碼格式時無法正確打印漢字,所以在讀取中文時會報錯。

注意:  Python3.X 源碼文件默認使用utf-8編碼,所以可以正常解析中文,無需指定 UTF-8 編碼。

注意:  如果你使用編輯器,同時需要設置 py 文件存儲的格式爲 UTF-8,否則會出現類似以下錯誤信息

#!/usr/bin/python

# -*- coding: UTF-8 -*-   ##解決法1:  只要在文件開頭加入 或~ 代碼中包含中文,要在頭部指定編碼

#coding: UTF-8            ##解決法2:  只要在文件開頭加入 或#coding=utf-8 就行(注意:  #coding=utf-8 的 = 號兩邊不要空格)

print "Hello, World!";    ##英文沒有問題

print "你好,世界";       ##但是如果輸出中文字符"你好,世界"就有可能會碰到中文編碼問題。

Python 文件中如果未指定編碼,在執行過程會出現報錯:

SyntaxError: Non-ASCII character '\xe4' in file test.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

--3-----------Python 基礎語法----------------------------------------------------------------------------------------------------------------------------

--標識符------區分大小寫

所有標識符,可以包括:  字母、數字、下劃線。

     字母......區分大小寫

     數字......不能以數字開頭

     下劃線....以下劃線開頭的標識符是有特殊意義的:

               以單下劃線開頭          _foo     代表不能直接訪問的類屬性,需通過類提供的接口進行訪問,不能用"from xxx import *"而導入;

               以雙下劃線開頭的        __foo    代表類的私有成員;

               以雙下劃線開頭和結尾的  __foo__  代表python裏特殊方法專用的標識,如__init__()代表類的構造函數。

--保留關鍵字------所有Python關鍵字只包含小寫字母

這些保留字不能用作常數或變數,或任何其他標識符名稱。

and       exec      not      assert    finally   or

break     for       pass     class     from      print

continue  global    raise    def       if        return

del       import    try      elif      in        while

else      is        with     except    lambda    yield

--註釋------單行註釋------採用 # 開頭

--註釋------多行註釋------使用三個單引號'''  或  三個雙引號"""

註釋可以在語句或表達式行末

#!/usr/bin/python

# -*- coding: UTF-8 -*-

# 文件名:  test.py

# 第1個註釋

print "Hello, Python!";  # 第2個註釋

name = "Madisetti"       # 這是3個註釋

'''

這是多行註釋,使用單引號。

'''

"""

這是多行註釋,使用雙引號。

"""

--行和縮進------python 最具特色的:用縮進來寫模塊

學習 Python 與其他語言最大的區別就是,Python 的代碼塊不使用大括號 {} 來控制類,函數以及其他邏輯判斷。

縮進的空白數量是可變的,但是所有代碼塊語句必須包含相同的縮進空白數量,這個必須嚴格執行。

#!/usr/bin/python

# -*- coding: UTF-8 -*-

# 文件名:  test.py

if True:

    print "Answer"

    print "True"

else:

    print "Answer"

    # 沒有嚴格縮進,在執行時會報錯

  print "False"

執行以上代碼,會出現如下錯誤提醒:

$ python test.py

  File "test.py", line 5

    if True:

    ^

IndentationError: unexpected indent

IndentationError: unexpected indent 錯誤是 python 編譯器是在告訴你"Hi,老兄,你的文件裏格式不對了,可能是tab和空格沒對齊的問題",所有 python 對格式要求非常嚴格。

如果是 IndentationError: unindent does not match any outer indentation level錯誤表明,你使用的縮進方式不一致,有的是 tab 鍵縮進,有的是空格縮進,改爲一致即可。

因此,在 Python 的代碼塊中必須使用相同數目的行首縮進空格數。

建議你在每個縮進層次使用 單個製表符 或 兩個空格 或 四個空格 , 切記不能混用

--多行語句

Python語句中一般以新行作爲爲語句的結束符。

但是我們可以使用斜槓( \)將一行的語句分爲多行顯示,

total = item_one + \

        item_two + \

        item_three

語句中包含 [], {} 或 () 括號就不需要使用多行連接符。

days = ['Monday', 'Tuesday', 'Wednesday',

        'Thursday', 'Friday']

--引號

Python 可以使用引號( ' )、雙引號( " )、三引號( ''' 或 """ ) 來表示字符串,引號的開始與結束必須的相同類型的。

其中三引號可以由多行組成,編寫多行文本的快捷語法,常用於文檔字符串,在文件的特定地點,被當做註釋。

word = 'word'

sentence = "這是一個句子。"

paragraph = """這是一個段落。

包含了多個語句"""

--空行

函數之間或類的方法之間用空行分隔,表示一段新的代碼的開始。類和函數入口之間也用一行空行分隔,以突出函數入口的開始。

空行與代碼縮進不同,空行並不是Python語法的一部分。書寫時不插入空行,Python解釋器運行也不會出錯。但是空行的作用在於分隔兩段不同功能或含義的代碼,便於日後代碼的維護或重構。

記住:  空行也是程序代碼的一部分。

--等待用戶輸入

下面的程序執行後就會等待用戶輸入,按回車鍵後就會退出:

#!/usr/bin/python

raw_input("\n\nPress the enter key to exit.")

以上代碼中 ,"\n\n"在結果輸出前會輸出兩個新的空行。一旦用戶按下 enter(回車) 鍵退出,其它鍵顯示。

--同一行顯示多條語句

Python可以在同一行中使用多條語句,語句之間使用分號(;)分割,以下是一個簡單的實例:

#!/usr/bin/python

import sys; x = 'runoob'; sys.stdout.write(x + '\n')

執行以上代碼,輸入結果爲:

$ python test.py

runoob

--Print 輸出

print 默認輸出是換行的,如果要實現不換行需要在變量末尾加上逗號 ,

Python 可以同一行顯示多條語句,方法是用分號 ; 分開,如:

>>> print 'hello';print 'runoob';

hello

runoob

#!/usr/bin/python

# -*- coding: UTF-8 -*-

x="a"

y="b"

# 換行輸出

print x

print y

print '---------'

# 不換行輸出

print x,

print y,

# 不換行輸出

print x,y

以上實例執行結果爲:

a

b

---------

a b a b

--多個語句構成代碼組

縮進相同的一組語句構成一個代碼塊,我們稱之代碼組。

像if、while、def和class這樣的複合語句,首行以關鍵字開始,以冒號( : )結束,該行之後的一行或多行代碼構成代碼組。

我們將首行及後面的代碼組稱爲一個子句(clause)。

如下實例:

if expression :

   suite

elif expression :

   suite

else :

   suite

--命令行參數

很多程序可以執行一些操作來查看一些基本信息,Python 可以使用 -h 參數查看各參數幫助信息:

$ python -h

usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...

Options and arguments (and corresponding environment variables):

-c cmd : program passed in as string (terminates option list)

-d     : debug output from parser (also PYTHONDEBUG=x)

-E     : ignore environment variables (such as PYTHONPATH)

-h     : print this help message and exit

[ etc. ]

我們在使用腳本形式執行 Python 時,可以接收命令行輸入的參數,具體使用可以參照 Python 命令行參數。

執行腳本傳入參數,使用sys模塊,編輯 test.py 如下

#!/usr/bin/python

# -*- coding: UTF-8 -*-

import sys

print sys.argv

sys.argv 用來獲取命令行參數

運行命令,執行結果:

./test.py hello

['./test.py', 'hello']

sys.argv[0] 代表文件本身路徑,所帶參數從 sys.argv[1] 開始。

腳本語言的第一行,目的就是指出,你想要你的這個文件中的代碼用什麼可執行程序去運行它,就這麼簡單。

#!/usr/bin/python : 是告訴操作系統執行這個腳本的時候,調用 /usr/bin 下的 python 解釋器;

#!/usr/bin/env python(推薦): 這種用法是爲了防止操作系統用戶沒有將 python 裝在默認的 /usr/bin 路徑裏。當系統看到這一行的時候,首先會到 env 設置裏查找 python 的安裝路徑,再調用對應路徑下的解釋器程序完成操作。

#!/usr/bin/python 相當於寫死了python路徑;

#!/usr/bin/env python 會去環境設置尋找 python 目錄,推薦這種寫法

--4-----------Python 標準數據類型 及 轉換----------------------------------------------------------------------------------------------------------------------------

在內存中存儲的數據可以有多種類型。

變量存儲在內存中的值。這就意味着在創建變量時會在內存中開闢一個空間。

基於變量的數據類型,解釋器會分配指定內存,並決定什麼數據可以被存儲在內存中。

因此,變量可以指定不同的數據類型,這些變量可以存儲整數,小數或字符。

Python 定義了5個標準類型,用於存儲各種類型的數據。

有2種:  數字型  非數字型

(1) 數字型     包括 1. 符號整型 int

                    2. 長整型   long     (也可以代表8進制和16進制)      Python的長整型,使用 L 來顯示,也可以使用小寫 l,但建議使用大寫 L,避免與數字 1 混淆

                    3. 浮點型   float

                    4. 複數類型 complex  (複數由實數部分和虛數部分構成,虛數部分以j或J標識) 可以用 a + bj,或者 complex(a,b) 表示, 複數的實部 a 和虛部 b 都是浮點型。

(2) 非數字型   包括 1. 字符串       表示方式:  str="hello,world"

                    2. 列表         表示方式:  list=['hello',2,3,4,'world']

                    3. 元組         表示方式:  tuple=('hello',2,3,4,'world')        相當於只讀列表,不可以二次賦值

                    4. 字典         key值對


非數字型的共同點:  都可以使用切片、鏈接(+)、重複(*)、取值(a[])等相關運算;

非數字型的不同點:  列表 可以直接賦值,元組不可以賦值,字典按照 dict[k]=v 的方式賦值。

截取方式相同:  名稱[頭下標:尾下標]

下標是從0開始算起,可以是正數或者負數,下標爲空則表示取到頭或者尾

開始截取時,包含了下邊界,而截取到最大範圍不包括上邊界。

元組不能二次賦值,列表可以

--變量賦值--Python 中的變量賦值不需要類型聲明。

每個變量在內存中創建,都包括變量的標識,名稱和數據這些信息。

每個變量在使用前都必須賦值,變量賦值以後該變量纔會被創建。

等號= 用來給變量賦值。

等號= 運算符左邊是一個變量名,等號(=)運算符右邊是存儲在變量中的值。例如:

#!/usr/bin/python

# -*- coding: UTF-8 -*-

counter = 100 # 賦值整型變量

miles = 1000.0 # 浮點型

name = "John" # 字符串

print counter

print miles

print name

以上實例中,100,1000.0和"John"分別賦值給counter,miles,name變量。

執行以上程序會輸出如下結果:

100

1000.0

John

--多個變量賦值--Python允許同時爲多個變量賦值

a = b = c = 1

以上實例,創建一個整型對象,值爲1,三個變量被分配到相同的內存空間上。

您也可以爲多個對象指定多個變量。例如:

a, b, c = 1, 2, "john"

以上實例,兩個整型對象1和2的分配給變量 a 和 b,字符串對象 "john" 分配給變量 c。

--Python數字類型--用於存儲數值

他們是不可改變的數據類型,這意味着改變數字數據類型會分配一個新的對象。

當你指定一個值時,Number對象就會被創建:

var1 = 1

var2 = 10

您也可以使用del語句刪除一些對象的引用。

del語句的語法是:

del var1[,var2[,var3[....,varN]]]]

您可以通過使用del語句刪除單個或多個對象的引用。

del var

del var_a, var_b

--Python字符串--接收單引號' 雙引號" 三引號(''' """) 來表示字符串,引號的開始與結束必須的相同類型的。

其中三引號可以由多行組成,編寫多行文本的快捷語法,常用語文檔字符串,在文件的特定地點,被當做註釋。

包含了多個語句"""

字符串或串(String)是由數字、字母、下劃線組成的一串字符。

一般記爲 :

s="a1a2···an"(n>=0)

它是編程語言中表示文本的數據類型。

python的字串列表有2種取值順序:

從左到右索引默認0開始的,最大範圍是字符串長度少1

從右到左索引默認-1開始的,最大範圍是字符串開頭

如果你要實現從字符串中獲取一段子字符串的話,可以使用變量 [頭下標:尾下標],就可以截取相應的字符串,其中下標是從 0 開始算起,可以是正數或負數,下標可以爲空表示取到頭或尾。

當使用以冒號分隔的字符串,python返回一個新的對象,結果包含了以這對偏移標識的連續的內容,左邊的開始是包含了下邊界。

上面的結果包含了s[1]的值l,而取到的最大範圍不包括上邊界,就是s[5]的值p。

#!/usr/bin/python

# -*- coding: UTF-8 -*-

word = 'word'

sentence = "這是一個句子。"

paragraph = """這是一個段落。

s = 'ilovepython'

print s[1:5]        # 結果是love

str = 'Hello World!'

print str           # 輸出完整字符串                         Hello World!

print str[0]        # 輸出字符串中的第1個字符                H

print str[2:5]      # 輸出字符串中第3個至第5個之間的字符串   llo

print str[2:]       # 輸出從第3個字符開始的字符串            llo World!

print str * 2       # 輸出字符串2次                          Hello World!Hello World!         星號(*)是重複操作

print str + "TEST"  # 輸出連接的字符串                       Hello World!TEST                 加號(+)是字符串連接運算符

dict(),dict(list) 轉換成一個dictionary

max(...) 求最大值

min(...) 求最小值

int(x [,base])     轉換成一個integer           將x轉換爲一個整數

long(x [,base] )   轉換成一個long interger     將x轉換爲一個長整數

float(x)           轉換成一個浮點數            將x轉換到一個浮點數

complex(real [,imag])    轉換成複數            創建一個複數

str(x)          得到obj的字符串描述     將對象 x 轉換爲字符串

repr(x)         將對象 x 轉換爲表達式字符串

eval(str)       用來計算在字符串中的有效Python表達式,並返回一個對象

tuple(seq)        把一個sequence轉換成一個tuple 將序列 s 轉換爲一個元組

list(seq)         把一個sequence轉換成一個list     將序列 s 轉換爲一個列表

set(s)          轉換爲可變集合

dict(d)         創建一個字典。d 必須是一個序列 (key,value)元組。

frozenset(s)    轉換爲不可變集合

chr(x)          把一個ASCII數值,變成字符    將一個整數轉換爲一個字符

unichr(x)       將一個整數轉換爲Unicode字符

ord(x)          把一個字符或者unicode字符,變成ASCII數值   將一個字符轉換爲它的整數值

hex(x)          把整數x變成十六進制表示的字符串    將一個整數轉換爲一個十六進制字符串

oct(x)          把整數x變成八進制表示的字符串    將一個整數轉換爲一個八進制字符串

--查看變量的數據類型--python 的所有數據類型都是類,可以通過 type() 查看該變量的數據類型

>>> n=1

>>> type(n)      <type 'int'>

>>> n="runoob"

>>> type(n)      <type 'str'>

--查看變量的數據類型--還可以用 isinstance 來判斷

a = 111

isinstance(a, int)      輸出 True

--isinstance 和 type 的區別在於

>>> class A:

...     pass

...

>>> class B(A):

...     pass

...

>>> isinstance(A(), A)

True

>>> type(A()) == A

False

>>> isinstance(B(), A)

True

>>> type(B()) == A

False

區別就是:

 type()不會認爲子類是一種父類類型。

 isinstance()會認爲子類是一種父類類型。

--5-----------Python 運算符----------------------------------------------------------------------------------------------------------------------------

--比較運算符

== 等於           != 不等於         <> 不等於

> 大於           < 小於

>= 大於等於       <= 小於等於

--位運算符

& 按位與運算符:  參與運算的兩個值,如果兩個相應位都爲1,則該位的結果爲1,否則爲0 (a & b) 輸出結果 12 ,二進制解釋:   0000 1100

| 按位或運算符:  只要對應的二個二進位有一個爲1時,結果位就爲1。 (a | b) 輸出結果 61 ,二進制解釋:   0011 1101

^ 按位異或運算符:  當兩對應的二進位相異時,結果爲1 (a ^ b) 輸出結果 49 ,二進制解釋:   0011 0001

~ 按位取反運算符:  對數據的每個二進制位取反,即把1變爲0,把0變爲1 (~a ) 輸出結果 -61 ,二進制解釋:   1100 0011, 在一個有符號二進制數的補碼形式。

<< 左移動運算符:  運算數的各二進位全部左移若干位,由"<<"右邊的數指定移動的位數,高位丟棄,低位補0。 a << 2 輸出結果 240 ,二進制解釋:   1111 0000

>> 右移動運算符:  把">>"左邊的運算數的各二進位全部右移若干位,">>"右邊的數指定移動的位數 a >> 2 輸出結果 15 ,二進制解釋:   0000 1111

--邏輯運算符

and x and y   布爾"與" - 如果 x 爲 False,x and y 返回 False,否則它返回 y 的計算值。 (a and b) 返回 20。

 or x  or y   布爾"或" - 如果 x 是 True,它返回 True,否則它返回 y 的計算值。 (a or b) 返回 10。

not x         布爾"非" - 如果 x 爲 True,返回 False 。如果 x 爲 False,它返回 True。 not(a and b) 返回 False

--成員運算符

in 如果在指定的序列中找到值返回 True,否則返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。

not in 如果在指定的序列中沒有找到值返回 True,否則返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

--賦值運算符

變量賦值,簡單粗暴不需要聲明類型, 靈活多變,非常好用。

數字數據類是不可改變的數據類型,改變數字數據類型會分配一個新的對象。

字符串的操作有基本的功能不需要再自己進行拼接遍歷的操作。

  對於字符串來說,最常用的有+和*兩種運算,+表示把兩個字符串進行連接,*表示連乘。比如:

  注意:  一個字符串*0結果是空字符串,一個字符串*一個負數也是空字符串。

=   簡單的賦值運算符    例 c = a + b   將 a + b 的運算結果賦值爲 c

+=  加法賦值運算符      例 c += a 等效於 c = c + a

-=  減法賦值運算符      例 c -= a 等效於 c = c - a

*=  乘法賦值運算符      例 c *= a 等效於 c = c * a

/=  除法賦值運算符      例 c /= a 等效於 c = c / a

%=  取模賦值運算符      例 c %= a 等效於 c = c % a

**= 冪賦值運算符        例 c **= a 等效於 c = c ** a

//= 取整除賦值運算符    例 c //= a 等效於 c = c // a

a = 1         # 變量賦值

b = "god"

str = 'this is string 1'                        # 字符串賦值

list = ['this', 'is', 'list', 2]                # 列表串賦值   用 "[ ]" 標識類似 C 語言中的數組。

tuple = ('this', 'is', 'tuple', 3)              # 元組賦值     用 "( )" 標識。內部元素用逗號隔開。但是元組不能二次賦值,相當於只讀列表。

dict = {1:'this', 2:'is', 3:'dictionary', 4:4}  # 字典賦值     用 "{ }" 標識。字典由索引 key 和它對應的值 value 組成。

--算術運算符

+ 加           兩個對象相加 a + b 輸出結果 30

- 減 或 取反   得到負數或是一個數減去另一個數 a - b 輸出結果 -10

* 乘           兩個數相乘或是返回一個被重複若干次的字符串 a * b 輸出結果 200

/ 整除         整除運算最終值取的是中間值的floor值     x除以y b / a 輸出結果 2

% 取模/取餘    返回除法的餘數 b % a 輸出結果 0

** 冪/乘方      返回x的y次冪 a**b 爲10的20次方, 輸出結果 100000000000000000000

// 取整除       返回商的整數部分 9//2 輸出結果 4 , 9.0//2.0 輸出結果 4.0

--優先級 和運算符

** 指數 (最高優先級)

~ + - 按位翻轉, 一元加號和減號 (最後兩個的方法名爲 +@ 和 -@)

* / % // 乘,除,取模和取整除

+ - 加法減法

>> << 右移,左移運算符

& 位 'AND'

^ | 位運算符

<= < > >= 比較運算符

<> == != 等於運算符

= %= /= //= -= += *= **= 賦值運算符

is is not 身份運算符

in not in 成員運算符

not or and 邏輯運算符




--1.1-------------import------import shelve 模塊--------shelve也是python提供給我們的序列化工具,比pickle用起來更簡單一些。------------------------------------------------------

import shelve

f = shelve.open('shelve_file')            # shelve只提供給一個open方法,是用key來訪問的,使用起來和字典類似。

f['key'] = {'int':10, 'float':9.5, 'string':'Sample data'} #直接對文件句柄操作,就可以存入數據

f.close()

import shelve

f1 = shelve.open('shelve_file')

existing = f1['key'] #取出數據的時候也只需要直接用key獲取即可,但是如果key不存在會報錯

f1.close()

print(existing)    # 這個模塊有個限制,它不支持多個應用同一時間往同一個DB進行寫操作。所以當我們知道我們的應用如果只進行讀操作,我們可以讓shelve通過只讀方式打開DB

import shelve

f = shelve.open('shelve_file', flag='r')

existing = f['key']

f.close()

print(existing)    # 由於shelve在默認情況下是不會記錄待持久化對象的任何修改的,所以我們在shelve.open()時候需要修改默認參數,否則對象的修改不會保存。

import shelve

f1 = shelve.open('shelve_file')

print(f1['key'])

f1['key']['new_value'] = 'this was not here before'

f1.close()

f2 = shelve.open('shelve_file', writeback=True)

print(f2['key'])

f2['key']['new_value'] = 'this was not here before'

f2.close()

"""

writeback方式有優點也有缺點。優點是減少了我們出錯的概率,並且讓對象的持久化對用戶更加的透明瞭;

但這種方式並不是所有的情況下都需要,

首先,使用writeback以後,shelf在open()的時候會增加額外的內存消耗,並且當DB在close()的時候會將緩存中的每一個對象都寫入到DB,這也會帶來額外的等待時間。

因爲shelve沒有辦法知道緩存中哪些對象修改了,哪些對象沒有修改,因此所有的對象都會被寫入。

"""

--1.2-------------import------import pickle 模塊-------------提供了4個功能:   dumps、dump、loads、load------用於python特有的類型 和 python的數據類型間進行轉換-----------------------

import pickle

dic = {'k1':'v1','k2':'v2','k3':'v3'}

str_dic = pickle.dumps(dic)               # 功能1-dumps

print(str_dic) #一串二進制內容

dic2 = pickle.loads(str_dic)              # 功能3-loads-反序列化,讀

print(dic2) #字典

import time

struct_time = time.localtime(1000000000)

print(struct_time)

f = open('pickle_file','wb')

pickle.dump(struct_time,f)                # 功能2-dump-序列化,存

f.close()

f = open('pickle_file','rb')

struct_time2 = pickle.load(f)             # 功能4-load-不僅可以序列化字典,列表...可以把python中任意的數據類型序列化

print(struct_time2.tm_year)


--12.4-------------import------import logging 模塊-------------xx-----------------------------------------------------------------

--python中使用sys模板和logging模塊獲取行號和函數名的方法

對於python,這幾天一直有兩個問題在困擾我:

1.python中沒辦法直接取得當前的行號和函數名。這是有人在論壇裏提出的問題,底下一羣人只是在猜測python爲什麼不像__file__一樣提供__line__和__func__,但是卻最終也沒有找到解決方案。

2.如果一個函數在不知道自己名字的情況下,怎麼才能遞歸調用自己。這是我一個同事問我的,其實也是獲取函數名,但是當時也是回答不出來。

但是今晚!所有的問題都有了答案。

一切還要從我用python的logging模塊說起,logging中的format中是有如下選項的:

%(name)s            Name of the logger (logging channel)

%(levelno)s         Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL)

%(levelname)s       Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL")

%(pathname)s        Full pathname of the source file where the logging call was issued (if available)

%(filename)s        Filename portion of pathname

%(module)s          Module (name portion of filename)

%(lineno)d          Source line number where the logging call was issued (if available)

%(funcName)s        Function name

%(created)f         Time when the LogRecord was created (time.time() return value)

%(asctime)s         Textual time when the LogRecord was created

%(msecs)d           Millisecond portion of the creation time

%(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded (typically at application startup time)

%(thread)d          Thread ID (if available)

%(threadName)s      Thread name (if available)

%(process)d         Process ID (if available)

%(message)s         The result of record.getMessage(), computed just as the record is emitted

也就是說,logging是能夠獲取到調用者的行號和函數名的,那會不會也可以獲取到自己的行號和函數名呢?

我們來看一下源碼,主要部分如下:

def currentframe():

    """Return the frame object for the caller's stack frame."""

    try:

        raise Exception

    except:

        return sys.exc_info()[2].tb_frame.f_back

def findCaller(self):

    """

    Find the stack frame of the caller so that we can note the source

    file name, line number and function name.

    """

    f = currentframe()

    #On some versions of IronPython, currentframe() returns None if

    #IronPython isn't run with -X:Frames.

    if f is not None:

        f = f.f_back

    rv = "(unknown file)", 0, "(unknown function)"

    while hasattr(f, "f_code"):

        co = f.f_code

        filename = os.path.normcase(co.co_filename)

        if filename == _srcfile:

            f = f.f_back

            continue

        rv = (co.co_filename, f.f_lineno, co.co_name)

        break

    return rv

def _log(self, level, msg, args, exc_info=None, extra=None):

    """

    Low-level logging routine which creates a LogRecord and then calls

    all the handlers of this logger to handle the record.

    """

    if _srcfile:

        #IronPython doesn't track Python frames, so findCaller throws an

        #exception on some versions of IronPython. We trap it here so that

        #IronPython can use logging.

        try:

            fn, lno, func = self.findCaller()

        except ValueError:

            fn, lno, func = "(unknown file)", 0, "(unknown function)"

    else:

        fn, lno, func = "(unknown file)", 0, "(unknown function)"

    if exc_info:

        if not isinstance(exc_info, tuple):

            exc_info = sys.exc_info()

    record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra)

    self.handle(record)

我簡單解釋一下,實際上是通過在currentframe函數中拋出一個異常,然後通過向上查找的方式,找到調用的信息。其中

rv = (co.co_filename, f.f_lineno, co.co_name)

的三個值分別爲文件名,行號,函數名。(可以去http://docs.python.org/library/sys.html來看一下代碼中幾個系統函數的說明)

OK,如果已經看懂了源碼,那獲取當前位置的行號和函數名相信也非常清楚了,代碼如下:

#!/usr/bin/python

# -*- coding: utf-8 -*-

'''

#=============================================================================

#  FileName:        xf.py

#  Description:     獲取當前位置的行號和函數名

#  Version:         1.0

#=============================================================================

'''

import sys

def get_cur_info():

    """Return the frame object for the caller's stack frame."""

    try:

        raise Exception

    except:

        f = sys.exc_info()[2].tb_frame.f_back

    return (f.f_code.co_name, f.f_lineno)

def callfunc():

    print get_cur_info()

if __name__ == '__main__':

    callfunc()

輸入結果是:

('callfunc', 24)

符合預期~~

哈哈,OK!現在應該不用再抱怨取不到行號和函數名了吧~

=============================================================================

後來發現,其實也可以有更簡單的方法,如下:

import sys

def get_cur_info():

    print sys._getframe().f_code.co_name

    print sys._getframe().f_back.f_code.co_name

get_cur_info()

調用結果是:

get_cur_info

<module>

--1.1-------------import------import copy 模塊      提供了對複合對象進行淺拷貝和深拷貝的功能。(list,tuple,dict,custom class)

功能: 用於對象的拷貝操作。      複製操作只對複合對象有效。

方法: 該模塊非常簡單,只提供了2個主要的方法:

copy.copy        表示淺複製    拷貝後,對象的引用沒有發生變化,而對象的行爲發生變化,會反映到拷貝後的對象身上     只複製對象本身,沒有複製該對象所引用的對象。

copy.deepcopy    表示深複製    拷貝後,對象的引用發生了變化,即對象不同,所以,即使對象再怎麼變,也不會對其他對象產生影響

#coding=gbk

import copy

l1 = [1,2,[3,4]]

l2 = copy.copy(l1)

print l1    輸出結果 [1,2,[3,4]]

print l2    輸出結果 [1,2,[3,4]]

l2[2][0]=50

print l1    輸出結果 [1,2,[50,4]]

print l2    輸出結果 [1,2,[50,4]]

l3 = [1,2,[3,4]]

l4 = copy.deepcopy(l1)

print l3    輸出結果 [1,2,[3,4]]

print l4    輸出結果 [1,2,[50, 4]]

l4[2][0]=50

print l3    輸出結果 [1,2,[3,4]]

print l4    輸出結果 [1,2,[50,4]]

改變copy的默認行爲

在定義類時,通過定義__copy__和__deepcopy__方法,可以改變copy的默認行爲。

class CopyObj(object):

    def __repr__(self):

        return "CopyObj"

    def __copy__(self):

        return "Hello"

obj = CopyObj()

obj1= copy.copy(obj)

print obj     輸出結果 CopyObj

print obj1    輸出結果 Hello

舉例  https://www.cnblogs.com/hongten/p/hongten_python_copy.html

http://blog.csdn.net/xmnathan/article/details/36217631

--########################################################################################################################

--1.1-------------import------import paramiko 模塊---

最近在寫Python腳本的時候,需要一個功能就是使用ssh登錄Linux主機A,然後在主機A上執行scp命令將主機上的文件自動給拷貝到Linux主機B上。遠程登錄使用pycrypto和paramiko模塊實現了,但是在執行scp命令的時候需要輸入密碼沒有搞定,最後換了個角度思考,可不可以不輸入密碼就實現scp拷貝,到網上一搜就解決了。解決步驟如下(以從A主機向B主機拷貝文件爲例):

在A主機上以root用戶登錄,執行命令:  ssh-keygen -b 1024 -t rsa,之後連續三次回車即可

在A主機上進入/root/.ssh目錄就會發現幾個新生成的文件,其中一個是id_rsa.pub

在A主機上scp /root/.ssh/id_rsa.pub root@B:/root/.ssh/authorized_keys

會發現在這次拷貝的時候需要輸入密碼。

但是之後如果需要將A主機文件使用scp拷貝到B主機上的時候就可以不輸入密碼直接執行了

至此,信任關係配置完畢

參照:  http://eric-gcm.iteye.com/blog/912071

http://blog.csdn.net/doublefalse/article/details/1955922

之後就可以使用paramiko模塊,首先以root用戶身份登錄到A主機上,然後使用exec_command方法執行scp命令即可

#!/usr/bin/env python

import paramiko

import os

hostname  = '192.168.56.101'

port      = 22

username  = 'root'

password  = '111111'

dir_path  = '/root/perl'

if __name__ == "__main__":

    t = paramiko.Transport((hostname, port))

    t.connect(username=username, password=password)

    sftp = paramiko.SFTPClient.from_transport(t)

    files = sftp.listdir(dir_path)

    for f  in files:

        print 'Retrieving', f

        sftp.get(os.path.join(dir_path, f), f)

    t.close()

--########################################################################################################################

--1.1-------------import------import shutil 模塊      提供大量的文件的高級操作。特別針對文件拷貝,刪除,改名。 目錄和文件操作以及壓縮操作。對單個文件的操作也可參見os模塊。

                                                      shutil操作只針對一般的文件,不支持pipes,block devices等文件類型。

--########################################################################################################################

--shutil.copy(src, dst)    實現文件複製功能,將src文件複製到dst文件夾中

參數:   2個都是字符串格式。如果dst是一個文件名稱,那麼它等同於複製 + 重命名。

返回值: 複製成功後的字符串格式的文件路徑

import shutil

import os

os.chdir('D:\\PythonStudy\\pyfiles\\')

shutil.copy('D:\\PythonStudy\\pyfiles\\Hello_apple.py', 'D:\\PythonStudy\\target\\')

--shutil.copy2( src, dst)  在copy基礎上,再複製文件最後訪問時間與修改時間也複製過來了,類似於cp –p的東西

                           如果兩個位置的文件系統是一樣的話相當於是rename操作,只是改名;

                           如果是不在相同的文件系統的話就是做move操作

--shutil.copyfile(src, dst) 將源的內容複製給目標,如果當前的dst已存在的話就會被覆蓋掉

                            前提是目標地址是具備可寫權限。如果沒有權限寫目標文件則產生IoError,IOException.

                            實際是使用了底層函數copyfileobj()

--shutil.copymode(src, dst) 複製文件元數據

                            只是會複製其權限,其他的東西是不會被複制的(在UNIX創建一個新文件,會根據當前用戶的umask接受權限。要把權限從一個文件複製到另一個文件)

--shutil.copystat(src, dst) 複製權限、最後訪問時間、最後修改時間(要複製其他元數據)

--shutil.copytree(olddir, newdir, True/Flase)  把olddir拷貝一份newdir,

                            如果第3個參數是True,則複製目錄時將保持文件夾下的符號連接,

                            如果第3個參數是False,則將在複製的目錄下生成物理副本來替代符號連接

shutil.move( src, dst)  移動文件或重命名

shutil.rmtree( src ) 遞歸刪除一個目錄以及目錄內的所有內容

shutil包含三個函數處理目錄樹。要把一個目錄從一個位置複製到另一個位置,使用copytree()。這會遞歸遍歷源目錄樹,將文件複製到目標。

copytree()可以將當前這個實現當作起點,在使用前要讓它更健壯,可以增加一些特性,如進度條。

from shutil import *

from commands import *

print 'BEFORE:'

print getoutput('ls -rlast /tmp/example')

copytree('../shutil', '/tmp/example')

print '\nAFTER:'

print getoutput('ls -rlast /tmp/example')

symlinks 參數控制着符號鏈接作爲鏈接複製還是文件複製。默認將內容複製到新文件,如果選項爲true,會在目標中創建新的符號鏈接。

要刪除一個目錄及其內容,可以使用rmtree()。

from shutil import *

from commands import *

print 'BEFORE:'

print getoutput('ls -rlast /tmp/example')

rmtree('/tmp/example')

print '\nAFTER:'

print getoutput('ls -rlast /tmp/example')

將一個文件或目錄從一個位置移動到另一個位置,可以使用move()。

from shutil import *

from glob import glob

with open('example.txt', 'wt') as f:

  f.write('i love you')

print 'BEFORE: ', glob('example*')

move('example.txt', 'example.out')

print 'AFTER: ',glob('example*')

其語義與UNIX命令mv類似。如果源與目標都在同一個文件系統內,則會重命名源文件。否則,源文件會複製到目標文件,將源文件刪除。

>>> ================================ RESTART ================================

>>>

BEFORE: ['example', 'example.txt']

AFTER: ['example', 'example.out']

from shutil import *

import os

from commands import *

with open('file_to_change.txt', 'wt') as f:

  f.write('i love you')

os.chmod('file_to_change.txt', 0444)

print 'BEFORE:'

print getstatus('file_to_change.txt')

copymode('shutil_copymode.py', 'file_to_change.txt')

print 'AFTER:'

print getstatus('file_to_change.txt')

from shutil import *

import os

import time

def show_file_info(filename):

  stat_info = os.stat(filename)

  print '\tMode    :', stat_info.st_mode

  print '\tCreated  :', time.ctime(stat_info.st_ctime)

  print '\tAccessed  :', time.ctime(stat_info.st_atime)

  print '\tModified  :', time.ctime(stat_info.st_mtime)

with open('file_to_change.txt', 'wt') as f:

  f.write('i love you')

os.chmod('file_to_Change.txt', 0444)

print 'BEFORE:'

show_file_info('file_to_Change.txt')

copystat('shutil_copystat.py', 'file_to_Change.txt')

print 'AFTER:'

show_file_info('file_to_Change.txt')

使用copystat()只會複製與文件關聯的權限和日期。

from shutil import *

from glob import glob

print 'BEFORE:', glob('huanhuan.*')

copyfile('huanhuan.txt', 'huanhuan.txt.copy')

print 'AFTER:', glob('huanhuan.*')

這個函數會打開輸入文件進行讀寫,而不論其類型,所以某些特殊文件不可以用copyfile()複製爲新的特殊文件。

參數是文件名,copyfileobj()的參數是打開的文件句柄。第三個參數可選,用於讀入塊的緩衝區長度。

默認行爲是使用大數據塊讀取。使用-1會一次性讀取所有輸入,或者使用其他正數可以設置特定塊的大小。

類似於UNIX命令行工具cp,copy()函數會用同樣的方式解釋輸出名。如果指定的目標指示一個目錄而不是一個文件,會使用源文件的基名在該目錄中創建一個新文件。

from shutil import *

import os

import time

dir = os.getcwd()

if not os.path.exists('%s\\example' % dir):

  os.mkdir('%s\\example' % dir)

def show_file_info(filename):

  stat_info = os.stat(filename)

  print '\tMode  :', stat_info.st_mode

  print '\tCreated :', time.ctime(stat_info.st_ctime)

  print '\tAccessed:', time.ctime(stat_info.st_atime)

  print '\tModified:', time.ctime(stat_info.st_mtime)

print 'SOURCE:'

show_file_info('huanhuan.txt')

copy2('huanhuan.txt', 'example')

print 'DEST:'

show_file_info('%s\\example\\huanhuan.txt' % dir)

--python實現拷貝指定文件到指定目錄               python實現這個功能非常簡單,因爲庫太強大了

import os

import shutil

alllist=os.listdir(u"D:\\notes\\python\\docx\\")

for i in alllist:

    aa,bb=i.split(".")

    if 'python' in aa.lower():

        oldname=u"D:\\notes\\python\\docx\\"+aa+"."+bb

        newname=u"d:\\copy\\newname"+aa+"."+bb

        shutil.copyfile(oldname,newname)

用python實現了一個小型的自動發版本的工具。這個“自動發版本”有點虛, 只是簡單地把debug 目錄下的配置文件複製到指定目錄,把Release下的生成文件複製到同一指定,過濾掉不需要的文件夾(.svn),然後再往這個指定目錄添加幾個特定的文件。

首先插入必要的庫:

import os

import os.path

import shutil

import time,  datetime

然後就是一大堆功能函數。第一個就是把某一目錄下的所有文件複製到指定目錄中:

def copyFiles(sourceDir,  targetDir):

    if sourceDir.find(".svn") > 0:

        return

    for file in os.listdir(sourceDir):

        sourceFile = os.path.join(sourceDir,  file)

        targetFile = os.path.join(targetDir,  file)

        if os.path.isfile(sourceFile):

            if not os.path.exists(targetDir):

                os.makedirs(targetDir)

            if not os.path.exists(targetFile) or(os.path.exists(targetFile) and (os.path.getsize(targetFile) != os.path.getsize(sourceFile))):

                    open(targetFile, "wb").write(open(sourceFile, "rb").read())

        if os.path.isdir(sourceFile):

            First_Directory = False

            copyFiles(sourceFile, targetFile)

--刪除一級目錄下的所有文件

def removeFileInFirstDir(targetDir):

    for file in os.listdir(targetDir):

        targetFile = os.path.join(targetDir,  file)

        if os.path.isfile(targetFile):

            os.remove(targetFile)

複製一級目錄下的所有文件到指定目錄:

def coverFiles(sourceDir,  targetDir):

        for file in os.listdir(sourceDir):

            sourceFile = os.path.join(sourceDir,  file)

            targetFile = os.path.join(targetDir,  file)

            #cover the files

            if os.path.isfile(sourceFile):

                open(targetFile, "wb").write(open(sourceFile, "rb").read())

--複製指定文件到目錄

def moveFileto(sourceDir,  targetDir):

    shutil.copy(sourceDir,  targetDir)

--往指定目錄寫文本文件

def writeVersionInfo(targetDir):

    open(targetDir, "wb").write("Revison:")

--返回當前的日期,以便在創建指定目錄的時候用:

def getCurTime():

    nowTime = time.localtime()

    year = str(nowTime.tm_year)

    month = str(nowTime.tm_mon)

    if len(month) < 2:

        month = '0' + month

    day =  str(nowTime.tm_yday)

    if len(day) < 2:

        day = '0' + day

    return (year + '-' + month + '-' + day)

--然後就是主函數的實現了:

if  __name__ =="__main__":

    print "Start(S) or Quilt(Q) \n"

    flag = True

    while (flag):

        answer = raw_input()

        if  'Q' == answer:

            flag = False

        elif 'S'== answer :

            formatTime = getCurTime()

            targetFoldername = "Build " + formatTime + "-01"

            Target_File_Path += targetFoldername

            copyFiles(Debug_File_Path,   Target_File_Path)

            removeFileInFirstDir(Target_File_Path)

            coverFiles(Release_File_Path,  Target_File_Path)

            moveFileto(Firebird_File_Path,  Target_File_Path)

            moveFileto(AssistantGui_File_Path,  Target_File_Path)

            writeVersionInfo(Target_File_Path+"\\ReadMe.txt")

            print "all sucess"

        else:

            print "not the correct command"          感覺是果然簡單, 不過簡單的原因是因爲庫函數豐富,語言基本特性的簡單真沒感覺出來。

--12.4-------------import------import filecmp 模塊---比較目錄的不同

--12.4-------------import------import difflib 模塊---提供的類和方法用來進行序列的差異化比較,它能夠比對文件並生成差異結果文本或者html格式的差異化比較頁面

class difflib.SequenceMatcher    此類提供了比較任意可哈希類型序列對方法。此方法將尋找沒有包含‘垃圾'元素的最大連續匹配序列。

                                 通過對算法的複雜度比較,它由於原始的完形匹配算法,在最壞情況下有n的平方次運算,在最好情況下,具有線性的效率。

                                 它具有自動垃圾啓發式,可以將重複超過片段1%或者重複200次的字符作爲垃圾來處理。可以通過將autojunk設置爲false關閉該功能。

class difflib.Differ             此類比較的是文本行的差異並且產生適合人類閱讀的差異結果或者增量結果,結果中各部分的表示如下:

class difflib.HtmlDiff           此類可以被用來創建HTML表格 (或者說包含表格的html文件) ,兩邊對應展示或者行對行的展示比對差異結果。

make_file(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])    用來生成包含一個內容爲比對結果的表格的html文件,並且部分內容會高亮顯示

make_table(fromlines, tolines [, fromdesc][, todesc][, context][, numlines])   用來生成包含一個內容爲比對結果的表格的html文件,並且部分內容會高亮顯示

--difflib.context_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])    比較a與b(字符串列表),並且返回一個差異文本行的生成器  

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']

>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']

>>> for line in context_diff(s1, s2, fromfile='before.py', tofile='after.py'):

...   sys.stdout.write(line)

--difflib.get_close_matches(word, possibilities[, n][, cutoff])     返回最大匹配結果的列表

>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])         ['apple', 'ape']

>>> import keyword

>>> get_close_matches('wheel', keyword.kwlist)       ['while']

>>> get_close_matches('apple', keyword.kwlist)       []

>>> get_close_matches('accept', keyword.kwlist)      ['except']

--difflib.ndiff(a, b[, linejunk][, charjunk])     比較a與b(字符串列表),返回一個Differ-style 的差異結果

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1), 'ore\ntree\nemu\n'.splitlines(1))

>>> print ''.join(diff),

--difflib.restore(sequence, which)      返回一個由兩個比對序列產生的結果

>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1),  'ore\ntree\nemu\n'.splitlines(1))

>>> diff = list(diff) # materialize the generated delta into a list

>>> print ''.join(restore(diff, 1)),

>>> print ''.join(restore(diff, 2)),

--difflib.unified_diff(a, b[, fromfile][, tofile][, fromfiledate][, tofiledate][, n][, lineterm])   比較a與b(字符串列表),返回一個unified diff格式的差異結果.

>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']

>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']

>>> for line in unified_diff(s1, s2, fromfile='before.py', tofile='after.py'):

實際應用示例

比對兩個文件,然後生成一個展示差異結果的HTML文件

#coding:utf-8

'''

file:difflibeg.py

date:2017/9/9 10:33

author:lockey

email:[email protected]

desc:diffle module learning and practising

'''

import difflib

hd = difflib.HtmlDiff()

loads = ''

with open('G:/python/note/day09/0907code/hostinfo/cpu.py','r') as load:

 loads = load.readlines()

 load.close()

mems = ''

with open('G:/python/note/day09/0907code/hostinfo/mem.py', 'r') as mem:

 mems = mem.readlines()

 mem.close()

with open('htmlout.html','a+') as fo:

 fo.write(hd.make_file(loads,mems))

 fo.close()

運行結果:

這裏寫圖片描述

生成的html文件比對結果:

這裏寫圖片描述

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。


--37-----------Python 100例----------------------------------------------------------------------------------------------------------------------------

一.變量、表達式和語句

  Python中的語句也稱作命令,比如print "hello python"這就是一條語句。

  表達式,顧名思義,是指用運算符將運算對象連接起來的式子,在Python中表達式是語句的一種(注意在C語言和Java中表達式是表達式,語句是語句,表達式不可能是語句)。舉個例子,在Python中,"3+2"這是一個表達式,同時也是一條語句,但是在C和java中完全是兩個不同的概念。

  變量,用來存儲可變的值,同其他的解釋型編程語言一樣,在Python中使用變量不需要預先定義,也不需要定義其類型,只需要在使用時進行定義和初始化即可。比如:

i=3

print i

  另外,在Python中,同一變量名在不同階段可以存儲不同類型的數據(至於其中的緣由在以後會慢慢作解釋)。比如:

i=3

print i

i='hello python'

print i

i=2.3

print i

  Python中的變量的命名規則同C語言中的變量命名規則基本一樣。不過在Python中以下劃線開始或者結束的變量名通常有特殊的意義,比如__name__這個是每個模塊保留的內置屬性。

##簡單例子,推python運行原理,包含了兩個文件 foo.py 和 demo.py

[foo.py]

def add(a, b):

return a + b

[demo.py] import foo

a = [1, 'python'] a = 'a string'

def func():

a = 1 b = 257

print(a + b)

print(a) if __name__ == '__main__': func() foo.add(1, 2)

執行這個程序

python demo.py

輸出結果

a string 258

同時,該文件目錄多出一個 foo.pyc 文件

## 命名空間 (namespace)

在介紹上面的這些代碼時,還漏掉了一個關鍵的信息就是命名空間。在 Python 中,類、函數、module 都對應着一個獨立的命名空間。而一個獨立的命名空間會對應一個 PyCodeObject 對象,所以上面的 demo.py 文件編譯後會生成兩個 PyCodeObject,只是在 demo.py 這個 module 層的 PyCodeObject 中通過一個變量符號 func 嵌套了一個函數的 PyCodeObject。

命名空間的意義,就是用來確定一個變量符號到底對應什麼對象。命名空間可以一個套一個地形成一條命名空間鏈,Python 虛擬機在執行的過程中,會有很大一部分時間消耗在從這條命名空間鏈中確定一個符號所對應的對象是什麼。

在 Python中,命名空間是由一個 dict 對象實現的,它維護了(name,obj)這樣的關聯關係。

說到這裏,再補充一下 import foo 這行代碼會在 demo.py 這個模塊的命名空間中,創建一個新的變量名 foo,foo 將綁定到一個 PyCodeObject 對象,也就是 foo.py 的編譯結果。

--LEGB 規則

Python 使用 LEGB 的順序來查找一個符號對應的對象

locals -> enclosing function -> globals -> builtins

locals,當前所在命名空間(如函數、模塊),函數的參數也屬於命名空間內的變量

enclosing,外部嵌套函數的命名空間(閉包中常見)

def fun1(a): def fun2(): # a 位於外部嵌套函數的命名空間 print(a)

globals,全局變量,函數定義所在模塊的命名空間

a = 1 def fun(): # 需要通過 global 指令來聲明全局變量 global a # 修改全局變量,而不是創建一個新的 local 變量 a = 2

builtins,內置模塊的命名空間。Python 在啓動的時候會自動爲我們載入很多內置的函數、類,比如 dict,list,type,print,這些都位於 __builtins__ 模塊中,可以使用 dir(__builtins__) 來查看。這也是爲什麼我們在沒有 import 任何模塊的情況下,就能使用這麼多豐富的函數和功能了。

介紹完命名空間,就能理解 print(a) 這行代碼輸出的結果爲什麼是 a string 了。

--內置屬性 __name__

現在到了解釋 if __name__ == '__main__' 這行代碼的時候了。當 Python 程序啓動後,Python 會自動爲每個模塊設置一個屬性 __name__ 通常使用的是模塊的名字,也就是文件名,但唯一的例外是主模塊,主模塊將會被設置爲 __main__。利用這一特性,就可以做一些特別的事。比如當該模塊以主模塊來運行的時候,可以運行測試用例。而當被其他模塊 import 時,則只是乖乖的,提供函數和功能就好。

--動態類型

繼續看函數 func 裏面的代碼,這時又有一條賦值語句 a = 1。變量 a 現在已經變成了第三種類型,它現在是一個整數了。那麼 Python 是怎麼實現動態類型的呢?答案就藏在具體存儲的對象上。變量 a 僅僅只是一個符號(實際上是一個字符串對象),類型信息是存儲在對象上的。在 Python 中,對象機制的核心是類型信息和引用計數(引用計數屬於垃圾回收的部分)。

用 type(a),可以輸出 a 的類型,這裏是 int

b = 257 跳過,我們直接來看看 print(a + b),print 是輸出函數,這裏略過。這裏想要探究的是 a + b。

因爲 a 和 b 並不存儲類型信息,因此當執行 a + b 的時候就必須先檢查類型,比如 1 + 2 和 "1" + "2" 的結果是不一樣的。

看到這裏,我們就可以想象一下執行一句簡單的 a + b,Python 虛擬機需要做多少繁瑣的事情了。首先需要分別檢查 a 和 b 所對應對象的類型,還要匹配類型是否一致(1 + "2" 將會出現異常),然後根據對象的類型調用正確的 + 函數(例如數值的 + 或字符串的 +),而 CPU 對於上面這條語句只需要執行 ADD 指令(還需要先將變量 MOV 到寄存器)。

--小整數對象池

在 demo.py 這裏例子中,所用的整數特意用了一個 257,這是爲了介紹小整數對象池的。整數在程序中的使用非常廣泛,Python 爲了優化速度,使用了小整數對象池,避免爲整數頻繁申請和銷燬內存空間。

Python 對小整數的定義是 [-5, 257),這些整數對象是提前建立好的,不會被垃圾回收。在一個 Python 的程序中,所有位於這個範圍內的整數使用的都是同一個對象,從下面這個例子就可以看出。

>>> a = 1 >>> id(a) 40059744 >>> b = 1 >>> id(b) 40059744 >>> c = 257 >>> id(c) 41069072 >>> d = 257 >>> id(257) 41069096

id 函數可以用來查看一個對象的唯一標誌,可以認爲是內存地址

對於大整數,Python 使用的是一個大整數對象池。這句話的意思是:

每當創建一個大整數的時候,都會新建一個對象,但是這個對象不再使用的時候,並不會銷燬,後面再建立的對象會複用之前已經不再使用的對象的內存空間。(這裏的不再使用指的是引用計數爲0,可以被銷燬)

--字符串對象緩衝池

如果仔細思考一下,一定會猜到字符串也採用了這種類似的技術,我們來看一下

>>> a = 'a' >>> b = 'a' >>> id(a) 14660456 >>> id(b) 14660456

沒錯,Python 的設計者爲一個字節的字符對應的字符串對象 (PyStringObject) 也設計了這樣一個對象池。同時還有一個 intern 機制,可以將內容相同的字符串變量轉換成指向同一個字符串對象。

intern 機制的關鍵,就是在系統中有一個(key,value)映射關係的集合,集合的名稱叫做 interned。在這個集合中,記錄着被 intern 機制處理過的 PyStringObject 對象。不過 Python 始終會爲字符串創建 PyStringObject 對象,即便在interned 中已經有一個與之對應的 PyStringObject 對象了,而 intern 機制是在字符串被創建後才起作用。

>>> a = 'a string' >>> b = 'a string' >>> a is b False >>> a = intern('a string') # 手動調用 intern 方法 >>> b = intern('a string') >>> a is b True

關於 intern 函數 可以參考官方文檔,更多擴展閱讀:

http://stackoverflow.com/questions/15541404/python-string-interning

值得說明的是,數值類型和字符串類型在 Python 中都是不可變的,這意味着你無法修改這個對象的值,每次對變量的修改,實際上是創建一個新的對象。得益於這樣的設計,才能使用對象緩衝池這種優化。

Python 的實現上大量採用了這種內存對象池的技術,不僅僅對於這些特定的對象,還有專門的內存池用於小對象,使用這種技術可以避免頻繁地申請和釋放內存空間,目的就是讓 Python 能稍微更快一點。更多內容可以參考這裏。

如果想了解更快的 Python,可以看看 PyPy

--垃圾回收

在講到垃圾回收的時候,通常會使用引用計數的模型,這是一種最直觀,最簡單的垃圾收集技術。Python 同樣也使用了引用計數,但是引用計數存在這些缺點:

? 頻繁更新引用計數會降低運行效率

? 引用計數無法解決循環引用問題

Python 在引用計數機制的基礎上,使用了主流垃圾收集技術中的標記——清除和分代收集兩種技術。

關於垃圾回收,可以參考

http://hbprotoss.github.io/posts/pythonla-ji-hui-shou-ji-zhi.html

2. 背後的魔法

看完程序的執行結果,接下來開始一行行解釋代碼。

2.7 絕對引入和相對引入

前文已經介紹了 import foo 這行代碼。這裏隱含了一個問題,就是 foo 是什麼,如何找到 foo。這就屬於 Python 的模塊引入規則,這裏不展開介紹,可以參考 pep-0328。

2.8 賦值語句

接下來,執行到 a = [1, 'python'],這是一條賦值語句,定義了一個變量 a,它對應的值是 [1, 'python']。這裏要解釋一下,變量是什麼呢?

按照[維基百科]("https://en.wikipedia.org/wiki/Variable_(computer_science") 的解釋

變量是一個存儲位置和一個關聯的符號名字,這個存儲位置包含了一些已知或未知的量或者信息。

變量實際上是一個字符串的符號,用來關聯一個存儲在內存中的對象。在 Python 中,會使用 dict(就是 Python 的 dict 對象)來存儲變量符號(字符串)與一個對象的映射。

那麼賦值語句實際上就是用來建立這種關聯,在這個例子中是將符號 a 與一個列表對象 [1, 'python'] 建立映射。

緊接着的代碼執行了 a = 'a string',這條指令則將符號 a 與另外一個字符串對象 a string 建立了映射。今後對變量 a 的操作,將反應到字符串對象 a string 上。

4. 參考文獻

? Python 源碼剖析

? Python 官方文檔

-------------Python數據分析幾個比較常用的方法

##--1,表頭或是excel的索引如果是中文的話,輸出會出錯

解決方法:  python的版本問題!換成python3就自動解決了!當然也有其他的方法,這裏就不再深究

##--2,如果有很多列,如何輸出指定的列?

需求情況:  有的時候,數據很多,但是隻要僅僅對部分列的數據進行分析的話,要怎麼做?

解決方法:

df = pandas.read_excel('1.xls',sheetname= '店鋪分析日報')

df = df.loc[:,['關鍵詞','帶來的訪客數','跳失率']] #訪問指定的列

一行讀取數據,第二行訪問指定列

##--3,如何爲數據框添加新的列?

需求情況:  有一個表格,裏面的列是單價,數量,想再輸出一個總價的列,或是對一些數據進行總結

解決方法:  直接上代碼

from pandas import read_csv;

import pandas;

df = read_csv("1.csv", sep="|");

#把計算結果添加爲一個新的列

df['result'] = df.price*df.num     #新的列名,後面是對應的數值

print (df)

##--4,如何對百分號的數值進行計算,再將其輸出

需求情況:  比較蛋疼的一個情況,電商很多數據都是百分比的,帶有百分號,不能進行直接的計算,需要對其進行轉換,然後再輸出

解決方法:

from pandas import read_csv;

import pandas;

df = read_csv("1.csv", sep="|");

f = df['跳失率'].str.strip("%").astype(float)/100;

f.round(decimals=2)  #保留小數點後面2位

f_str = f.apply(lambda x: format(x, '.2%'));  #再轉換成百分號並且保留2位數(精度可以調整)

df['跳失率'] = f_str     #重新賦值

##--5,如何獲取導入的數據有幾行和幾列(數值)

需求情況:  有的時候需要寫一個通用腳本,比如隨機抽樣分析,程序自動獲取行和列的話,寫出來的腳本通用性明顯會很強

解決方法:

df.columns.size   #獲取列數

df.iloc[:, 0].size  #獲取行數

##--6,如何對數據進行排序

需求情況:  這個就不用說了,到處都要用到

解決方法:

df['跳失率'].size   #對數據進行排序

newDF = df.sort(['曝光量', '帶來的訪客數'], ascending=[True, False]);  #多重排序

##--7,如何刪除指定的列?

需求情況:  同樣,十幾列的數據,如果你想獲取指定的輸出數據,可以用方法2,但是如果想要獲取的數據列比較多,只有1-2行不想要,這樣就可以用指定刪除列的方法了

解決方法:

df.columns.delete(1)

一行代碼搞定!

總結:  整體來說的,python的語法在做數據分析還是相當簡單的,很多的需求基本上就是一行代碼搞定!

##--8,如何添加整行數據?

df.append([1,2,34,,5])


--python中的__slots__使用示例

__slots__  用來限制class能添加的屬性

正常情況下,當定義了一個class,創建了一個class的實例後,可以給該實例綁定任何屬性和方法,這就是動態語言的靈活性。

先定義class:

>>> class Staff(object):

...     pass

...

然後,嘗試給實例綁定一個屬性:

>>> s = Staff()

>>> s.name = 'jack'

>>> print s.name        #jack

>>>

還可以嘗試給實例綁定一個方法:

>>> def set_age(self,age):

...     self.age = age

...

>>> from types import MethodType

>>> s.set_age = MethodType(set_age, s, Staff)

>>> s.set_age(34)

>>> s.age         #34

但是,給一個實例綁定的方法,對另一個實例是不起作用的:

>>> s2 = Staff()

>>> s2.set_age(35)

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: 'Staff' object has no attribute 'set_age'

爲了給所有實例都綁定方法,可以給class綁定方法:

>>> def set_score(self, score):

...     self.score = score

...

>>> Staff.set_score = MethodType(set_score, None, Staff)

給class綁定方法後,所有實例均可調用:

>>> s.set_score(100)

>>> s.score      #100

>>> s2.set_score(99)

>>> s2.score      #99

通常情況下,上面的set_score方法可以直接定義在class中,但動態綁定允許我們在程序運行的過程中動態給class加上功能,這在靜態語言中很難實現。

使用__slots__

但是,如果我們想要限制class的屬性怎麼辦?比如,只允許對Staff實例添加name和age屬性。

爲了達到限制的目的,Python允許在定義class的時候,定義一個特殊的__slots__變量,來限制該class能添加的屬性:

>>> class Staff(object):

...     __slots__ = ('name', 'age')

...

然後,我們試試:

>>> s = Staff()

>>> s.name = 'jack'

>>> s.age = 34

>>> s.score = 99

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: 'Staff' object has no attribute 'score'

由於‘sorce'沒有被放到__slots__中,所以不能綁定score屬性,試圖綁定score將得到AttributeError的錯誤。

使用__slots__要注意,__slots__定義的屬性僅對當前類起作用,對繼承的子類是不起作用的:

>>> class GraduateStaff(Staff):

...     pass

...

>>> g = GraduateStaff()

>>> g.score = 9999

>>> g.score

9999

除非在子類中也定義__slots__,這樣,子類允許定義的屬性就是自身的__slots__加上父類的__slots__。



--********************************************************************************************************************************

--python循環控制----------------------------------------------------------------------------

--********************************************************************************************************************************

--條件語句 if else-----------------------------------------------------------------------------------------------------------------

--循環語句 while--for--break--continue--pass----------------------------------------------------------------------------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章