1.經過headers反爬蟲
2.基於用戶行爲的發爬蟲:(同一IP短期內訪問的頻率)
3.動態網頁反爬蟲(經過ajax請求數據,或者經過JavaScript生成)
4.對部分數據進行加密處理的(數據是亂碼)html
對於基本網頁的抓取能夠自定義headers,添加headers的數據
使用多個代理ip進行抓取或者設置抓取的頻率下降一些,
動態網頁的可使用selenium + phantomjs 進行抓取
對部分數據進行加密的,可使用selenium進行截圖,使用python自帶的pytesseract庫進行識別,可是比較慢最直接的方法是找到加密的方法進行逆向推理。python
headers方向
判斷User-Agent、判斷Referer、判斷Cookie。
將瀏覽器的headers信息所有添加進去
注意:Accept-Encoding;gzip,deflate須要註釋掉react
它是將scrapy框架中Scheduler替換爲redis數據庫,實現隊列管理共享。jquery
分爲5個部分;Spiders(爬蟲類),Scrapy Engine(引擎),Scheduler(調度器),Downloader(下載器),Item Pipeline(處理管道)。web
對於一個可迭代的(iterable)/可遍歷的對象(如列表、字符串),enumerate將其組成一個索引序列,利用它能夠同時得到索引和值
enumerate多用於在for循環中獲得計數ajax
無頭瀏覽器即headless browser,是一種沒有界面的瀏覽器。既然是瀏覽器那麼瀏覽器該有的東西它都應該有,只是看不到界面而已。redis
Python中selenium模塊中的PhantomJS即爲無界面瀏覽器(無頭瀏覽器):是基於QtWebkit的無頭瀏覽器。算法
scrapy是一個爬蟲通用框架,但不支持分佈式,scrapy-redis是爲了更方便的實現scrapy分佈式爬蟲,而提供了一些以redis爲基礎的組件shell
由於redis支持主從同步,並且數據都是緩存在內存中,因此基於redis的分佈式爬蟲,對請求和數據的高頻讀取效率很是高數據庫
在Redis中,用戶能夠經過執行SLAVEOF命令或者設置slaveof選項,讓一個服務器去複製(replicate)另外一個服務器,咱們稱呼被複制的服務器爲主服務器(master),而對主服務器進行復制的服務器則被稱爲從服務器(slave),當客戶端向從服務器發送SLAVEOF命令,要求從服務器複製主服務器時,從服務器首先須要執行同步操做,也便是,將從服務器的數據庫狀態更新至主服務器當前所處的數據庫狀態
採起可讀性更強的xpath代替正則 強大的統計和log系統 同時在不一樣的url上爬行 支持shell方式,方便獨立調試 寫middleware,方便寫一些統一的過濾器 經過管道的方式存入數據庫
基於python爬蟲框架,擴展性比較差,基於twisted框架,運行中exception是不會幹掉reactor,而且異步框架出錯後是不會停掉其餘任務的,數據出錯後難以察覺
requests 是 polling 方式的,會被網絡阻塞,不適合爬取大量數據
scapy 底層是異步框架 twisted ,併發是最大優點
從start_urls裏面獲取第一批url發送請求,請求由請求引擎給調度器入請求對列,獲取完畢後,調度器將請求對列交給下載器去獲取請求對應的響應資源,並將響應交給本身編寫的解析方法作提取處理,若是提取出須要的數據,則交給管道處理,若是提取出url,則繼續執行以前的步驟,直到多列裏沒有請求,程序結束。
IO密集型代碼(文件處理、網絡爬蟲等),多線程可以有效提高效率(單線程下有IO操做會進行IO等待,形成沒必要要的時間浪費,而開啓多線程能在線程A等待時,自動切換到線程B,能夠不浪費CPU的資源,從而能提高程序執行效率)。在實際的數據採集過程當中,既考慮網速和響應的問題,也須要考慮自身機器的硬件狀況,來設置多進程或多線程
面對海量待抓取網頁,只有採用分佈式架構,纔有可能在較短期內完成一輪抓取工做。
它的開發效率是比較快並且簡單的。
爬蟲下載慢主要緣由是阻塞等待發往網站的請求和網站返回
1,採用異步與多線程,擴大電腦的cpu利用率; 2,採用消息隊列模式 3,提升帶寬
Robots協議(也稱爲爬蟲協議、爬蟲規則、機器人協議等)也就是robots.txt,網站經過robots協議告訴搜索引擎哪些頁面能夠抓取,哪些頁面不能抓取。
Robots協議是網站國際互聯網界通行的道德規範,其目的是保護網站數據和敏感信息、確保用戶我的信息和隱私不被侵犯。因其不是命令,故須要搜索引擎自覺遵照。
#Python學習交流QQ羣:857662006 尋找有志同道合的小夥伴 def get_lines(): with open('file.txt','rb') as f: return f.readlines() if __name__ == '__main__': for e in get_lines(): process(e) # 處理每一行數據
如今要處理一個大小爲10G的文件,可是內存只有4G,若是在只修改get_lines 函數而其餘代碼保持不變的狀況下,應該如何實現?須要考慮的問題都有那些?
def get_lines(): with open('file.txt','rb') as f: for i in f: yield i
Pandaaaa906提供的方法
from mmap import mmap def get_lines(fp): with open(fp,"r+") as f: m = mmap(f.fileno(), 0) tmp = 0 for i, char in enumerate(m): if char==b"\n": yield m[tmp:i+1].decode() tmp = i+1 if __name__=="__main__": for i in get_lines("fp_some_huge_file"): print(i)
要考慮的問題有:內存只有4G沒法一次性讀入10G文件,須要分批讀入分批讀入數據要記錄每次讀入數據的位置。分批每次讀取數據的大小,過小會在讀取操做花費過多時間。
https://stackoverflow.com/questions/30294146/python-fastest-way-to-process-large-file
def print_directory_contents(sPath): """ 這個函數接收文件夾的名稱做爲輸入參數 返回該文件夾中文件的路徑 以及其包含文件夾中文件的路徑 """ import os for s_child in os.listdir(s_path): s_child_path = os.path.join(s_path, s_child) if os.path.isdir(s_child_path): print_directory_contents(s_child_path) else: print(s_child_path)
import datetime def dayofyear(): year = input("請輸入年份: ") month = input("請輸入月份: ") day = input("請輸入天: ") date1 = datetime.date(year=int(year),month=int(month),day=int(day)) date2 = datetime.date(year=int(year),month=1,day=1) return (date1-date2).days+1
import random alist = [1,2,3,4,5] random.shuffle(alist) print(alist)
sorted(d.items(),key=lambda x:x[1])
d = {key:value for (key,value) in iterable}
print("aStr"[::-1])
str1 = "k:1|k1:2|k2:3|k3:4" def str2dict(str1): dict1 = {} for iterms in str1.split('|'): key,value = iterms.split(':') dict1[key] = value return dict1 #字典推導式 d = {k:int(v) for t in str1.split("|") for k, v in (t.split(":"), )}
alist = [{'name':'a','age':20},{'name':'b','age':30},{'name':'c','age':25}] def sort_by_age(list1): return sorted(alist,key=lambda x:x['age'],reverse=True)
list = ['a','b','c','d','e'] print(list[10:])
代碼將輸出[],不會產生IndexError錯誤,就像所指望的那樣,嘗試用超出成員的個數的index來獲取某個列表的成員。例如,嘗試獲取list[10]和以後的成員,會致使IndexError。然而,嘗試獲取列表的切片,開始的index超過了成員個數不會產生IndexError,而是僅僅返回一個空列表。這成爲特別讓人噁心的疑難雜症,由於運行的時候沒有錯誤產生,致使Bug很難被追蹤到。
print([x*11 for x in range(10)])
list1 = [1,2,3] list2 = [3,4,5] set1 = set(list1) set2 = set(list2) print(set1 & set2) print(set1 ^ set2)
l1 = ['b','c','d','c','a','a'] l2 = list(set(l1)) print(l2)
用list類的sort方法:
l1 = ['b','c','d','c','a','a'] l2 = list(set(l1)) l2.sort(key=l1.index) print(l2)
也能夠這樣寫:
l1 = ['b','c','d','c','a','a'] l2 = sorted(set(l1),key=l1.index) print(l2)
也能夠用遍歷:
l1 = ['b','c','d','c','a','a'] l2 = [] for i in l1: if not i in l2: l2.append(i) print(l2)
A,B 中相同元素:print(set(A)&set(B)) A,B 中不一樣元素: print(set(A)^set(B))
a. 在python裏凡是繼承了object的類,都是新式類
b. Python3裏只有新式類
c. Python2裏面繼承object的是新式類,沒有寫父類的是經典類
d. 經典類目前在Python裏基本沒有應用
a. 整型 int、 長整型 long、浮點型 float、 複數 complex
b. 字符串 str、 列表 list、 元祖 tuple
c. 字典 dict 、 集合 set
d. Python3 中沒有 long,只有無限精度的 int
第一種方法:使用裝飾器
#Python學習交流QQ羣:857662006 def singleton(cls): instances = {} def wrapper(*args, **kwargs): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class Foo(object): pass foo1 = Foo() foo2 = Foo() print(foo1 is foo2) # True
第二種方法:使用基類
New 是真正建立實例對象的方法,因此重寫基類的new 方法,以此保證建立對象的時候只生成一個實例
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance class Foo(Singleton): pass foo1 = Foo() foo2 = Foo() print(foo1 is foo2) # True
第三種方法:元類,元類是用於建立類對象的類,類對象建立實例對象時必定要調用call方法,所以在調用call時候保證始終只建立一個實例便可,type是python的元類
class Singleton(type): def __call__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__call__(*args, **kwargs) return cls._instance # Python2 class Foo(object): __metaclass__ = Singleton # Python3 class Foo(metaclass=Singleton): pass foo1 = Foo() foo2 = Foo() print(foo1 is foo2) # True
class Solution(object): def reverse(self,x): if -10<x<10: return x str_x = str(x) if str_x[0] !="-": str_x = str_x[::-1] x = int(str_x) else: str_x = str_x[1:][::-1] x = int(str_x) x = -x return x if -2147483648<x<2147483647 else 0 if __name__ == '__main__': s = Solution() reverse_int = s.reverse(-120) print(reverse_int)
第一種方法:
import os def get_files(dir,suffix): res = [] for root,dirs,files in os.walk(dir): for filename in files: name,suf = os.path.splitext(filename) if suf == suffix: res.append(os.path.join(root,filename)) print(res) get_files("./",'.pyc')
第二種方法:
import os def pick(obj): if ob.endswith(".pyc"): print(obj) def scan_path(ph): file_list = os.listdir(ph) for obj in file_list: if os.path.isfile(obj): pick(obj) elif os.path.isdir(obj): scan_path(obj) if __name__=='__main__': path = input('輸入目錄') scan_path(path)
第三種方法
from glob import iglob def func(fp, postfix): for i in iglob(f"{fp}/**/*{postfix}", recursive=True): print(i) if __name__ == "__main__": postfix = ".pyc" func("K:\Python_script", postfix)
遍歷在新在列表操做,刪除時在原來的列表操做
a = [1,2,3,4,5,6,7,8] print(id(a)) print(id(a[:])) for i in a[:]: if i>5: pass else: a.remove(i) print(a) print('-----------') print(id(a)) #filter a=[1,2,3,4,5,6,7,8] b = filter(lambda x: x>5,a) print(list(b))
列表解析
a=[1,2,3,4,5,6,7,8] b = [i for i in a if i>5] print(b)
倒序刪除
由於列表老是‘向前移’,因此能夠倒序遍歷,即便後面的元素被修改了,尚未被遍歷的元素和其座標仍是保持不變的
a=[1,2,3,4,5,6,7,8] print(id(a)) for i in range(len(a)-1,-1,-1): if a[i]>5: pass else: a.remove(a[i]) print(id(a)) print('-----------') print(a)
全字母短句 PANGRAM 是包含全部英文字母的句子,好比:A QUICK BROWN FOX JUMPS OVER THE LAZY DOG. 定義並實現一個方法 get_missing_letter, 傳入一個字符串採納數,返回參數字符串變成一個 PANGRAM 中所缺失的字符。應該忽略傳入字符串參數中的大小寫,返回應該都是小寫字符並按字母順序排序(請忽略全部非 ACSII 字符)
下面示例是用來解釋,雙引號不須要考慮:
(0)輸入: "A quick brown for jumps over the lazy dog"
返回:""
(1)輸入: "A slow yellow fox crawls under the proactive dog"
返回: "bjkmqz"
(2)輸入: "Lions, and tigers, and bears, oh my!"
返回: "cfjkpquvwxz"
(3)輸入: ""
返回:"abcdefghijklmnopqrstuvwxyz"
def get_missing_letter(a): s1 = set("abcdefghijklmnopqrstuvwxyz") s2 = set(a) ret = "".join(sorted(s1-s2)) return ret print(get_missing_letter("python"))
1,可變類型有list,dict.不可變類型有string,number,tuple.
2,當進行修改操做時,可變類型傳遞的是內存中的地址,也就是說,直接修改內存中的值,並無開闢新的內存。
3,不可變類型被改變時,並無改變原內存地址中的值,而是開闢一塊新的內存,將原地址中的值複製過去,對這塊新開闢的內存中的值進行操做。
is:比較的是兩個對象的id值是否相等,也就是比較倆對象是否爲同一個實例對象。是否指向同一個內存地址
== :比較的兩個對象的內容/值是否相等,默認會調用對象的eq()方法
a = [1,2,3,4,5,6,7,8,9,10] res = [ i for i in a if i%2==1] print(res)
from functools import reduce #1.使用sum內置求和函數 num = sum([1,2,3,10248]) print(num) #2.reduce 函數 num1 = reduce(lambda x,y :x+y,[1,2,3,10248]) print(num1)
函數做用域的LEGB順序
1.什麼是LEGB?
L:local 函數內部做用域
E: enclosing 函數內部與內嵌函數之間
G: global 全局做用域
B:build-in 內置做用
python在函數裏面的查找分爲4種,稱之爲LEGB,也正是按照這是順序來查找的
"123"
轉換成 123
,不使用內置api,例如 int()
方法一:利用 str
函數
def atoi(s): num = 0 for v in s: for j in range(10): if v == str(j): num = num * 10 + j return num
方法二:利用 ord
函數
def atoi(s): num = 0 for v in s: num = num * 10 + ord(v) - ord('0') return num
方法三: 利用 eval
函數
def atoi(s): num = 0 for v in s: t = "%s * 1" % v n = eval(t) num = num * 10 + n return num
方法四: 結合方法二,使用 reduce
,一行解決
from functools import reduce def atoi(s): return reduce(lambda num, v: num * 10 + ord(v) - ord('0'), s, 0)
給定一個整數數組和一個目標值,找出數組中和爲目標值的兩個數。你能夠假設每一個輸入只對應一種答案,且一樣的元素不能被重複利用。示例:給定nums = [2,7,11,15],target=9 由於 nums[0]+nums[1] = 2+7 =9,因此返回[0,1]
class Solution: def twoSum(self,nums,target): """ :type nums: List[int] :type target: int :rtype: List[int] """ d = {} size = 0 while size < len(nums): if target-nums[size] in d: if d[target-nums[size]] <size: return [d[target-nums[size]],size] else: d[nums[size]] = size size = size +1 solution = Solution() list = [2,7,11,15] target = 9 nums = solution.twoSum(list,target) print(nums)
給列表中的字典排序:假設有以下list對象,alist=[{"name":"a","age":20},{"name":"b","age":30},{"name":"c","age":25}],將alist中的元素按照age從大到小排序 alist=[{"name":"a","age":20},{"name":"b","age":30},{"name":"c","age":25}]
alist_sort = sorted(alist,key=lambda e: e.__getitem__('age'),reverse=True)
def distFunc1(a): """使用集合去重""" a = list(set(a)) print(a) def distFunc2(a): """將一個列表的數據取出放到另外一個列表中,中間做判斷""" list = [] for i in a: if i not in list: list.append(i) #若是須要排序的話用sort list.sort() print(list) def distFunc3(a): """使用字典""" b = {} b = b.fromkeys(a) c = list(b.keys()) print(c) if __name__ == "__main__": a = [1,2,4,2,4,5,7,10,5,5,7,8,9,0,3] distFunc1(a) distFunc2(a) distFunc3(a)
import re # 方法一 def test(filepath): distone = {} with open(filepath) as f: for line in f: line = re.sub("\W+", " ", line) lineone = line.split() for keyone in lineone: if not distone.get(keyone): distone[keyone] = 1 else: distone[keyone] += 1 num_ten = sorted(distone.items(), key=lambda x:x[1], reverse=True)[:10] num_ten =[x[0] for x in num_ten] return num_ten # 方法二 # 使用 built-in 的 Counter 裏面的 most_common import re from collections import Counter def test2(filepath): with open(filepath) as f: return list(map(lambda c: c[0], Counter(re.sub("\W+", " ", f.read()).split()).most_common(10)))
該函數的輸入是一個僅包含數字的list,輸出一個新的list,其中每個元素要知足如下條件:
一、該元素是偶數
二、該元素在原list中是在偶數的位置(index是偶數)
def num_list(num): return [i for i in num if i %2 ==0 and num.index(i)%2==0] num = [0,1,2,3,4,5,6,7,8,9,10] result = num_list(num) print(result)
該列表只包含知足如下條件的值,元素爲原始列表中偶數切片
list_data = [1,2,5,8,10,3,18,6,20] res = [x for x in list_data[::2] if x %2 ==0] print(res)
[x * x for x in range(1,11)]
import datetime y = int(input("請輸入4位數字的年份:")) m = int(input("請輸入月份:")) d = int(input("請輸入是哪一天")) targetDay = datetime.date(y,m,d) dayCount = targetDay - datetime.date(targetDay.year -1,12,31) print("%s是 %s年的第%s天。"%(targetDay,y,dayCount.days))
def loop_merge_sort(l1,l2): tmp = [] while len(l1)>0 and len(l2)>0: if l1[0] <l2[0]: tmp.append(l1[0]) del l1[0] else: tmp.append(l2[0]) del l2[0] while len(l1)>0: tmp.append(l1[0]) del l1[0] while len(l2)>0: tmp.append(l2[0]) del l2[0] return tmp
讓全部奇數都在偶數前面,並且奇數升序排列,偶數降序排序,如字符串'1982376455',變成'1355798642'
# 方法一 def func1(l): if isinstance(l, str): l = [int(i) for i in l] l.sort(reverse=True) for i in range(len(l)): if l[i] % 2 > 0: l.insert(0, l.pop(i)) print(''.join(str(e) for e in l)) # 方法二 def func2(l): print("".join(sorted(l, key=lambda x: int(x) % 2 == 0 and 20 - int(x) or int(x))))
#Python學習交流QQ羣:857662006 def find_second_large_num(num_list): """ 找出數組第2大的數字 """ # 方法一 # 直接排序,輸出倒數第二個數便可 tmp_list = sorted(num_list) print("方法一\nSecond_large_num is :", tmp_list[-2]) # 方法二 # 設置兩個標誌位一個存儲最大數一個存儲次大數 # two 存儲次大值,one 存儲最大值,遍歷一次數組便可,先判斷是否大於 one,若大於將 one 的值給 two,將 num_list[i] 的值給 one,不然比較是否大於two,若大於直接將 num_list[i] 的值給two,不然pass one = num_list[0] two = num_list[0] for i in range(1, len(num_list)): if num_list[i] > one: two = one one = num_list[i] elif num_list[i] > two: two = num_list[i] print("方法二\nSecond_large_num is :", two) # 方法三 # 用 reduce 與邏輯符號 (and, or) # 基本思路與方法二同樣,可是不須要用 if 進行判斷。 from functools import reduce num = reduce(lambda ot, x: ot[1] < x and (ot[1], x) or ot[0] < x and (x, ot[1]) or ot, num_list, (0, 0))[0] print("方法三\nSecond_large_num is :", num) if __name__ == '__main___': num_list = [34, 11, 23, 56, 78, 0, 9, 12, 3, 7, 5] find_second_large_num(num_list)
def multi(): return [lambda x : i*x for i in range(4)] print([m(3) for m in multi()])
正確答案是[9,9,9,9],而不是[0,3,6,9]產生的緣由是Python的閉包的後期綁定致使的,這意味着在閉包中的變量是在內部函數被調用的時候被查找的,由於,最後函數被調用的時候,for循環已經完成, i 的值最後是3,所以每個返回值的i都是3,因此最後的結果是[9,9,9,9]
# 方法一 def count_str(str_data): """定義一個字符出現次數的函數""" dict_str = {} for i in str_data: dict_str[i] = dict_str.get(i, 0) + 1 return dict_str dict_str = count_str("AAABBCCAC") str_count_data = "" for k, v in dict_str.items(): str_count_data += k + str(v) print(str_count_data) # 方法二 from collections import Counter print("".join(map(lambda x: x[0] + str(x[1]), Counter("AAABBCCAC").most_common())))
類方法: 是類對象的方法,在定義時須要在上方使用 @classmethod 進行裝飾,形參爲cls,表示類對象,類對象和實例對象均可調用
類實例方法: 是類實例化對象的方法,只有實例對象能夠調用,形參爲self,指代對象自己;
靜態方法: 是一個任意函數,在其上方使用 @staticmethod 進行裝飾,能夠用對象直接調用,靜態方法實際上跟該類沒有太大關係
class Car: def __init__(self,name,loss): # loss [價格,油耗,千米數] self.name = name self.loss = loss def getName(self): return self.name def getPrice(self): # 獲取汽車價格 return self.loss[0] def getLoss(self): # 獲取汽車損耗值 return self.loss[1] * self.loss[2] Bmw = Car("寶馬",[60,9,500]) # 實例化一個寶馬車對象 print(getattr(Bmw,"name")) # 使用getattr()傳入對象名字,屬性值。 print(dir(Bmw)) # 獲Bmw全部的屬性和方法
class Array: __list = [] def __init__(self): print "constructor" def __del__(self): print "destruct" def __str__(self): return "this self-defined array class" def __getitem__(self,key): return self.__list[key] def __len__(self): return len(self.__list) def Add(self,value): self.__list.append(value) def Remove(self,index): del self.__list[index] def DisplayItems(self): print "show all items---" for item in self.__list: print item
A,變量沒必要事先聲明 B,變量無須先建立和賦值而直接使用
C,變量無須指定類型 D,可使用del釋放資源
內存管理機制: 引用計數、垃圾回收、內存池
引用計數:引用計數是一種很是高效的內存管理手段,當一個Python對象被引用時其引用計數增長1,
當其再也不被一個變量引用時則計數減1,當引用計數等於0時對象被刪除。弱引用不會增長引用計數
垃圾回收:
1.引用計數
引用計數也是一種垃圾收集機制,並且也是一種最直觀、最簡單的垃圾收集技術。當Python的某個對象的引用計數降爲0時,說明沒有任何引用指向該對象,該對象就成爲要被回收的垃圾了。好比某個新建對象,它被分配給某個引用,對象的引用計數變爲1,若是引用被刪除,對象的引用計數爲0,那麼該對象就能夠被垃圾回收。不過若是出現循環引用的話,引用計數機制就再也不起有效的做用了。
2.標記清除
調優手段
1.手動垃圾回收
2.調高垃圾回收閾值
3.避免循環引用
內存泄漏指因爲疏忽或錯誤形成程序未能釋放已經再也不使用的內存。內存泄漏並不是指內存在物理上的消失,而是應用程序分配某段內存後,因爲設計錯誤,致使在釋放該段內存以前就失去了對該段內存的控制,從而形成了內存的浪費。
有__del__()
函數的對象間的循環引用是致使內存泄露的主兇。不使用一個對象時使用: del object 來刪除一個對象的引用計數就能夠有效防止內存泄露問題。
經過Python擴展模塊gc 來查看不能回收的對象的詳細信息。
能夠經過 sys.getrefcount(obj) 來獲取對象的引用計數,並根據返回值是否爲0來判斷是否內存泄露
[表達式 for 變量 in 列表] 或者 [表達式 for 變量 in 列表 if 條件]
read 讀取整個文件
readline 讀取下一行
readlines 讀取整個文件到一個迭代器以供咱們遍歷
散列函數(英語:Hash function)又稱散列算法、哈希函數,是一種從任何一種數據中建立小的數字「指紋」的方法。散列函數把消息或數據壓縮成摘要,使得數據量變小,將數據的格式固定下來。該函數將數據打亂混合,從新建立一個叫作散列值(hash values,hash codes,hash sums,或hashes)的指紋。散列值一般用一個短的隨機字母和數字組成的字符串來表明
函數重載主要是爲了解決兩個問題。
1。可變參數類型。
2。可變參數個數。
另外,一個基本的設計原則是,僅僅當兩個函數除了參數類型和參數個數不一樣之外,其功能是徹底相同的,此時才使用函數重載,若是兩個函數的功能其實不一樣,那麼不該當使用重載,而應當使用一個名字不一樣的函數。
好吧,那麼對於狀況 1 ,函數功能相同,可是參數類型不一樣,python 如何處理?答案是根本不須要處理,由於 python 能夠接受任何類型的參數,若是函數的功能相同,那麼不一樣的參數類型在 python 中極可能是相同的代碼,沒有必要作成兩個不一樣函數。
那麼對於狀況 2 ,函數功能相同,但參數個數不一樣,python 如何處理?你們知道,答案就是缺省參數。對那些缺乏的參數設定爲缺省參數便可解決問題。由於你假設函數功能相同,那麼那些缺乏的參數終歸是須要用的。
好了,鑑於狀況 1 跟 狀況 2 都有了解決方案,python 天然就不須要函數重載了。
import datetime class TimeException(Exception): def __init__(self, exception_info): super().__init__() self.info = exception_info def __str__(self): return self.info def timecheck(func): def wrapper(*args, **kwargs): if datetime.datetime.now().year == 2019: func(*args, **kwargs) else: raise TimeException("函數已過期") return wrapper @timecheck def test(name): print("Hello {}, 2019 Happy".format(name)) if __name__ == "__main__": test("backbp")
list(filter(lambda x: x % 2 == 0, range(10)))
1.函數設計要儘可能短小
2.函數聲明要作到合理、簡單、易於使用
3.函數參數設計應該考慮向下兼容
4.一個函數只作一件事情,儘可能保證函數語句粒度的一致性
Python的參數傳遞有:位置參數、默認參數、可變參數、關鍵字參數。
函數的傳值究竟是值傳遞仍是引用傳遞、要分狀況:
不可變參數用值傳遞:像整數和字符串這樣的不可變對象,是經過拷貝進行傳遞的,由於你不管如何都不可能在原處改變不可變對象。
可變參數是引用傳遞:好比像列表,字典這樣的對象是經過引用傳遞、和C語言裏面的用指針傳遞數組很類似,可變對象能在函數內部改變。
globals() # 返回包含當前做用餘全局變量的字典。 global 變量 設置使用全局變量
缺省參數指在調用函數的時候沒有傳入參數的狀況下,調用默認的參數,在調用函數的同時賦值時,所傳入的參數會替代默認參數。
*args是不定長參數,它能夠表示輸入參數是不肯定的,能夠是任意多個。
**kwargs是關鍵字參數,賦值的時候是以鍵值對的方式,參數能夠是任意多對在定義函數的時候
不肯定會有多少參數會傳入時,就可使用兩個參數
帶定長參數的裝飾器
def new_func(func): def wrappedfun(username, passwd): if username == 'root' and passwd == '123456789': print('經過認證') print('開始執行附加功能') return func() else: print('用戶名或密碼錯誤') return return wrappedfun @new_func def origin(): print('開始執行函數') origin('root','123456789')
帶不定長參數的裝飾器
def new_func(func): def wrappedfun(*parts): if parts: counts = len(parts) print('本系統包含 ', end='') for part in parts: print(part, ' ',end='') print('等', counts, '部分') return func() else: print('用戶名或密碼錯誤') return func() return wrappedfun
Python中一切皆對象,函數名是函數在內存中的空間,也是一個對象
在編寫代碼時只寫框架思路,具體實現還未編寫就能夠用pass進行佔位,是程序不報錯,不會進行任何操做。
a = 10 b = 20 c = [a] a = 15
答:10對於字符串,數字,傳遞是相應的值
a, b = b, a
map(lambda x: x * x, [1, 2, 3, 4]) # 使用 lambda # [1, 4, 9, 16] reduce(lambda x, y: x * y, [1, 2, 3, 4]) # 至關於 ((1 * 2) * 3) * 4 # 24
回調函數是把函數的指針(地址)做爲參數傳遞給另外一個函數,將整個函數看成一個對象,賦值給調用的函數。
內建類型:布爾類型,數字,字符串,列表,元組,字典,集合
輸出字符串'a'的內建方法
[0, 1, 4]
hasattr(object,name)函數:
判斷一個對象裏面是否有name屬性或者name方法,返回bool值,有name屬性(方法)返回True,不然返回False。
class function_demo(object): name = 'demo' def run(self): return "hello function" functiondemo = function_demo() res = hasattr(functiondemo, "name") # 判斷對象是否有name屬性,True res = hasattr(functiondemo, "run") # 判斷對象是否有run方法,True res = hasattr(functiondemo, "age") # 判斷對象是否有age屬性,False print(res)
getattr(object, name[,default])函數:
獲取對象object的屬性或者方法,若是存在則打印出來,若是不存在,打印默認值,默認值可選。注意:若是返回的是對象的方法,則打印結果是:方法的內存地址,若是須要運行這個方法,能夠在後面添加括號().
functiondemo = function_demo() getattr(functiondemo, "name")# 獲取name屬性,存在就打印出來 --- demo getattr(functiondemo, "run") # 獲取run 方法,存在打印出方法的內存地址 getattr(functiondemo, "age") # 獲取不存在的屬性,報錯 getattr(functiondemo, "age", 18)# 獲取不存在的屬性,返回一個默認值
setattr(object, name, values)函數:
給對象的屬性賦值,若屬性不存在,先建立再賦值
class function_demo(object): name = "demo" def run(self): return "hello function" functiondemo = function_demo() res = hasattr(functiondemo, "age") # 判斷age屬性是否存在,False print(res) setattr(functiondemo, "age", 18) # 對age屬性進行賦值,無返回值 res1 = hasattr(functiondemo, "age") # 再次判斷屬性是否存在,True
綜合使用
class function_demo(object): name = "demo" def run(self): return "hello function" functiondemo = function_demo() res = hasattr(functiondemo, "addr") # 先判斷是否存在 if res: addr = getattr(functiondemo, "addr") print(addr) else: addr = getattr(functiondemo, "addr", setattr(functiondemo, "addr", "北京首都")) print(addr)
reduce(lambda x,y : x*y,range(1,n+1))
設計模式是通過總結,優化的,對咱們常常會碰到的一些編程問題的可重用解決方案。一個設計模式並不像一個類或一個庫那樣可以直接做用於咱們的代碼,反之,設計模式更爲高級,它是一種必須在特定情形下實現的一種方法模板。
常見的是工廠模式和單例模式
#python2 class A(object): __instance = None def __new__(cls,*args,**kwargs): if cls.__instance is None: cls.__instance = objecet.__new__(cls) return cls.__instance else: return cls.__instance
單例模式應用的場景通常發如今如下條件下:
資源共享的狀況下,避免因爲資源操做時致使的性能或損耗等,如日誌文件,應用配置。
控制資源的狀況下,方便資源之間的互相通訊。如線程池等,1,網站的計數器 2,應用配置 3.多線程池 4數據庫配置 數據庫鏈接池 5.應用程序的日誌應用…
print([x*x for x in range(1, 11)])
裝飾器本質上是一個callable object ,它可讓其餘函數在不須要作任何代碼變更的前提下增長額外功能,裝飾器的返回值也是一個函數對象。
import time from functools import wraps def timeit(func): @wraps(func) def wrapper(*args, **kwargs): start = time.clock() ret = func(*args, **kwargs) end = time.clock() print('used:',end-start) return ret return wrapper @timeit def foo(): print('in foo()'foo())
在函數內部再定義一個函數,而且這個函數用到了外邊函數的變量,那麼將這個函數以及用到的一些變量稱之爲閉包。
裝飾器本質上是一個callable object,它能夠在讓其餘函數在不須要作任何代碼的變更的前提下增長額外的功能。裝飾器的返回值也是一個函數的對象,它常常用於有切面需求的場景。好比:插入日誌,性能測試,事務處理,緩存。權限的校驗等場景,有了裝飾器就能夠抽離出大量的與函數功能自己無關的雷同代碼併發並繼續使用。
詳細參考:https://manjusaka.itscoder.com/2018/02/23/something-about-decorator/
迭代器是遵循迭代協議的對象。用戶可使用 iter() 以從任何序列獲得迭代器(如 list, tuple, dictionary, set 等)。另外一個方法則是建立一個另外一種形式的迭代器 —— generator 。要獲取下一個元素,則使用成員函數 next()(Python 2)或函數 next() function (Python 3) 。當沒有元素時,則引起 StopIteration 此例外。若要實現本身的迭代器,則只要實現 next()(Python 2)或 __next__
()( Python 3)
生成器(Generator),只是在須要返回數據的時候使用yield語句。每次next()被調用時,生成器會返回它脫離的位置(它記憶語句最後一次執行的位置和全部的數據值)
區別:生成器能作到迭代器能作的全部事,並且由於自動建立iter()和next()方法,生成器顯得特別簡潔,並且生成器也是高效的,使用生成器表達式取代列表解析能夠同時節省內存。除了建立和保存程序狀態的自動方法,當發生器終結時,還會自動拋出StopIteration異常。
X= (i for i in range(10))
X是 generator類型
N =100 print ([[x for x in range(1,100)] [i:i+3] for i in range(0,100,3)])
yield就是保存當前程序執行狀態。你用for循環的時候,每次取一個元素的時候就會計算一次。用yield的函數叫generator,和iterator同樣,它的好處是不用一次計算全部元素,而是用一次算一次,能夠節省不少空間,generator每次計算須要上一次計算結果,因此用yield,不然一return,上次計算結果就沒了