python基礎學習筆記

Python中,數值類型(intfloat)、字符串str、元組tuple都是不可變類型。python

而列表list、字典dict、集合set是可變類型。mysql

1.關於''' '''(一對三引號)
主要有兩種做用 1.對代碼得註釋 2.在print(''' ''' )按原樣輸出
2.關於轉義字符
\r 回車,將當前位置移動到本行開頭
\n 換行,將當前位置移動到下一行開頭正則表達式

>>> print('ab\\rcd') ab\rcd >>> print('ab\rcd') ab cd >>> print('ab\ncd') ab cd >>> print(r'ab\rcd') ab\rcd

3.變量命名規則
字母、數字和下劃線,不能以數字開頭
4.經常使用數據類型
最經常使用的數據類型有三種——字符串(str)、整數(int)和浮點數(float)、
print(0.55+0.3)      0.8500000000000001
Python計算浮點數時,會先把0.55和0.3轉化成二進制數
5.數據拼接
數據拼接的方法簡單,利用數據拼接符號【+】,將須要拼接的變量連在一塊兒就好了
hero = '亞瑟'
enemy = '敵方'
action = '團滅'
gain = '得到'
achieve = 'ACE稱號'
print(hero+action+enemy+gain+achieve)
print()函數也能夠接受多個字符串,用逗號「,」隔開,就能夠連成一串輸出:
>>> print('The quick brown fox', 'jumps over', 'the lazy dog')
The quick brown fox jumps over the lazy dogsql

6.type()函數
爲何不一樣類型的數據不能拼接在一塊兒呢?一句話:圈子不一樣不相融。
負責轉換數據類型的函數一共有3種:str()、 int()和float()。
整數轉換字符串類型的方法是否是很方便?還有一種轉換成字符串的方法,那就是借用引號的幫助,
只有符合整數規範的字符串類數據,才能被int()強制轉換。
雖然浮點形式的字符串,不能使用int()函數。但浮點數是能夠被int()函數強制轉換的。
7.float()函數
首先float()函數的使用,也是將須要轉換的數據放在括號裏,像這樣:float(數據)。
其次,float()函數也能夠將整數和字符串轉換爲浮點類型。同時,若是括號裏面數據是字符串類型,這個數據必定得是數字形式。數據庫

用英文輸入法打:後按回車,開發工具(IDE)會自動實現下一行代碼,向右縮進的功能。編程

else想正確執行,必定要有一個和他平級的前提,這個前提能夠是if判斷,也能夠是其餘命令,好比循環命令。json

多向判斷:if…elif…else…緩存

8.input()函數
input('請鏟屎官輸入寵物的名字:')
對於input()函數來講,無論咱們輸入的回答是什麼,
無論你輸入的是整數1234,仍是字符串我愛摩卡,input()函數的輸入值(蒐集到的回答),
永遠會被強制性地轉換爲字符串類型。(Python3固定規則)
9.CPython用>>>做爲提示符,而IPython用In [序號]:做爲提示符。服務器

方法是在.py文件的第一行加上一個特殊的註釋:
#!/usr/bin/env python3
print('hello, world')
而後,經過命令給hello.py以執行權限:
$ chmod a+x hello.py
就能夠直接運行hello.py了
10.若是字符串裏面有不少字符都須要轉義,就須要加不少\,
爲了簡化,Python還容許用r' '表示' '內部的字符串默認不轉義
>>> print(r'\\\t\\')
\\\t\\網絡

對於單個字符的編碼,
Python提供了ord()函數獲取字符的整數表示,chr()函數把編碼轉換爲對應的字符:

encode()編碼
decode()解碼
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

11.關於格式化輸出

>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
%d整數
%f浮點數
%s字符串
%x十六進制整數
>>> '%2d-%02d' % (3, 1)
' 3-01'
>>> '%.2f'% 3.1415926
'3.14'

若是你不太肯定應該用什麼,%s永遠起做用,它會把任何數據類型轉換爲字符串:
>>> 'Age: %s. Gender: %s' % (25, True)
'Age: 25. Gender: True'
有些時候,字符串裏面的%是一個普通字符怎麼辦?這個時候就須要轉義,用%%來表示一個%:
>>> 'growth rate: %d %%' % 7
'growth rate: 7 %'
list
12.Python內置的一種數據類型是列表:list。
list是一種有序的集合,能夠隨時添加和刪除其中的元素。
列表 list[]
元組tuple() t=(1,)
這是由於input()返回的數據類型是str,str不能直接和整數比較,必須先把str轉換成整數。
Python提供了int()函數來完成這件事情:
13.Python的循環有兩種:
一種是for...in循環,依次把list或tuple中的每一個元素迭代出來,看例子:
names = ['Michael', 'Bob', 'Tracy']
for name in names:
  print(name)
=================================================
sum = 0
for x in range(101):
  sum = sum + x
  print(sum)
第二種循環是while循環,只要條件知足,就不斷循環,條件不知足時退出循環。
好比咱們要計算100之內全部奇數之和,能夠用while循環實現:
sum = 0
n = 99
while n > 0:
  sum = sum + n
  n = n - 2
print(sum)
=================================================
14.使用dict和set
dict字典:使用鍵-值(key-value)存儲,具備極快的查找速度。
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
>>> d['Michael']
95
因爲一個key只能對應一個value,因此,屢次對一個key放入value,後面的值會把前面的值沖掉:
>>> d['Jack'] = 90
>>> d['Jack']
90
>>> d['Jack'] = 88
>>> d['Jack']
88
要避免key不存在的錯誤,有兩種辦法,一是經過in判斷key是否存在:
>>> 'Thomas' in d
False
二是經過dict提供的get方法,若是key不存在,能夠返回None,或者本身指定的value:
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
要刪除一個key,用pop(key)方法,對應的value也會從dict中刪除:
>>> d.pop('Bob')
75
>>> d
{'Michael': 95, 'Tracy': 85}
請務必注意,dict內部存放的順序和key放入的順序是沒有關係的。
和list比較,dict有如下幾個特色:
1. 查找和插入的速度極快,不會隨着key的增長而增長;
2. 須要佔用大量的內存,內存浪費多。
而list相反:
1. 查找和插入的時間隨着元素的增長而增長;
2. 佔用空間小,浪費內存不多。
因此,dict是用空間來換取時間的一種方法。
dict能夠用在須要高速查找的不少地方,在Python代碼中幾乎無處不在,
正確使用dict很是重要,須要牢記的第一條就是dict的key必須是不可變對象。
set
set和dict相似,也是一組key的集合,但不存儲value。
因爲key不能重複,因此,在set中,沒有重複的key
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
注意,傳入的參數[1, 2, 3]是一個list,而顯示的{1, 2, 3}只是告訴你這個set內部有1,2,3這3個元素,
顯示的順序也不表示set是有序的。
經過add(key)方法能夠添加元素到set中,能夠重複添加,但不會有效果:
經過remove(key)方法能夠刪除元素:
set能夠當作數學意義上的無序和無重複元素的集合,所以,兩個set能夠作數學意義上的交集、並集等操做:
上面咱們講了,str是不變對象,而list是可變對象。
對於可變對象,好比list,對list進行操做,list內部的內容是會變化的,好比:
>>> a = ['c', 'b', 'a']
>>> a.sort()
>>> a
['a', 'b', 'c']
而對於不可變對象,好比str,對str進行操做呢:
>>> a = 'abc'
>>> a.replace('a', 'A')
'Abc'
>>> a
'abc'
15.定義函數
在Python中,定義一個函數要使用def語句,依次寫出函數名、括號、括號中的參數和冒號:,
而後,在縮進塊中編寫函數體,函數的返回值用return語句返回。
咱們以自定義一個求絕對值的my_abs函數爲例:
def my_abs(x):
  if x >= 0:
    return x
  else:
    return -x
已經把my_abs()的函數定義保存爲abstest.py文件了,能夠在該文件的當前目錄下啓動Python解釋器
用from abstest import my_abs來導入my_abs()函數,注意abstest是文件名(不含.py擴展名):
16.空函數
若是想定義一個什麼事也不作的空函數,能夠用pass語句:
def nop():
  pass
pass語句什麼都不作,那有什麼用?實際上pass能夠用來做爲佔位符,
好比如今還沒想好怎麼寫函數的代碼,就能夠先放一個pass,讓代碼能運行起來。
pass還能夠用在其餘語句裏,好比:
if age >= 18:
  pass
缺乏了pass,代碼運行就會有語法錯誤。
讓咱們修改一下my_abs的定義,對參數類型作檢查,只容許整數和浮點數類型的參數。
數據類型檢查能夠用內置函數isinstance()實現:
def my_abs(x):
  if not isinstance(x, (int, float)):
    raise TypeError('bad operand type')
  if x >= 0:
    return x
  else:
    return -x
函數執行完畢也沒有return語句時,自動return None。
函數能夠同時返回多個值,但其實就是一個tuple。
Python的函數定義很是簡單,但靈活度卻很是大。
除了正常定義的必選參數外,還可使用默認參數、可變參數和關鍵字參數,使得函數定義出來的接口,不但能處理複雜的參數,還能夠簡化調用者的代碼。
把power(x)修改成power(x, n),用來計算xn
def power(x, n):
  s = 1
while n > 0:
  n = n - 1
  s = s * x
  return s
對於這個修改後的power(x, n)函數,能夠計算任意n次方:
17.默認參數
新的power(x, n)函數定義沒有問題,
可是,舊的調用代碼失敗了,緣由是咱們增長了一個參數,致使舊的代碼由於缺乏一個參數而沒法正常調用:
Python的錯誤信息很明確:調用函數power()缺乏了一個位置參數n。
這個時候,默認參數就排上用場了。因爲咱們常常計算x2,因此,徹底能夠把第二個參數n的默認值設定爲2:
def power(x, n=2):
這樣,當咱們調用power(5)時,至關於調用power(5, 2):
>>> power(5)
25
>>> power(5, 2)
25
而對於n > 2的其餘狀況,就必須明確地傳入n,好比power(5, 3)。
從上面的例子能夠看出,默認參數能夠簡化函數的調用。
設置默認參數時,有幾點要注意:
一是必選參數在前,默認參數在後,不然Python的解釋器會報錯
定義默認參數要牢記一點:默認參數必須指向不變對象!
18.關鍵字參數
可變參數容許你傳入0個或任意個參數,這些可變參數在函數調用時自動組裝爲一個tuple。

而關鍵字參數容許你傳入0個或任意個含參數名的參數,這些關鍵字參數在函數內部自動組裝爲一個dict。請看示例:
def person(name, age, **kw):
  print('name:', name, 'age:', age, 'other:', kw)
函數person除了必選參數name和age外,還接受關鍵字參數kw。在調用該函數時,能夠只傳入必選參數:
>>> person('Michael', 30)
name: Michael age: 30 other: {}
也能夠傳入任意個數的關鍵字參數:
>>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
關鍵字參數有什麼用?它能夠擴展函數的功能。
好比,在person函數裏,咱們保證能接收到name和age這兩個參數,
可是,若是調用者願意提供更多的參數,咱們也能收到。試想你正在作一個用戶註冊的功能,
除了用戶名和年齡是必填項外,其餘都是可選項,利用關鍵字參數來定義這個函數就能知足註冊的需求。
和可變參數相似,也能夠先組裝出一個dict,而後,把該dict轉換爲關鍵字參數傳進去:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
固然,上面複雜的調用能夠用簡化的寫法:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
**extra表示把extra這個dict的全部key-value用關鍵字參數傳入到函數的**kw參數,
kw將得到一個dict,注意kw得到的dict是extra的一份拷貝,對kw的改動不會影響到函數外的extra。
19.命名關鍵字參數
對於關鍵字參數,函數的調用者能夠傳入任意不受限制的關鍵字參數。
至於到底傳入了哪些,就須要在函數內部經過kw檢查。
仍以person()函數爲例,咱們但願檢查是否有city和job參數:
def person(name, age, **kw):
  if 'city' in kw:
# 有city參數
  pass
if 'job' in kw:
# 有job參數
  pass
print('name:', name, 'age:', age, 'other:', kw)
可是調用者仍能夠傳入不受限制的關鍵字參數:
>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)
若是要限制關鍵字參數的名字,就能夠用命名關鍵字參數,
例如,只接收city和job做爲關鍵字參數。這種方式定義的函數以下:
def person(name, age, *, city, job):
  print(name, age, city, job)
和關鍵字參數**kw不一樣,命名關鍵字參數須要一個特殊分隔符*,*後面的參數被視爲命名關鍵字參數。
調用方式以下:
>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer
命名關鍵字參數必須傳入參數名,這和位置參數不一樣。若是沒有傳入參數名,調用將報錯:
>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given
因爲調用時缺乏參數名city和job,
Python解釋器把這4個參數均視爲位置參數,但person()函數僅接受2個位置參數。
命名關鍵字參數能夠有缺省值,從而簡化調用:
def person(name, age, *, city='Beijing', job):
  print(name, age, city, job)
因爲命名關鍵字參數city具備默認值,調用時,可不傳入city參數:
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer
使用命名關鍵字參數時,要特別注意,*不是參數,而是特殊分隔符。
若是缺乏*,Python解釋器將沒法識別位置參數和命名關鍵字參數:
def person(name, age, city, job):
# 缺乏 *,city和job被視爲位置參數
  pass
*args是可變參數,args接收的是一個tuple;
**kw是關鍵字參數,kw接收的是一個dict。
在函數內部,能夠調用其餘函數。若是一個函數在內部調用自身自己,這個函數就是遞歸函數。
20.切片
取一個list或tuple的部分元素是很是常見的操做。好比,一個list以下:
>>> L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
取前3個元素,應該怎麼作?
對應上面的問題,取前3個元素,用一行代碼就能夠完成切片:
>>> L[0:3]
['Michael', 'Sarah', 'Tracy']
若是第一個索引是0,還能夠省略:
>>> L[:3]
tuple也是一種list,惟一區別是tuple不可變。所以,tuple也能夠用切片操做,只是操做的結果還是tuple:
>>> (0, 1, 2, 3, 4, 5)[:3]
(0, 1, 2)
字符串'xxx'也能夠當作是一種list,每一個元素就是一個字符。所以,字符串也能夠用切片操做,只是操做結果還是字符串:
>>> 'ABCDEFG'[:3]
'ABC'
>>> 'ABCDEFG'[::2]
'ACEG'
在不少編程語言中,針對字符串提供了不少各類截取函數(例如,substring),其實目的就是對字符串切片。
Python沒有針對字符串的截取函數,只須要切片一個操做就能夠完成,很是簡單。
21.默認狀況下,dict迭代的是key。

若是要迭代value,能夠用for value in d.values()
若是要同時迭代key和value,能夠用for k, v in d.items()
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> for k, v in d.items():
... print(k, '=', v)
y = B
x = A
z = C
那麼,如何判斷一個對象是可迭代對象呢?方法是經過collections模塊的Iterable類型判斷:
>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整數是否可迭代
False
最後一個小問題,若是要對list實現相似Java那樣的下標循環怎麼辦?
Python內置的enumerate函數能夠把一個list變成索引-元素對,這樣就能夠在for循環中同時迭代索引和元素自己:
>>> for i, value in enumerate(['A', 'B', 'C']):
... print(i, value)
0 A
1 B
2 C
22.列表生成式
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
寫列表生成式時,把要生成的元素x * x放到前面,後面跟for循環,就能夠把list建立出來
for循環後面還能夠加上if判斷,這樣咱們就能夠篩選出僅偶數的平方:
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]
還可使用兩層循環,能夠生成全排列:
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
所以,列表生成式也可使用兩個變量來生成list:
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
最後把一個list中全部的字符串變成小寫:
>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']
23.要建立一個generator,有不少種方法
第一種方法很簡單,只要把一個列表生成式的[]改爲(),就建立了一個generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>
建立L和g的區別僅在於最外層的[]和(),L是一個list,而g是一個generator。
固然,上面這種不斷調用next(g)實在是太變態了,正確的方法是使用for循環,由於generator也是可迭代對象:
>>> g = (x * x for x in range(10))
>>> for n in g:
... print(n)
一樣的,把函數改爲generator後,
咱們基本上歷來不會用next()來獲取下一個返回值,而是直接使用for循環來迭代

24.yield
def odd():
  print('step 1')
  yield 1
  print('step 2')
  yield(3)
  print('step 3')
  yield(5)
>>> for n in odd():
    print(n)
step 1
1
step 2
33
step 3
55
咱們已經知道,能夠直接做用於for循環的數據類型有如下幾種:
一類是集合數據類型,如list、tuple、dict、set、str等;
一類是generator,包括生成器和帶yield的generator function。
這些能夠直接做用於for循環的對象統稱爲可迭代對象:Iterable。
可使用isinstance()判斷一個對象是不是Iterable對象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
而生成器不但能夠做用於for循環,還能夠被next()函數不斷調用並返回下一個值,直到最後拋出StopIteration錯誤表示沒法繼續返回下一個值了。
能夠被next()函數調用並不斷返回下一個值的對象稱爲迭代器:Iterator。
可使用isinstance()判斷一個對象是不是Iterator對象:
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator對象,但list、dict、str雖然是Iterable,卻不是Iterator。
把list、dict、str等Iterable變成Iterator可使用iter()函數:

25.要進行反向排序,沒必要改動key函數,能夠傳入第三個參數reverse=True:
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
因爲函數也是一個對象,並且函數對象能夠被賦值給變量,因此,經過變量也能調用該函數。
>>> def now():
... print('2015-3-25')
>>> f = now
>>> f()
2015-3-25
函數對象有一個__name__屬性,能夠拿到函數的名字:
>>> now.__name__
'now'
>>> f.__name__
'now'
如今,假設咱們要加強now()函數的功能,好比,在函數調用先後自動打印日誌,
但又不但願修改now()函數的定義,這種在代碼運行期間動態增長功能的方式,稱之爲「裝飾器」(Decorator)。
和靜態語言不一樣,Python容許對實例變量綁定任何數據,也就是說,對於兩個實例變量,雖然它們都是同一個類的不一樣實例,但擁有的變量名稱均可能不一樣:
>>> bart = Student('Bart Simpson', 59)
>>> lisa = Student('Lisa Simpson', 87)
>>> bart.age = 8
>>> bart.age
8
>>> lisa.age
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'age'
若是要讓內部屬性不被外部訪問,能夠把屬性的名稱前加上兩個下劃線__,
在Python中,實例的變量名若是以__開頭,就變成了一個私有變量(private),
只有內部能夠訪問,外部不能訪問,因此,咱們把Student類改一改:
class Student(object):
  def __init__(self, name, score):
    self.__name = name
    self.__score = score
  def print_score(self):
    print('%s: %s' % (self.__name, self.__score))
可是若是外部代碼要獲取name和score怎麼辦?能夠給Student類增長get_name和get_score這樣的方法:
class Student(object):
...
  def get_name(self):
    return self.__name
  def get_score(self):
    return self.__score
若是又要容許外部代碼修改score怎麼辦?能夠再給Student類增長set_score方法:
class Student(object):
...
def set_score(self, score):
self.__score = score
須要注意的是,在Python中,變量名相似__xxx__的,也就是以雙下劃線開頭,而且以雙下劃線結尾的,是特殊變量,特殊變量是能夠直接訪問的,不是private變量,因此,不能用__name__、__score__這樣的變量名。
有些時候,你會看到以一個下劃線開頭的實例變量名,好比_name,這樣的實例變量外部是能夠訪問的,可是,按照約定俗成的規定,當你看到這樣的變量時,意思就是,「雖然我能夠被訪問,可是,請把我視爲私有變量,不要隨意訪問」。
雙下劃線開頭的實例變量是否是必定不能從外部訪問呢?其實也不是。不能直接訪問__name是由於Python解釋器對外把__name變量改爲了
_Student__name,因此,仍然能夠經過_Student__name來訪問__name變量:
>>> bart._Student__name
'Bart Simpson'
可是強烈建議你不要這麼幹,由於不一樣版本的Python解釋器可能會把__name改爲不一樣的變量名。
總的來講就是,Python自己沒有任何機制阻止你幹壞事,一切全靠自覺。
好比,咱們已經編寫了一個名爲Animal的class,有一個run()方法能夠直接打印:
class Animal(object):
  def run(self):
    print('Animal is running...')
當咱們須要編寫Dog和Cat類時,就能夠直接從Animal類繼承:
class Dog(Animal):
  pass
class Cat(Animal):
  pass
要理解什麼是多態,咱們首先要對數據類型再做一點說明。當咱們定義一個class的時候,咱們實際上就定義了一種數據類型。咱們定義的數據類型和Python自帶的數據類型,好比str、list、dict沒什麼兩樣:
a = list() # a是list類型
b = Animal() # b是Animal類型
c = Dog() # c是Dog類型
判斷一個變量是不是某個類型能夠用isinstance()判斷:
>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True
因此,在繼承關係中,若是一個實例的數據類型是某個子類,那它的數據類型也能夠被看作是父類。可是,反過來就不行:
>>> b = Animal()
>>> isinstance(b, Dog)
False
Dog能夠當作Animal,但Animal不能夠當作Dog。
獲取對象信息
當咱們拿到一個對象的引用時,如何知道這個對象是什麼類型、有哪些方法呢?
使用type()
首先,咱們來判斷對象類型,使用type()函數:
基本類型均可以用type()判斷:
>>> type(123)
<class 'int'>
>>> type('str')
<class 'str'>
>>> type(None)
<type(None) 'NoneType'>
若是一個變量指向函數或者類,也能夠用type()判斷:
>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
使用dir()
若是要得到一個對象的全部屬性和方法,可使用dir()函數,它返回一個包含字符串的list,好比,得到一個str對象的全部屬性和方法:
>>> dir('ABC')
====================================================
186/531
>>> def set_age(self, age): # 定義一個函數做爲實例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 給實例綁定一個方法
>>> s.set_age(25) # 調用實例方法
>>> s.age # 測試結果
25
可是,給一個實例綁定的方法,對另外一個實例是不起做用的:
>>> s2 = Student() # 建立新的實例
>>> s2.set_age(25) # 嘗試調用方法
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'
爲了給全部實例都綁定方法,能夠給class綁定方法:
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = MethodType(set_score, Student)
給class綁定方法後,全部實例都可調用:
>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99
一般狀況下,上面的set_score方法能夠直接定義在class中,
但動態綁定容許咱們在程序運行的過程當中動態給class加上功能,這在靜態語言中很難實現。
若是咱們想要限制實例的屬性怎麼辦?好比,只容許對Student實例添加name和age屬性。
爲了達到限制的目的,Python容許在定義class的時候,定義一個特殊的__slots__變量,來限制該class實例能添加的屬性:
class Student(object):
  __slots__ = ('name', 'age') # 用tuple定義容許綁定的屬性名稱
而後,咱們試試:
>>> s = Student() # 建立新的實例
>>> s.name = 'Michael' # 綁定屬性'name'
>>> s.age = 25 # 綁定屬性'age'
>>> s.score = 99 # 綁定屬性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
因爲'score'沒有被放到__slots__中,因此不能綁定score屬性,試圖綁定score將獲得AttributeError的錯誤。
使用__slots__要注意,__slots__定義的屬性僅對當前類實例起做用,對繼承的子類是不起做用的:
>>> class GraduateStudent(Student):
... pass
...
>>> g = GraduateStudent()
>>> g.score = 9999
除非在子類中也定義__slots__,這樣,子類實例容許定義的屬性就是自身的__slots__加上父類的__slots__。
怎麼才能打印得好看呢?只須要定義好__str__()方法,返回一個好看的字符串就能夠了:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return 'Student object (name: %s)' % self.name
...
>>> print(Student('Michael'))
Student object (name: Michael)
高級語言一般都內置了一套try...except...finally...的錯誤處理機制,Python也不例外。
try
讓咱們用一個例子來看看try的機制:
try:
  print('try...')
  r = 10 / 0
  print('result:', r)
except ZeroDivisionError as e:
  print('except:', e)
finally:
  print('finally...')
  print('END')
當咱們認爲某些代碼可能會出錯時,就能夠用try來運行這段代碼,
若是執行出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,
即except語句塊,執行完except後,若是有finally語句塊,則執行finally語句塊,至此,執行完畢。
全部的錯誤類型都繼承自BaseException
try:
  print('try...')
  r = 10 / 0
  print('result:', r)
except BaseException as e:
  print('except:', e)
finally:
  print('finally...')
  print('END')
可使用Python內置的logging模塊能夠很是容易地記錄錯誤信息:
except Exception as e:
  logging.exception(e)
一樣是出錯,但程序打印完錯誤信息後會繼續執行,並正常退出
raise 拋出錯誤
若是要比較爽地設置斷點、單步執行,就須要一個支持調試功能的IDE。
目前比較好的Python IDE有PyCharm:
第一種是CPU等着,也就是程序暫停執行後續代碼,等100M的數據在10秒後寫入磁盤,再接着往下執行,這種模式稱爲同步IO;

另外一種方法是CPU不等待,只是告訴磁盤,「您老慢慢寫,不着急,我接着幹別的事去了」,
因而,後續代碼能夠馬上接着執行,這種模式稱爲異步IO。
26.讀文件
要以讀文件的模式打開一個文件對象,使用Python內置的open()函數,傳入文件名和標示符:
>>> f = open('/Users/michael/test.txt', 'r')
標示符'r'表示讀,這樣,咱們就成功地打開了一個文件。
248/531
若是文件不存在,open()函數就會拋出一個IOError的錯誤,而且給出錯誤碼和詳細的信息告訴你文件不存在:
>>> f=open('/Users/michael/notfound.txt', 'r')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/Users/michael/notfound.txt'
若是文件打開成功,接下來,調用read()方法能夠一次讀取文件的所有內容,Python把內容讀到內存,用一個str對象表示:
>>> f.read()
'Hello, world!'
最後一步是調用close()方法關閉文件。文件使用完畢後必須關閉,由於文件對象會佔用操做系統的資源,而且操做系統同一時間能打開的文件數量也是有限的:
>>> f.close()
Python引入了with語句來自動幫咱們調用close()方法:
with open('/path/to/file', 'r') as f:
print(f.read())
若是文件很小,read()一次性讀取最方便;若是不能肯定文件大小,反覆調用read(size)比較保險;若是是配置文件,調用readlines()最方便:
for line in f.readlines():
print(line.strip()) # 把末尾的'\n'刪掉
要讀取二進制文件,好比圖片、視頻等等,用'rb'模式打開文件便可:
>>> f = open('/Users/michael/test.jpg', 'rb')
>>> f.read()
b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六進制表示的字節
要讀取非UTF-8編碼的文本文件,須要給open()函數傳入encoding參數,例如,讀取GBK編碼的文件:
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk')
>>> f.read()
'測試'
遇到有些編碼不規範的文件,你可能會遇到UnicodeDecodeError,
由於在文本文件中可能夾雜了一些非法編碼的字符。
遇到這種狀況,open()函數還接收一個errors參數,表示若是遇到編碼錯誤後如何處理。
最簡單的方式是直接忽略:
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
寫文件
寫文件和讀文件是同樣的,惟一區別是調用open()函數時,傳入標識符'w'或者'wb'表示寫文本文件或寫二進制文件:
>>> f = open('/Users/michael/test.txt', 'w')
>>> f.write('Hello, world!')
>>> f.close()
251/531
你能夠反覆調用write()來寫入文件,可是務必要調用f.close()來關閉文件。
當咱們寫文件時,操做系統每每不會馬上把數據寫入磁盤,而是放到內存緩存起來,空閒的時候再慢慢寫入。
只有調用close()方法時,操做系統才保證把沒有寫入的數據所有寫入磁盤。
忘記調用close()的後果是數據可能只寫了一部分到磁盤,剩下的丟失了。
因此,仍是用with語句來得保險:
with open('/Users/michael/test.txt', 'w') as f:
f.write('Hello, world!')
要寫入特定編碼的文本文件,請給open()函數傳入encoding參數,將字符串自動轉換成指定編碼。
27.StringIO和BytesIO
StringIO
不少時候,數據讀寫不必定是文件,也能夠在內存中讀寫。
StringIO顧名思義就是在內存中讀寫str。
要把str寫入StringIO,咱們須要先建立一個StringIO,而後,像文件同樣寫入便可:
>>> from io import StringIO
>>> f = StringIO()
>>> f.write('hello')
5
>>> f.write(' ')
1
>>> f.write('world!')
6
>>> print(f.getvalue())
hello world!
getvalue()方法用於得到寫入後的str。
要讀取StringIO,能夠用一個str初始化StringIO,而後,像讀文件同樣讀取:
>>> from io import StringIO
>>> f = StringIO('Hello!\nHi!\nGoodbye!')
>>> while True:
... s = f.readline()
... if s == '':
... break
... print(s.strip())
...
Hello!
Hi!
Goodbye!
BytesIO
StringIO操做的只能是str,若是要操做二進制數據,就須要使用BytesIO。
BytesIO實現了在內存中讀寫bytes,咱們建立一個BytesIO,而後寫入一些bytes:
>>> from io import BytesIO
>>> f = BytesIO()
>>> f.write('中文'.encode('utf-8'))
6
>>> print(f.getvalue())
b'\xe4\xb8\xad\xe6\x96\x87'
請注意,寫入的不是str,而是通過UTF-8編碼的bytes。
和StringIO相似,能夠用一個bytes初始化BytesIO,而後,像讀文件同樣讀取:
>>> from io import StringIO
>>> f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
>>> f.read()
b'\xe4\xb8\xad\xe6\x96\x87'
小結
StringIO和BytesIO是在內存中操做str和bytes的方法,使得和讀寫文件具備一致的接口。
操做文件和目錄的函數一部分放在os模塊中,一部分放在os.path模塊中,這一點要注意一下。
查看、建立和刪除目錄能夠這麼調用:
# 查看當前目錄的絕對路徑:
>>> os.path.abspath('.')
'/Users/michael'
# 在某個目錄下建立一個新目錄,首先把新目錄的完整路徑表示出來:
>>> os.path.join('/Users/michael', 'testdir')
'/Users/michael/testdir'
# 而後建立一個目錄:
>>> os.mkdir('/Users/michael/testdir')
# 刪掉一個目錄:
>>> os.rmdir('/Users/michael/testdir')
把兩個路徑合成一個時,不要直接拼字符串,而要經過os.path.join()函數,
這樣能夠正確處理不一樣操做系統的路徑分隔符。
咱們把變量從內存中變成可存儲或傳輸的過程稱之爲序列化,
在Python中叫pickling,在其餘語言中也被稱之爲serialization,marshalling,flattening等等,都是一個意思。
序列化以後,就能夠把序列化後的內容寫入磁盤,或者經過網絡傳輸到別的機器上。
反過來,把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化,即unpickling。
Python提供了pickle模塊來實現序列化。
首先,咱們嘗試把一個對象序列化並寫入文件:
>>> import pickle
>>> d = dict(name='Bob', age=20, score=88)
>>> pickle.dumps(d)
b'\x80\x03}q\x00(X\x03\x00\x00\x00ageq\x01K\x14X\x05\x00\x00\x00scoreq\x02KXX\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Bobq\x04u.'
pickle.dumps()方法把任意對象序列化成一個bytes,而後,就能夠把這個bytes寫入文件。或者用另外一個方法pickle.dump()直接把對象序列化後寫入一個file-like Object:
>>> f = open('dump.txt', 'wb')
>>> pickle.dump(d, f)
>>> f.close()
看看寫入的dump.txt文件,一堆亂七八糟的內容,這些都是Python保存的對象內部信息。
當咱們要把對象從磁盤讀到內存時,能夠先把內容讀到一個bytes,而後用pickle.loads()方法反序列化出對象,
也能夠直接用pickle.load()方法從一個file-like Object中直接反序列化出對象。
咱們打開另外一個Python命令行來反序列化剛纔保存的對象:
>>> f = open('dump.txt', 'rb')
>>> d = pickle.load(f)
>>> f.close()
>>> d
{'age': 20, 'score': 88, 'name': 'Bob'}
變量的內容又回來了!
固然,這個變量和原來的變量是徹底不相干的對象,它們只是內容相同而已。
Pickle的問題和全部其餘編程語言特有的序列化問題同樣,就是它只能用於Python,
而且可能不一樣版本的Python彼此都不兼容,所以,只能用Pickle保存那些不重要的數據,不能成功地反序列化也不要緊。
JSON
若是咱們要在不一樣的編程語言之間傳遞對象,就必須把對象序列化爲標準格式,好比XML,但更好的方法是序列化爲JSON,
由於JSON表示出來就是一個字符串,能夠被全部語言讀取,也能夠方便地存儲到磁盤
或者經過網絡傳輸。JSON不只是標準格式,而且比XML更快,並且能夠直接在Web頁面中讀取,很是方便。
Python內置的json模塊提供了很是完善的Python對象到JSON格式的轉換。咱們先看看如何把Python對象變成一個JSON:
>>> import json
>>> d = dict(name='Bob', age=20, score=88)
>>> json.dumps(d)
'{"age": 20, "score": 88, "name": "Bob"}'
dumps()方法返回一個str,內容就是標準的JSON。相似的,dump()方法能夠直接把JSON寫入一個file-like Object。
要把JSON反序列化爲Python對象,用loads()或者對應的load()方法,前者把JSON的字符串反序列化,
後者從file-like Object中讀取字符串並反序列化:
>>> json_str = '{"age": 20, "score": 88, "name": "Bob"}'
>>> json.loads(json_str)
{'age': 20, 'score': 88, 'name': 'Bob'}
不過,下次若是遇到一個Teacher類的實例,照樣沒法序列化爲JSON。咱們能夠偷個懶,把任意class的實例變爲dict:
print(json.dumps(s, default=lambda obj: obj.__dict__))
由於一般class的實例都有一個__dict__屬性,它就是一個dict,用來存儲實例變量。
也有少數例外,好比定義了__slots__的class。
==================================================
有些進程還不止同時幹一件事,好比Word,它能夠同時進行打字、拼寫檢查、打印等事情。
在一個進程內部,要同時幹多件事,就須要同時運行多個「子任務」,咱們把進程內的這些「子任務」稱爲線程(Thread)
因爲每一個進程至少要幹一件事,因此,一個進程至少有一個線程。固然,像Word這種複雜的進程能夠有多個線程,多個線程能夠同時執行,多線程的執行方式和多進程是同樣的,
也是由操做系統在多個線程之間快速切換,讓每一個線程都短暫地交替運行,看起來就像同時執行同樣
Python既支持多進程,又支持多線程,咱們會討論如何編寫這兩種多任務程序。
==========================================
因爲線程是操做系統直接支持的執行單元,所以,高級語言一般都內置多線程的支持,Python也不例外,
而且,Python的線程是真正的Posix Thread,而不是模擬出來的線程。
Python的標準庫提供了兩個模塊:_thread和threading,_thread是低級模塊,threading是高級模塊,
對_thread進行了封裝。絕大多數狀況下,咱們只須要使用threading這個高級模塊
建立一個鎖就是經過threading.Lock()來實現:
balance = 0
lock = threading.Lock()
def run_thread(n):
for i in range(100000):
# 先要獲取鎖:
lock.acquire()
try:
# 放心地改吧:
change_it(n)
finally:
# 改完了必定要釋放鎖:
lock.release()
當多個線程同時執行lock.acquire()時,
只有一個線程能成功地獲取鎖,而後繼續執行代碼,其餘線程就繼續等待直到得到鎖爲止
=========================================
A|B能夠匹配A或B,因此[P|p]ython能夠匹配'Python'或者'python'。
^表示行的開頭,^\d表示必須以數字開頭。
$表示行的結束,\d$表示必須以數字結束
===========================
re模塊
有了準備知識,咱們就能夠在Python中使用正則表達式了。Python提供re模塊,包含全部正則表達式的功能。因爲Python的字符串自己也用\轉義,因此要特別注意:
s = 'ABC\\-001' # Python的字符串
# 對應的正則表達式字符串變成:
# 'ABC\-001'
所以咱們強烈建議使用Python的r前綴,就不用考慮轉義的問題了:
s = r'ABC\-001' # Python的字符串
# 對應的正則表達式字符串不變:
# 'ABC\-001'
先看看如何判斷正則表達式是否匹配:
>>> import re
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
>>> re.match(r'^\d{3}\-\d{3,8}$', '010 12345')
>>>
match()方法判斷是否匹配,若是匹配成功,返回一個Match對象,不然返回None。
virtualenv
每一個應用可能須要各自擁有一套「獨立」的Python運行環境。
virtualenv就是用來爲一個應用建立一套「隔離」的Python運行環境。
首先,咱們用pip安裝virtualenv:
$ pip3 install virtualenv
而後,假定咱們要開發一個新的項目,須要一套獨立的Python運行環境,能夠這麼作:
第一步,建立目錄:
Mac:~ michael$ mkdir myproject
Mac:~ michael$ cd myproject/
Mac:myproject michael$
第二步,建立一個獨立的Python運行環境,命名爲venv:
Mac:myproject michael$ virtualenv --no-site-packages venv
Using base prefix '/usr/local/.../Python.framework/Versions/3.4'
New python executable in venv/bin/python3.4
Also creating executable in venv/bin/python
Installing setuptools, pip, wheel...done.
命令virtualenv就能夠建立一個獨立的Python運行環境,咱們還加上了參數--no-site-packages,這樣,已經安裝到系統Python環境中的全部第三方包都不會複製過來,這樣,咱們就獲得了一個不帶任何第三方包的「乾淨」的Python運行環境。
新建的Python環境被放到當前目錄下的venv目錄。有了venv這個Python環境,能夠用source進入該環境:
Mac:myproject michael$ source venv/bin/activate
(venv)Mac:myproject michael$
注意到命令提示符變了,有個(venv)前綴,表示當前環境是一個名爲venv的Python環境。
下面正常安裝各類第三方包,並運行python命令:
(venv)Mac:myproject michael$ pip install jinja2
...
Successfully installed jinja2-2.7.3 markupsafe-0.23
(venv)Mac:myproject michael$ python myapp.py
...
在venv環境下,用pip安裝的包都被安裝到venv這個環境下,系統Python環境不受任何影響。
也就是說,venv環境是專門針對myproject這個應用建立的。
退出當前的venv環境,使用deactivate命令:
(venv)Mac:myproject michael$ deactivate
Mac:myproject michael$
此時就回到了正常的環境,如今pip或python均是在系統Python環境下執行。
徹底能夠針對每一個應用建立獨立的Python運行環境,這樣就能夠對每一個應用的Python環境進行隔離。
virtualenv是如何建立「獨立」的Python運行環境的呢?
原理很簡單,就是把系統Python複製一份到virtualenv的環境,用命令source venv/bin/activate進入一個virtualenv環境時,
virtualenv會修改相關環境變量,讓命令python和pip均指向當前的virtualenv環境
小結
virtualenv爲應用提供了隔離的Python運行環境,解決了不一樣應用間多版本的衝突問題。
用TCP協議進行Socket編程在Python中十分簡單,對於客戶端,要主動鏈接服務器的IP和指定端口,
對於服務器,要首先監聽指定端口,而後,對每個新的鏈接,建立一個線程或進程來處理。一般,服務器程序會無限運行下去。
同一個端口,被一個Socket綁定了之後,就不能被別的Socket綁定了。
===================
$ pip install mysql-connector-python --allow-external
咱們演示如何鏈接到MySQL服務器的test數據庫:
# 導入MySQL驅動:
>>> import mysql.connector
# 注意把password設爲你的root口令:
>>> conn = mysql.connector.connect(user='root', password='password', database='test')
>>> cursor = conn.cursor()
# 建立user表:
>>> cursor.execute('create table user (id varchar(20) primary key, name varchar(20))')
# 插入一行記錄,注意MySQL的佔位符是%s:
>>> cursor.execute('insert into user (id, name) values (%s, %s)', ['1', 'Michael'])
>>> cursor.rowcount
1
# 提交事務:
>>> conn.commit()
>>> cursor.close()
# 運行查詢:
>>> cursor = conn.cursor()
>>> cursor.execute('select * from user where id = %s', ['1'])
>>> values = cursor.fetchall()
>>> values
[('1', 'Michael')]
# 關閉Cursor和Connection:
>>> cursor.close()
True
>>> conn.close()
===========================================韋瑋爬蟲課程的python基礎================================================
方向:數據分析與挖掘
    機器學習
    自動化運維
print()
註釋:1.# 2.''' '''註釋法
數據類型:
數  字符串  列表  元組  集合  字典
列表:[]
元組:()
字典:{鍵:值,鍵:值}
集合:set()去重
e=set(「abcdef)
f=set(「sdfrhg」)
e-f e中有f中沒有的元素

+號能夠用於字符串的連接
"abc"+"def"

縮進: tab
有三種控制流
1.順序結構
2.條件分支結構
3.循環結構
whlie現實沒有for用的多
for:遍歷列表
a=[1,'a',23]
for i in a:
for:進行常規循環
for i in range(0,10):
break 和 continue:中斷一次循環,繼續下一次循環
a=["AA","B",'C','D']
for i in a:
  if(i=='c'):
    contine
  print(i)
會輸出"AA","B",'D' 中斷一次c繼續
print(,end="")end=「」表明不換行輸出

print() 換行
================================

系統自帶的模塊都在安裝目錄lib目錄中

import 模塊名
from 模塊名 import 方法名
==============
模塊類別:
自帶模塊
第三方模塊 pip安裝 whl下載後再用pip安裝 直接複製 anaconda

自定義模塊
============
文件操做
open(文件地址,操做形式)
/ 向左斜槓
w:寫入
r:讀取
b:二進制
a+:追加
==========================
異常

try:
程序
except exception as 異常名稱err:
異常處理部分如print(err)

注意try except的位置,是否能夠作到異常後的程序繼續

=======================
面向對象

class cl1:
pass

構造函數: 類在實例化的時候自動首先觸發的方法 初始化
__init__(self,參數) 兩個下劃線

class cl2:
  def __init__(self):
    print(""")

給類加上參數:構造方法加上參數
class cl3:
def __init__(self,name,job):
print(""")
=========================
屬性:類裏面的變量
class cl4:
def __init__(self,name,job):
  self.name=name
  self.job=job
=======================
方法:類裏面的函數 def 函數名(self,參數)
class cl5:
  def myfunc1(self):
    print("hello")

class cl6:
  def __init__(self,name):
    self.name=name
  def myfunc1(self):
    print("hello"+name)
===========================

相關文章
相關標籤/搜索