美食電子商務網站建設規(guī)劃書青島網絡優(yōu)化廠家
基礎
編碼、解碼
str.encode('utf-8') # 編碼
str.decode('utf-8') # 解碼
關鍵字
import keyword
keyword.kwlist
格式化輸出
%
'''
占位符:%s 字符串%d 整數%f 浮點數
'''
'Hello, %s' % 'world'
'Hi, %s, you have $%d.' % ('Michael', 1000000)
'''
占位符的修飾符
-左對齊 .小數點后位數 0左邊補零
'''
# 3以左對齊占兩個占位的形式輸出,1以右對齊占兩個占位的形式,并且前面填零補齊的形式輸出
print("%-2d xx %02d" % (3, 1))
# 小數點后兩位的形式輸出:3.14
print('%.2f' % 3.1415926)# %s可以將任何數據轉換為字符串
'Age: %s. Gender: %s' % (25, True) # 表示以字符串形式輸出25和True
format
用傳入的參數依次替換字符串內的占位符{0}、{1}…
print('Hello, {0}, 成績提升了 {1:.1f}%'.format('小明', 17.125))
# 'Hello, 小明, 成績提升了 17.1%'
輸入
# python3
Name=input(“請輸入你的名字:”)
print(“你的姓名是%s”%Name)
# python2
Name=raw_input(“請輸入你的名字:”)
print(“你的姓名是%s”%Name)
數據結構
字符串
len(str) # 長
str[n] # 返回索引n的值
str['起始':'結束':'步長'] # 切片: 不包含‘結束’;‘步長’為負數時倒序遍歷
str.find('xx') # 包含“xx”返回索引值,否報異常
str.rfind('xx') # 從右邊開始查
str.index('xx') # 包含“xx”返回索引值,否返回-1
str.count('xx') # 出現次數
str.count('xx' , 0 , len(str)) # 起始下標,終止下標
str.replace('a','A',n) # a替換為A,替換n個
str.split(',',n) # 以","分割,分割n次
str.split('\n') str. splitlines() # 以換行符分割
str.partition('xx') # 把str分割成三部分(xx前,xx,xx后)
str.ljust(n) # 左對齊,n:字符串總長度
str.rjust(n) # 右對齊
str.center(n) # 居中
str.lstrip() # 刪除左邊空白字符
str.rstrip() # 刪除右邊空白字符
str.strip() # 刪除兩邊空白字符
str.strip('x') # 刪除兩邊x字符
str = ['a', 'b', 'c']
'-'.join(str) # 按指定格式合并字符串:a-b-c
列表
# 創(chuàng)建
list = []
# 遍歷值
for i in list:print(i)
# 遍歷索引及值
for index,name in list:print(index,name)list.count('xx') # xx出現的次數
list.append('xx') # 添加元素到末尾
list.insert(index,'xx') # 指定坐標插入
list.extend(list2) # 添加集合到末尾
list[1] = 'xx' # 修改
del list[index] # 根據下標刪除元素
list.pop() # 刪除最后一個元素
list.pop('xx') # 刪除并返回索引值為xx的元素;list為空,會拋異常
list.remove('xx') # 刪除第一個出現的xx
list.sort(reverse=True) # 排序,默認升序;reverse=True降序
list.reverse() # 翻轉元素順序
x in/not in list # x是否存在
元祖
Python的元組與列表類似,不同之處在于元組的元素不能修改。元組使用小括號,列表使用防括號。
tt = 3*('a', 2)
print(tt)
('a', 2, 'a', 2, 'a', 2)# 與字符串一樣,元組可以進行連接、索引和切片等操作
t1 = (1, 'two', 3)
t2 = (t1, 3.25)
print(t2)
print((t1 + t2))
print((t1 + t2)[3])
print((t1 + t2)[2:5])('a', 2, 'a', 2, 'a', 2)
((1, 'two', 3), 3.25)
(1, 'two', 3, (1, 'two', 3), 3.25)
(1, 'two', 3)
(3, (1, 'two', 3), 3.25)
字典
dict 作為 Python 的關鍵字和內置函數,變量名不建議命名為 dict。
鍵一般是唯一的,如果重復最后的一個鍵值對會替換前面的,值不需要唯一。
值可以取任何數據類型,但鍵必須是不可變的,如字符串,數字或元組。
d = {key1 : value1, key2 : value2 }
d[key] = value # 修改、添加
del d[key] # 刪除
d.keys() # 返回所有key-列表
d.values() # 返回所有value-列表
d.items() # 返回所有key、value-元祖
d.has_key(key) # 是否包含key
# 排序
a = {8:'b',1:'c',2:'a'}
b = sorted(a.items(),key=lambda x:x[0])
b2 = sorted(a.items(),key=lambda x:x[1])
print('key排序:%s'%b)
print('value排序: %s'%b2)
列表推導式
將某種操作應用到序列中的一個值上。它會創(chuàng)建一個新列表
L = [x**2 for x in range(1,7)]
print(L)
[1, 4, 9, 16, 25, 36]列表推導中的for從句后面可以有一個或多個if語句和for語句,它們可以應用到for子句產生的值。這些附加從句可以修改第一個for從句生成的序列中的值,并產生一個新的序列。例如,
mixed = [1, 2, 'a', 3, 4.0]
print([x**2 for x in mixed if type(x) == int])
對mixed中的整數求平方,輸出:[1, 4, 9]
json序列化
json只適用簡單的數據類型(字典、列表、字符串)
json.dumps(data) # 序列化
json.loads(data) # 反序列化import json
data = {'name':'張三','age':18,
}with open('a.txt','w',encoding='utf8') as f:f.write(json.dumps(data))#json.dump(data,f) 等同上面寫法with open('a.txt','r',encoding='utf8') as f:data=json.loads(f.read())# data=json.load(f) 等同上面寫法print(data['name'])
pickle序列化
import pickle
# pickle 只適用python所有的數據類型
# 用法和json完全一致,把‘json’換成‘pickle’即可
# (注意讀寫時是二進制文件)
pickle.dumps(data) # 序列化
pickle.loads(data) # 反序列化
排序(sorted)
sort 與 sorted 區(qū)別:
sort 是應用在 list 上的方法,sorted 可以對所有可迭代的對象進行排序操作。
list 的 sort 方法返回的是對已經存在的列表進行操作,而內建函數 sorted 方法返回的是一個新的 list,而不是在原來的基礎上進行的操作。
sorted(iterable, key=None, reverse=False)
# iterable:指定要排序的list或者iterable
# key:用來進行比較的元素
# reverse:reverse = True 降序 , reverse = False 升序(默認)
時間模塊
格式輸出
strftim(‘格式’, struct_time元組) 格式化的字符串
strftim(‘格式化的字符串’,‘格式’) struct_time元組
# 獲取當前時間戳
time.time() # 返回:1970年1月1日午夜(歷元)至今過了n秒
# 獲取當前時間元組
time.localtime(time.time()) # 返回:struct_time元組
# 獲取格式化的時間
time.asctime(struct_time元組)
time.ctime(時間戳)# 格式化日期
time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
'2023-02-27 15:48:42'
time.strftime("%a %b %d %H:%M:%S %Y", time.localtime())
'Mon Feb 27 15:48:46 2023'
time.mktime(time.strptime("Wed May 22 15:52:51 2019","%a %b %d %H:%M:%S %Y"))
1558511571.0
struct_time元組:
序號 | 屬性 | 值 |
---|---|---|
0 | tm_year | 2008 |
1 | tm_mon | 1 到 12 |
2 | tm_mday | 1 到 31 |
3 | tm_hour | 0 到 23 |
4 | tm_min | 0 到 59 |
5 | tm_sec | 0 到 61 (60或61 是閏秒) |
6 | tm_wday | 0到6 (0是周一) |
7 | tm_yday | 1 到 366(儒略歷) |
8 | tm_isdst | -1, 0, 1, -1是決定是否為夏令時的旗幟 |
datatime
import datetime
i = datetime.datetime.now()
print ("當前的日期和時間是 %s" % i)
print ("ISO格式的日期和時間是 %s" % i.isoformat() )
print ("當前的年份是 %s" %i.year)
print ("當前的月份是 %s" %i.month)
print ("當前的日期是 %s" %i.day)
print ("dd/mm/yyyy 格式是 %s/%s/%s" % (i.day, i.month, i.year) )
print ("當前小時是 %s" %i.hour)
print ("當前分鐘是 %s" %i.minute)
print ("當前秒是 %s" %i.second)
timedelta(時間的加減)
from datetime import date,timedelta
time = date(2019,4,17)+ timedelta(days=2) # 加兩天
time = date(2019,4,17)+ timedelta(days=-1) # 減兩天
random模塊-隨機數
import random
# 隨機0-1浮點數
random.random()
# 隨機1-3浮點數
random.uniform(1,3)
# 隨機1-10整數
random.randint(1,10)
# 隨機1-10整數
random.randrange(1,10)
# 列表、字符串、元組隨機
random.choice('hello')
random.choice(['hello','hah'])
# 隨機取兩位
random.sample('hello',2)
# 用于將一個列表中的元素打亂順序
# 值得注意的是使用這個方法不會生成新的列表,只是將原列表的次序打亂
list=[1,2,3,4,5]
random.shuffle(list)
print(list)
OS模塊
os.path.exists(‘文件名’) 判斷是否存在
os.rename(’源名’,’新名’) 文件重命名
os.remove(’文件名’) 刪除文件
os.rmdir(‘文件夾’) 刪除文件夾
os.mkdir(‘文件夾名’) 創(chuàng)建文件夾
os.getcwd() 獲取當前目錄
os.chdir(‘path’) 切換目錄
os.listdir(‘path’) 獲取目錄列表
os.remove() 刪除文件
os.rename() 重命名文件
os.walk() 生成目錄樹下的所有文件名
os.chdir() 改變目錄
os.mkdir/makedirs 創(chuàng)建目錄/多層目錄
os.rmdir/removedirs 刪除目錄/多層目錄
os.listdir() 列出指定目錄的文件
os.getcwd() 取得當前工作目錄
os.chmod() 改變目錄權限
os.path.basename() 去掉目錄路徑,返回文件名
os.path.dirname() 去掉文件名,返回目錄路徑
os.path.join() 將分離的各部分組合成一個路徑名
os.path.split() 返回(dirname(),basename())元組
os.path.splitext() (返回 filename,extension)元組
os.path.getatime\ctime\mtim 分別返回最近訪問、創(chuàng)建、修改時間
os.path.getsize() 返回文件大小
os.path.exists() 是否存在
os.path.isabs() 是否為絕對路徑
os.path.isdir() 是否為目錄
os.path.isfile() 是否為文件
加密
import hashlib# md5加密
m = hashlib.md5()
m.update(b"Hello")
print(m.hexdigest())
===============================================================
# sha512加密
s = hashlib.sha512()
s.update(b"Hello")
print(s.hexdigest())
===============================================================
# 創(chuàng)建一個key和內容,再進行處理后加密
import hmac
h = hmac.new('key'.encode(encoding="utf-8"),'msg'.encode(encoding="utf-8"))
print(h.digest()) # 十進制加密
print(h.hexdigest())# 十六進制加密
反射
通過字符串映射或修改程序運行時的狀態(tài)、屬性、方法。
把字符串反射成內存中的對象地址。
"""
1.什么是反射:把字符映射到實例的變量或實例的方法,然后可以去執(zhí)行調用、修改反射的本質(核心):基于字符串的事件驅動,利用字符串的形式去操作對象/模塊中成員(方法、屬性)
2.反射的四個重要方法1)getattr獲取對象屬性/對象方法2)hasattr判斷對象是否有對應的屬性及方法3)delattr刪除指定的屬性4)setattr為對象設置內容
"""
class TestObject:def __init__(self, name, age):self.name = nameself.age = agedef test(self):print("執(zhí)行test方法")def a():print("類的外部方法")if __name__ == '__main__':"""1.getattr 獲取對象屬性、對象方法"""xiaoyu = TestObject("小于", 20)# 獲取對象的屬性print(getattr(xiaoyu, "name"))# 獲取對象的方法result = getattr(xiaoyu, "test")print(type(result))result()"""2.hasattr 判斷對象是否有對應的屬性、方法"""if hasattr(xiaoyu, "address"):print(getattr(xiaoyu, "address"))if hasattr(xiaoyu, "name"):print(getattr(xiaoyu, "name"))"""3.delattr 刪除屬性"""# delattr(xiaoyu,"name")"""4.setattr 為對象設置內容"""# 修改屬性的值setattr(xiaoyu, "name", "liuwei")print(getattr(xiaoyu, "name"))# 修改方法setattr(xiaoyu, "test11", a)getattr(xiaoyu, "test11")()# 相當于增加了test11方法xiaoyu.test11()
"""
實現某個業(yè)務,定義類,類里面封裝了很多方法,提供一個統(tǒng)一的入口能夠調用各種方法
業(yè)務:登錄 退出 注冊 注銷
"""
class Test:func_list = ["login", "loginOut", "register", "delete"]def login(self):print("這是登錄")def loginOut(self):print("這是退出")def register(self):print("這是注冊")def delete(self):print("這是注銷")# 1.login 2.loginOut 3.register 4.deletedef run(self, num):getattr(self, self.func_list[num - 1])()num = int(input("請輸入你的操作(1.login 2.loginOut 3.register 4.delete):"))
Test().run(num)
open 文件
文件的輸入/輸出都是相對于內存;
in:輸入,讀入。從硬盤讀到內存。
out:輸出。從內存寫到硬盤。
file = open('/path/file', 'w')
# 寫入
str = file.write('xx') # 寫入(文件不存在,會新建)
str = file.writelines('set') # 將集合中的每個元素作為一個單獨的行寫入
# 讀取
str = file.read() # 讀取全部
str = file.read(num) # 讀取num字節(jié)
set = file.readlines() # 按行讀取全部,并返回一個列表集合
file.readline() # 讀取一行
# 光標
num = file.tell() # 光標所在的位置
file.seek(0) # 指定光標位置(0:開始位置)file.close() # 關閉
import shutil
shutil.copyfile('源文件路徑', '目的路徑') # 復制文件
shutil.move('源文件路徑', '目的路徑') # 移動文件
# with語句會自動調用close()方法
with open('/path/file', 'r') as f:print(f.read())
模式 | 描述 |
---|---|
r | 以只讀方式打開文件。文件的指針將會放在文件的開頭。這是默認模式。 |
rb | 以二進制格式打開一個文件用于只讀。文件指針將會放在文件的開頭。這是默認模式。一般用于非文本文件如圖片等。 |
r+ | 打開一個文件用于讀寫。文件指針將會放在文件的開頭。 |
rb+ | 以二進制格式打開一個文件用于讀寫。文件指針將會放在文件的開頭。一般用于非文本文件如圖片等。 |
w | 打開一個文件只用于寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。 |
wb | 以二進制格式打開一個文件只用于寫入。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。一般用于非文本文件如圖片等。 |
w+ | 打開一個文件用于讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。 |
wb+ | 以二進制格式打開一個文件用于讀寫。如果該文件已存在則將其覆蓋。如果該文件不存在,創(chuàng)建新文件。一般用于非文本文件如圖片等。 |
a | 打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創(chuàng)建新文件進行寫入。 |
ab | 以二進制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。也就是說,新的內容將會被寫入到已有內容之后。如果該文件不存在,創(chuàng)建新文件進行寫入。 |
a+ | 打開一個文件用于讀寫。如果該文件已存在,文件指針將會放在文件的結尾。文件打開時會是追加模式。如果該文件不存在,創(chuàng)建新文件用于讀寫。 |
ab+ | 以二進制格式打開一個文件用于追加。如果該文件已存在,文件指針將會放在文件的結尾。如果該文件不存在,創(chuàng)建新文件用于讀寫。 |
屬性 | 描述 |
---|---|
file.closed | 返回true如果文件已被關閉,否則返回false。 |
file.mode | 返回被打開文件的訪問模式。 |
file.name | 返回文件的名稱。 |
file.softspace | 如果用print輸出后,必須跟一個空格符,則返回false。否則返回true。 |
函數
函數是組織好的,可重復使用的,用來實現單一或相關功能的代碼段。
可變參數
參數必須加*,傳遞過去之后,會組合成元組
*組成元組,**組成字典
*args:表示可以傳多個值
list = [1,2,3,4] # 參數是列表時,調用加* fun(*list)
# 參數必須加 *,傳遞過去之后,會組合成元組
# * 組成元組,**組成字典
def A(a, b, c=1, *d, **e):print(11, a)print(22, b)print(33, c)print(44, d)print(55, e)A(1, 2, 33, 44, 55, bb='bb')11 1
22 2
33 33
44 (44, 55)
55 {'bb': 'bb'}
全局變量
在代碼塊中,首先是從當前代碼中找是否有這樣名字的變量如果有,拿來用,如果沒有,再從全局變量中找是否有。
global 變量名:
? 1、先在全局中找是否有這個變量
? 2、如果有,拿來用,如果沒有,創(chuàng)建并放到全局中,如果想在函數中修改全局變量,將變量聲明位global
建議:全局變量命名規(guī)則g_num
例: global g_num (不能直接賦值,先聲明)
遞歸
"""
1、函數本身調用本身
2、有反復執(zhí)行的過程
3、有退出的條件
"""
#輸入一個數字求階乘
num=int(input('輸入一個數字求階乘:'))
def f1(num):if num==1:return 1return(num*f1(num-1))
set=f1(num)
print(set)
類
三大特征:封裝、繼承、多態(tài)
魔法方法
class Person(object):# 實例化類時調用# 創(chuàng)建對象時同時給對象賦值屬性# 在java里叫構造方法def __init__(self, name):print('__init__')self.name = name# 創(chuàng)建實例時def __new__(cls, name):print('__new__')return object.__new__(cls)# 在對象轉成字符串的時候(打印對象時)調用def __str__(self):print('__str__')return "name is : %s" % (self.name)# 通過'對象()' 或 '類()()'觸發(fā)def __call__(self):print('__call__')# 會在對象被垃圾回收的時候被調用# 釋放資源:比如文件的連接,數據庫的連接def __del__(self):print('__del__')A = Person('張三')
print(A)
A()
# 輸出
__new__
__init__
__str__
name is : 張三
__call__
__del__
對象的引用數量
import sys
sys.getrefcount('對象')
封裝
'''
私有屬性和方法:__屬性名、__方法名
獲取:1、set、get方法 2、實例化對象名._類名__私有屬性名
'''
class Person(object):def __init__(self):self.__name = Nonedef getname(self):return self.__namedef setname(self, name):self.__name = namedef delname(self):del self.__namename = property(getname, setname, delname, "說明。。")print(help(Person.name)) # 說明。。
A = Person()
print(A.getname()) # None
A.setname('張三')
print(A.getname()) # 張三
#####################################
# 將 property 函數用作裝飾器
class Person(object):def __init__(self):self.__name = None@propertydef name(self):return self.__name@name.getterdef name(self, name):self.__name = name@name.deleterdef name(self):del self.__nameA = Person()
print(A.getname())
A.setname('張三')
print(A.getname())
類屬性、實例屬性
類屬性:直接在類中定義的,與方法平齊,不在方法里的屬性。
實例屬性:方法里通過self.屬性的都是實例屬性。
類方法、靜態(tài)方法
類方法(cls) : @classmethod
靜態(tài)方法() : @staticmethod
形式上的區(qū)別:實例方法隱含的參數為類實例self,而類方法隱含的參數為類本身cls。 靜態(tài)方法無隱含參數,主要為了類實例也可以直接調用靜態(tài)方法。
邏輯上:類方法被類調用,實例方法被實例調用,靜態(tài)方法兩者都能調用。主要區(qū)別在于參數傳遞上的區(qū)別,實例方法悄悄傳遞的是self引用作為參數,而類方法悄悄傳遞的是cls引用作為參數,靜態(tài)方法沒有類似 self、cls 這樣的特殊參數
class Person:# 類屬性name = '張三'# 普通方法/實例方法def myName(self):print('實例方法.','訪問類屬性:',self.name)# 類方法,可以訪問類屬性和類方法@classmethoddef className(cls):print('類方法.','訪問類屬性:', cls.name)# 靜態(tài)方法,無法調用任何類屬性和類方法@staticmethoddef staticName():print('靜態(tài)方法.','不能訪問類屬性')P = Person()
# 實例訪問
P.name = '李四'
P.myName() # 實例方法. 訪問類屬性: 李四
P.className() # 類方法. 訪問類屬性: 張三
P.staticName() # 靜態(tài)方法. 不能訪問類屬性
# 類訪問
print(Person.name) # 張三
# Person.myName() # 類不能訪問 實例方法
Person.className() # 類方法. 訪問類屬性: 張三
Person.staticName() # 靜態(tài)方法. 不能訪問類屬性
繼承
將共性的內容放在父類中,子類只需要關注自己特有的內容。(符合邏輯習慣,利于擴展)
重寫父類方法:(子對父)子類中和父類同名的方法,子類的方法會覆蓋父類的方法。
# 返回該類的所有父類:類名.__mor__
# 調用父類中的屬性
def __init__(self):Father.__init__(self)
# 子類調用父類的方法
super().父類方法()
父類名.父類方法(self)# 多繼承(從左向右找)
class C2:def f2(self):print('C2...f2')def hehe(self):print('C2...hehe')class C3:def f3(self):print('C3...f3')def haha(self):print('C3...haha')def hehe(self):print('C3...hehe')class C4(C2):def f4(self):print('C4...f4')def haha(self):print('C4...haha')class C5(C4, C3):def f5(self):print('C5...f5')def hehe(self):print('C5...hehe')c5 = C5()
c5.haha() # C4...haha
c5.hehe() # C5...hehe
判斷是否為子類、實例
# A是否為B的子類/A是否為B的實例
Issubclass( A , B )
多態(tài)
一個對象在不同的情況下顯示不同的形態(tài)。因python是弱類型語言,對類型沒有限定。Python中不完全支持多態(tài),但是多態(tài)的思想,也是能體現的。
變量的類型永遠都是通過右側的值判斷,方法中的參數傳遞任何值都行,但要考慮方法內部的業(yè)務邏輯。
'''
多態(tài):1、父類作為參數,可以傳遞父類和子類對象。2、接口作為參數,只能傳遞實現對象。所以有兩種理解:
1、pyhton不支持多態(tài):python是弱類型,沒有類型限定,無法區(qū)分父與子,或者說接口和實現類
2、python處處是多態(tài):python是弱類型,沒有類型限定,傳遞任何內容都行
'''
對象的創(chuàng)建過程
'''
1.調用__new__方法,在object中返回一個對象;
2.調用__init__方法,將1中的返回對象傳遞給__init__中的selif;
3.返回這個對象;
'''
class Dog(object):def __init__(self):print('__init__')def __new__(cls):print('__new__')obj = object.__new__(cls)print('obj: %s, cls: %s' % (obj, cls))return objwangcai = Dog()
print(wangcai)# 輸出
__new__
obj: <__main__.Dog object at 0x0093D3D0>, cls: <class '__main__.Dog'>
__init__
<__main__.Dog object at 0x0093D3D0>
單例模式
class F(object):# 創(chuàng)建對象def __new__(cls):return object.__new__(cls)a = F()
b = F()
print(a == b) # False
########################################################
class F2(object):# 定義一個變量存儲new處理的對象a = Nonedef __new__(cls):# 如果對象為None,調用父類方法,創(chuàng)建對象,并賦值給aif cls.a == None:cls.a == object.__new__(cls)# 對象不為None,返回第一次創(chuàng)建的對象return cls.aaa = F2()
bb = F2()
print(aa == bb) # True
異常
Exception:所有異常的父類
try:# …可能出現異常的代碼塊
except Exception [as xx]: # 有異常執(zhí)行;xx 異常的基本信息
# except (NameErrot, IOError) as xx: # 捕獲多個異常# …處理異常print(xx)
else: # 沒異常執(zhí)行,可以不用pass
finally: # 無論有沒有異常都會執(zhí)行# 有沒有異常都要執(zhí)行的代碼
自定義異常
1、必須繼承異常類
2、自己通過 raise 觸發(fā)自定義異常
class XxError(Exception):# 不顯示異常# silent_variable_failure = True def __init__(self,m):super().__init__() self.m=m
class SexErrot(Exception):def __init__(self, msg):self.msg = msgdef fun():sex = input('請輸入性別:')if sex not in ['男', '女']:raise SexErrot('性別只能是男女!') # raise 拋出異常try:fun()
except Exception as ex: # ex 相當于ex.msgprint(ex)
包
# 包將有聯系的模塊組織在一起,即放在同一個文件夾下,并且在這個文件夾創(chuàng)建一個同名字為__init__.py的文件,那么這個文件就稱之為包。
# __init__.py :導入的同時,直接運行import 包名.文件名(模塊).函數名 [as 別名]
引用:包名.文件名(模塊).函數名from 包名 import * 或者 [模塊1,模塊2…] # *表示到py文件
引用:文件名(模塊).函數名from 模塊 import * # 將模塊里的所有內容導入
引用:函數名
深、淺拷貝
? 在Python中每個變量都有自己的標識、類型和值。每個對象一旦創(chuàng)建,它的標識就絕對不會變。一個對象的標識,我們可以理解成其在內存中的地址。is()
運算符比較的是兩個對象的標識;id()
方法返回的就是對象標識的整數表示。
is比較對象的標識;
==`運算符比較兩個對象的值(對象中保存的數據)。
1、賦值其實只是傳遞對象引用,引用對象id是一樣的。
2、淺拷貝是指拷貝的只是原始對象元素的引用,換句話說,淺拷貝產生的對象本身是新的,但是它的內容不是新的,只是對原對象的一個引用。 淺拷貝只是拷貝數據的第一層,不會拷貝子對象。
3、深拷貝是指完全拷貝原始對象,而且產生的對象是新的,并且不受其他引用對象的操作影響。
a = [1, 2, 3]
b = [1, 2, 3]print(id(a)) # 32096712
print(id(b)) # 32099848print(a == b) # True
print(a is b) # False# is 是比較兩個應用是否指向同一個對象(引用比較)
# == 是比較連個對象是否相等
結論:
- 在不可變數據類型中,深淺拷貝都不會開辟新的內存空間,用的都是同一個內存地址。
- 在存在嵌套可變類型的數據時,深淺拷貝都會開辟新的一塊內存空間;同時,不可變類型的值還是指向原來的值的地址。
- 不同的是:在嵌套可變類型中,淺拷貝只會拷貝最外層的數據,而深拷貝會拷貝所有層級的可變類型數據。
生成器
列表生成器
>>> [0,1,2,3,4,5,6,7,8,9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> ret = [x for x in range(10)]
>>> ret
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> ret = [(x,y) for x in range(3) for y in range(4)]
>>> ret
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
generator 生成器
相當于保存了一個算法,只有調用的時候使用。
好處:防止數據量過大的內存溢出!
ge=(x for x in range(3))
print(ge) # <generator object <genexpr> at 0x01EDDAA8> (可遍歷)
# 沒有下一個值時,報StopIteration異常
print(next(ge)) # 0 獲取下一個值
print(ge.__next__()) # 1 獲取下一個值,同next(ge)
生成器寫法
# 一旦數據量大了,可能造成內存溢出
def fib(times):n = 0a, b = 0, 1while n < times:print(b)a, b = b, a + bn += 1return 'done'ret = fib(4) # 1 1 2 3
print(ret) # done# 并沒有完全保存值,而是通過算法每次計算出需要的值,這樣一旦是大數據,也不會造成內存溢出
def fib(times):n = 0a, b = 0, 1while n < times:yield b # 函數遇到y(tǒng)ield會停止運行,直到next()輸出或者遍歷a, b = b, a + bn += 1return 'over'ret = fib(4)
print(ret) # <generator object fib at 0x0239DA70>
print(next(ret)) # 1
send用法
# 相當于可以傳值的__next__()
# 向生成器中傳遞參數,用一個變量=yield … 接收傳遞的參數
def fun():for i in range(10):temp = yield i # temp 默認為Noneif temp%2 == 0:print('xx')else:print('yy')gen = fun()
print(gen)
print(next(gen))
print(gen.send(3)) # send 傳參給temp,可以添加一些邏輯
print(gen.send(6))# 輸出
<generator object fun at 0x0197AB18>
0
yy
1
xx
2
迭代器
可以被next()函數調用并不斷返回下一個值的對象稱為迭代器;
可以使用iter(object),把對象變成迭代器;
優(yōu)點:可以減少使用內存。
# 是否可迭代
import collections isinstance(object, collections.Iterable) # True/False
閉包
在函數內部再定義一個函數,并且這個函數用到了外部函數的變量,那么這個函數以及用到的一些變量稱之為閉包。
# 閉包結構
def outer(xx):passdef inner(yy):passreturn inner
# inner 函數里一定存在對outer 函數變量的引用# 本來如果outer執(zhí)行完后,outer內的變量會被垃圾回收機制回收。
# 但是一旦在閉包中,python會發(fā)現,內部函數引用了外部函數的變量,這個變量不會被立即銷毀。
# 只有內部對象執(zhí)行后才會銷毀。這樣就在內部函數中保存了外部函數的一些變量,進行一些業(yè)務邏輯。
裝飾器
在運行原來代碼的基礎上,加入一些功能;比如權限的驗證等;
不修改原來的代碼,進行功能的擴展。比如:java中的動態(tài)代理;
裝飾器的功能
1.引入日志
2.函數的執(zhí)行時間
3.執(zhí)行函數前預備處理
4.執(zhí)行函數后清理功能
5.權限驗證等場景
6.緩存
單個裝飾器
def outer(fn):print('outer...')def inner():print('inner...')# 可以在fn前后加邏輯fn()print(inner)return inner@outer # 相當于 myFunc=outer(myFunc)
def myFunc():print('myFunc...')myFunc()# 輸出
outer...
<function outer.<locals>.inner at 0x01316148>
inner...
myFunc...
多個裝飾器
# 如果裝飾器運行完畢后還有裝飾器,交給下一個裝飾器;
# 直到沒有裝飾器了,執(zhí)行功能代碼def decorator1(fn):def inner1():print('decorator1_inner1 begin...')fn()print('decorator1_inner1 end...')return inner1def decorator2(fn):def inner2():print('decorator2_inner2 begin...')fn()print('decorator2_inner2 end...')return inner2@decorator1
@decorator2
def myFunc():print('myFunc...')myFunc()# 輸出
decorator1_inner1 begin...
decorator2_inner2 begin...
myFunc...
decorator2_inner2 end...
decorator1_inner1 end...
帶參數的裝飾器
# 裝飾帶參數的函數
def timeFun(func):def wrappedfunc(*args, **kwargs):func(*args, **kwargs)return wrappedfunc@timeFun
def foo(a, b, c):print(a+b)# 為了傳遞一些參數,再通過這些參數完成一些業(yè)務邏輯
def decorator(num):def timeFun(func):def wrappedfunc(*args, **kwargs):# 可以添加一些業(yè)務邏輯代碼if num % 2 == 0:print('驗證權限...')else:print('記錄日志...')# 調用最終想要調用的功能方法return func(*args, **kwargs)return wrappedfuncreturn timeFun@decorator(4) # 裝飾器傳參
def foo():print('foo...')foo() # 輸出
驗證權限...
foo...
帶返回值的裝飾器
def timeFu(func):def wrappedfunc(*args, **kwargs):return func(*args, **kwargs)return wrappedfunc@timeFu
def foo(a,b):return a+bret = foo(1,2)
print(ret) # 3
類裝飾器
'''
裝飾器函數其實是這樣一個接口約束,它必須接受一個callable對象作為參數,然后返回一個callable對象。
一般callable對象都是函數,但也有例外;只要某個對象重寫了__call__()方法,那么這個對象就是callable的。
callable:可調用的
'''class Test():def __call__(self, *args, **kwargs):print('call me!')t = Test()
t()
class Test(object):def __init__(self, fun):print('初始化...')print('fun name is %s'%fun.__name__)self.__fun = fundef __call__(self, *args, **kwargs):print('裝飾器中的功能...')self.__fun@Test
def test():print('...test...')test() # 如果注釋這句,重新運行,依然會看到"初始化..."
進程(Process)
進程是一堆資源(一個程序)的集合;
進程要操作CPU,必須要先創(chuàng)建一個線程;
多進程中,每個進程中所有數據(包括全局變量)都各擁有一份,互不影響。
os.fork( )
'''
加載os模塊后,首先os.fork()函數生成一個子進程,返回值pid有兩個,一個為0, 用以表示在子進程當中,一個為大于0的整數,表示在父進程,這個常數正是子進程的pid.
if pid == 0,在子進程當中os.getpid()是子進程的pid,os.getppid()是父進程pid
if pid >0 ,在父進程當中,os.getpid()是父進程的pid,os.fork()返回的就是子進程的pid
'''
import os
print('進程(%s)開始...'% os.getpid())
# 只適用于Unix/Linux/Mac操作系統(tǒng)
pid = os.fork()
if pid == 0:print('我是子進程(%s)and 我的父進程是(%s)'%(os.getpid(),os.getppid()))
else:print('(%s)創(chuàng)建了子進程(%s)'%(os.getpid(),pid))
multiprocessing
from multiprocessing import Process
def run(n):print('run.......',n)if __name__ == '__main__':print('1......')# 創(chuàng)建了一個子進程對象 狀態(tài):新建狀態(tài)p = Process(target=run,args='a',name='張三')# 啟動:并執(zhí)行run方法 狀態(tài):就緒狀態(tài)p.start()# 進程的名字,不傳有默認值print(p.name)# join等待前面的進程執(zhí)行完p.join()print('2......')
Process常用方法
is_alive():判斷進程實例是否還在執(zhí)行
join([timeout]):等待進程實例執(zhí)行結束(等待多少秒)
start():啟動(創(chuàng)建子進程)
treminate():不管任務是否完成,立即終止
name參數:當前進程實例別名,默認Process-N
pid:當前進程實例PID
繼承Process創(chuàng)建進程
from multiprocessing import Process
class Process_Class(Process):def __init__(self,A):Process.__init__(self) # 初始化使用父類屬性和方法self.A = Adef run(self):...
Pool(進程池)
進程池里的任務不需要自己start() !
進程池里的任務,不是按照放入的順序的執(zhí)行的!
哪個進程執(zhí)行哪個任務,不能手動干預!
'''
1、第一步:設置進程池中進程的數量 po = Pool(n)進程池的數字根據硬件環(huán)境進行設定,一般設置為cpu的數量
2、第二步:放任務 po.apply_async(方法名, 參數--元祖) ---異步po. apply() ---同步(單任務,一般不用)
3、第三步:關閉進程池 po.close() 關閉進程池,關閉后po不再接收新的請求
4、第四步:開始執(zhí)行 po.join()等待po中所有子進程執(zhí)行完成,必須放在close語句之后進程池中的進程開始執(zhí)行任務如果任務大于進程的數量,多余的任務等待一旦某個進程完成當下的任務,從等待的任務中隨機找一個任務執(zhí)行
'''
from multiprocessing import Pooldef worker1(msg):print(msg)def worker2(msg):print(msg)if __name__ == '__main__':po = Pool(2)# callback 回調,執(zhí)行完worker后執(zhí)行funpo.apply_async(worker1,(1,) , callback=fun)po.apply_async(worker2,(2,))po.close()# 如果不join,那么程序直接關閉po.join() # 進程池中進程執(zhí)行完畢后再關閉,需要放在close后
進程鎖
'''
進程數據相互獨立,按理不需要鎖;
這個鎖存在的意義就是:防止打印顯示時出錯,因為它們共享一個屏幕。
'''
from multiprocessing import Process, Lock
def f(l, i):l.acquire()print('hello world', i)l.release()
if __name__ == '__main__':lock = Lock()for num in range(100):Process(target=f, args=(lock, num)).start()
Queue(進程之間的通信)
q = mulitprocessing.Queue(n)
q.put('a') # 放入
q.put('b') # n等于2,放3個會阻塞
q.get() # 獲取先進先出# 進程實現數據讀寫
from multiprocessing import Process, Queue
import os, time, random
# 寫數據
def write(q):print('Process to write: %s' % os.getpid())for value in ['A', 'B', 'C']:print('Put %s to queue...' % value)q.put(value)time.sleep(random.random())
# 讀數據
def read(q):print('Process to read: %s' % os.getpid())while True:value = q.get(True)print('Get %s from queue.' % value)if __name__=='__main__':# 父進程創(chuàng)建Queue,并傳給各個子進程q = Queue(2)pw = Process(target=write, args=(q,))pr = Process(target=read, args=(q,))# 啟動子進程pw,寫入pw.start()# 啟動子進程pr,讀取pr.start()# 等待pw結束pw.join()# pr進程里是死循環(huán),無法等待其結束,只能強行終止pr.terminate()
Pipe(進程之間的通信)
from multiprocessing import Process, Pipe
def f(conn):# 向父進程發(fā)數據conn.send('hello from child')conn.send('hello from child2')# 接收父進程數據print("from parent:",conn.recv())conn.close()if __name__ == '__main__':# Pipe()返回兩個參數表示管道的兩頭,用以連接父子進程parent_conn, child_conn = Pipe()# 把其中一頭傳給子進程p = Process(target=f, args=(child_conn,))p.start()# 接收子進程數據print(parent_conn.recv())print(parent_conn.recv())# 向子進程發(fā)數據parent_conn.send("Hello!!")p.join()
線程(threading)
'''
是操作系統(tǒng)的最小的調度單位,是一串指令的集合;
python的多線程不適合CPU密集操作型的任務,適合IO操作密集型的任務(IO操作不占用CPU,計算暫用CPU);
多線程中全局變量共享!
'''
# 查看當前線程
threading.current_thread()
# 查看當前活動線程的個數
threading.active_count()
# 把當前線程設置為守護線程
# 相當于仆人,守護線程跟隨主線程停止
t.setDaemon(True)
# 當前線程執(zhí)行完,再繼續(xù)執(zhí)行后面線程
t.join()
創(chuàng)建
import threading
import time
def say(name):print(name)time.sleep(1)if __name__ == "__main__":# 存線程實例t_objs = []for i in range(5):# 創(chuàng)建子線程,子線程執(zhí)行的功能方法是sayt = threading.Thread(target=say, args=("張三",))# 啟動線程,即讓線程開始執(zhí)行t.start()# 為了不阻塞后面線程的啟動,不在這里join,先放到一個列表里t_objs.append(t)# 循環(huán)線程實例列表,等待所有線程執(zhí)行完畢for t in t_objs: t.join()
length = len(threading.enumerate()) # 查看線程的數量6
信號量(semaphore)
import threading, time
def run(n):semaphore.acquire()time.sleep(1)print("run the thread: %s\n" % n)semaphore.release()if __name__ == '__main__':# 最多允許5個線程同時運行# 每執(zhí)行完一個線程,就加入一個semaphore = threading.BoundedSemaphore(5)for i in range(22):t = threading.Thread(target=run, args=(i,))t.start()
queue隊列
q = queue.Queue(maxsize=n) # 先入先出
q = queue.LifoQueue(maxsize=n) # 后入先出
q = queue.PriorityQueue(maxsize=n) # 存儲(put)數據時,設置優(yōu)先級
q.put((-1,"數據")) # 優(yōu)先級:數字,字符串。。# 生產者消費者模型案例
import threading,time,queue
q = queue.Queue(maxsize=5)
def Producer(name):count = 1while True:q.put("骨頭%s" % count)print("[%s]生產了[骨頭%s]"%(name,count))count +=1time.sleep(0.1)def Consumer(name):#while q.qsize()>0:while True:print("[%s] 取到[%s] 并且吃了它..." %(name, q.get()))time.sleep(1)p = threading.Thread(target=Producer,args=("生產者",))
c = threading.Thread(target=Consumer,args=("消費者01",))
c1 = threading.Thread(target=Consumer,args=("消費者02",))
p.start()
c.start()
c1.start()
Event
'''
用于線程間通信(True/False)
event = threading.Event()
event對象維護一個內部標志(標志初始值為False),通過event.set()將其置為True
wait(timeout)則用于堵塞線程直至Flag被set(或者超時,可選的)
isSet()、is_set()用于查詢標志位是否為True
clear()則用于清除標志位(使之為False)
'''# 紅綠燈案例
import threading,time
event = threading.Event()
def lighter():count = 0# event對象維護一個內部標志(初始值為False),通過set()將其置為True# 標志為True,表示綠燈event.set()while True:if count >5 and count < 10: #改成紅燈# clear()則用于清除標志位(使之為False)event.clear()# "\033[41;1m內容\033[0m" 渲染字體顯示顏色print("\033[41;1m紅燈亮著....\033[0m")elif count >10:event.set() #變綠燈count = 0else:print("\033[42;1m綠燈亮著....\033[0m")time.sleep(1)count +=1def car(name):while True:# is_set()/isSet()用于查詢標志位是否為Trueif event.is_set(): # True代表綠燈print("[%s] running..."% name )time.sleep(1)else:print("[%s] 看到紅燈 , waiting...." %name)# wait(timeout)則用于堵塞線程直至標志位被設置(setevent.wait()print("\033[34;1m[%s] 綠燈亮了, start going...\033[0m" %name)light = threading.Thread(target=lighter,)
light.start()car = threading.Thread(target=car,args=("汽車",))
car.start()
鎖(Lock)
import threading
# 創(chuàng)建對象
myLock = threading.Lock()
print(myLock)
print('1...')
# 鎖住,如果此鎖,已經鎖了,如果再鎖,會阻塞,直到開鎖了,才能再鎖
myLock.acquire()
print('2...')
# 開鎖,如果鎖住了,可以開鎖。如果沒鎖,直接開,報錯
myLock.release()
threadloca
'''
threadlocal就有倆功能:1、將各自的局部變量綁定到各自的線程中2、局部變量可以傳遞了,而且并沒有變成形參
'''
import threading
# 創(chuàng)建全局ThreadLocal對象:
local_school = threading.local()
def process_student():# 獲取當前線程關聯的student:std = local_school.studentprint('Hello, %s (in %s)' % (std, threading.current_thread().name))def process_thread(name):# 綁定ThreadLocal的student:local_school.student = nameprocess_student()t1 =threading.Thread(target=process_thread,args=('yongGe',),name='Thread-A')
t2 =threading.Thread(target=process_thread, args=('老王',), name='Thread-B')
t1.start()
t2.start()
線程的幾種狀態(tài)
? 多線程程序的執(zhí)行順序是不確定的。當執(zhí)行到sleep語句時,線程將被阻塞(Blocked),到sleep結束后,線程進入就緒(Runnable)狀態(tài),等待調度。而線程調度將自行選擇一個線程執(zhí)行。代碼中只能保證每個線程都運行完整個run函數,但是線程的啟動順序、run函數中每次循環(huán)的執(zhí)行順序都不能確定。
*參考:https://www.mianshigee.com/note/detail/19137chn/*
進程、線程的區(qū)別
一個程序至少有一個進程,一個進程至少有一個線程。
線程不能獨立執(zhí)行,必須依存在進程中;
線程是進程的一個實體,是CPU調度個分派的基本單位,它是比進程更小的能獨立運行的基本單位。
線程自己基本上不擁有系統(tǒng)資源,只擁有一點在運行中必不可少的資源(如程序計算器,一組寄存器和棧),但它可與同屬一個進程的其他線程共享進程所擁有的全部資源。
線程的劃分小于進程(資源比進程少),使得多線程程序的并發(fā)性高 ;
區(qū)別 | 進程 | 線程 |
---|---|---|
開銷 | 每個經常都有獨立的代碼和數據空間(程序上下文),進程間的切換會有較大的開銷 | 線程可以看成是輕量級的進程,同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換的開銷小 |
所處環(huán)境 | 在操作系統(tǒng)中能同事運行多個任務(程序) | 在同一應用程序中有多個順序流同時執(zhí)行 |
分配內存 | 系統(tǒng)在運行時會為每個進程分配不通的內存區(qū)域 | 除了CPU外,不會為線程分配內存(線程所使用的資源是它所屬進程的資源),線程組只能共享資源 |
包含關系 | 沒有線程的進程是可以被看作單線程的,如果一個進程內擁有多個線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共同完成的 | 線程是進程的一部分,所以線程有的時候被稱為是輕量級進程 |
協程
比線程更小的執(zhí)行單元,又稱微線程;協程是一種用戶態(tài)的輕量級線程。
符合以下條件就能稱之為協程:
? 1、必須在只有一個單線程里實現并發(fā);
? 2、修改共享數據不需加鎖;
? 3、用戶程序里自己保存多個控制流的上下文棧;
? 4、一個協程遇到IO操作自動切換到其它協程;
'''
協程的切換只是單純的操作CPU上下文,比線程的切換更快速;
1:N 模式:一個線程作為一個容器放置多個協程;
IO密集型的程序和CPU密集型程序。
'''
import gevent
def func1():print('...func1...')
# 模仿耗時操作gevent.sleep(2) print('...func1_1...')def func2():print('...func2...')gevent.sleep(1)print('...func2_2...')gevent.joinall([# 創(chuàng)建并開始協程gevent.spawn(func1),gevent.spawn(func2),
])# 輸出
...func1...
...func2... # fun1耗時自動切換到fun2, fun2耗時自動切換到fun1
...func2_2...# fun1耗時2s還未結束,又切換到fun2
...func1_1...
# 整體執(zhí)行完成只需要2秒
協程-簡單爬蟲
from urllib import request
import gevent,time
from gevent import monkey
# 把當前程序的所有的IO操作給我單獨的做上標記
# 讓gevent知道該程序有哪些IO操作
monkey.patch_all()
def f(url):print('GET: %s' % url)resp = request.urlopen(url)data = resp.read()print('%d bytes received from %s.' % (len(data), url))urls = ['https://www.python.org/','https://www.yahoo.com/','https://github.com/' ]
time_start = time.time()
for url in urls:f(url)
print("串行cost",time.time() - time_start)async_time_start = time.time()
gevent.joinall([gevent.spawn(f, 'https://www.python.org/'),gevent.spawn(f, 'https://www.yahoo.com/'),gevent.spawn(f, 'https://github.com/'),
])
print("協程異步cost",time.time() - async_time_start)