目錄 生成器和迭代器 字元串格式化 內置函數vars 反射 面向對象編程 一. 生成器和迭代器 1. 生成器 生成器具有一種生成的能力,它僅僅代表著一種生成的能力,當我們需要使用的時候,才會通過迭代器去生成它。因為他只代表這一種生成的能力,因此,生成器比較節省記憶體,它一般通過yield來區分生成的位 ...
目錄
- 生成器和迭代器
- 字元串格式化
- 內置函數vars
- 反射
- 面向對象編程
一. 生成器和迭代器
1. 生成器
生成器具有一種生成的能力,它僅僅代表著一種生成的能力,當我們需要使用的時候,才會通過迭代器去生成它。因為他只代表這一種生成的能力,因此,生成器比較節省記憶體,它一般通過yield來區分生成的位置。通過next來找到下一個位置。
# 當直接去執行genetor函數的時候,會先返回一個1,然後就退出了,因為遇到了yield # 當用一個next之後就會執行2. 然後繼續退出 # 也就是說yield其實是生成器的一個地址保存機制,只有通過next才會使他的地址指向下一個yield def genetor(): print(1) yield 1 print(2) yield 2 print(3) yield 3 print(4) yield 4 obj=genetor() a = obj.__next__() b = obj.__next__() c = obj.__next__() d = obj.__next__()
書寫一個xrange函數
def xrange(args): value = 0 while True: if value >= args: return else: yield value value += 1 for i in xrange(5): print(i)
2. 迭代器
迭代器代表這個一種訪問的能力,他能夠通過一次次的next去迭代生成器產生的對象,因此,他能夠得到我們想要得到的數據。for迴圈就是一種迭代器。如上面的代碼,我們可以通過for迴圈去迭代生成器。
二. 字元串格式化
1. 字元串的格式化
字元串的格式化比拼接的方式更加有效
字元串的格式化更加的方便
2. %格式化
# %的使用格式,[]裡面的內容都可以省略 %[(name)][flags][width].[precision]typecode
[(name)]
格式:%[(name)][flags][width].[precision]typecode (name): 可選的,用於選擇指定的key flags: 輸入的格式是左對齊還是右對齊,和width一塊使用, + 右對齊, 正數前面加+號, 負數前面加-號 - 不變,就是左對齊 空格 不變,就是右對齊 0 右對齊,前面填充0 width 可選,占有的寬度 .precision 小數點後保留的位數 typecode s 字元串 f 有精度的數 d 整數
事例:
字元串s1 = "I am %+10d, age %-10d, % 10d %010d" % (10, 10, 10, 10) s2 = "I am %+10d, age %-10d, % 10d %010d" % (-10, -10, -10, -10) print(s1) print(s2) 結果: I am +10, age 10 , 10 0000000010 I am -10, age -10 , -10 -000000010整數
# 常用事例: s1 = "I am %s" % "hu" s2 = "I am %(name)s, age%(age)s" % {"name": "hu", "age": 13} s3 = "3.335 + 4.2345 = %2.f" % 7.23566 print(s1, s2, s3)
3. format格式化的常用方法
[[fill]align][sign][#][0][width][,][.precision][type] 這個是format的格式,很多和%都是一樣的,下麵只列舉一下關於它的常見用法
s1 = "i am {}, {}, {}".format("hu", "zhou", "12") s1 = "I am {}, {}, {}".format(*["hu", "zhou", "12"]) s1 = "I am {0}, {1}, {0}".format("seven", 18) s1 = "I am {0}, {1}, {0}".format(*["seven", 19]) s1 = "I am {name}, {age}, {name}".format(name="hu", age=11) s1 = "I am {name}, {age}, {name}".format(**{"name":"hu", "age":11}) s1 = "I am {:s}, {:d}, {:f}".format("hu", 18, 1823.923) s1 = "{:b},{:x},{:o}".format(10,10,10) s1 = "{:#b},{:#x},{:#o}".format(10,10,10)
三. 內置函數vars
# 內置函數的一些預設的變數
print(vars())
{'__file__': 'C:/Users/zhou/PycharmProjects/fullstack2/6_20/test.py', '__doc__': None, '__cached__': None, '__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__package__': None, '__name__': '__main__', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000063B24C4F98>}
1. __file__ 當前工作的環境的絕對路徑
2. __name__ 如果是在當前工作目錄,則返回的是__main__, 如果是導入的模塊,返回的就是模塊的名字
3. __packge__
4. __doc__ 這個變數保存的是這個文件的說明,也就是在文件開頭部分對這個文件功能的說明
5. __cached__ 這個是緩存,如果是導入的模塊就會有緩存
6. __builtins__ 這個是內置函數
''' 這個是一個測試文檔 文檔名稱為test ''' import index print(index.__name__) print(__name__) print(__file__) print(__doc__) print(index.__cached__) 顯示結果: index __main__ C:/Users/zhou/PycharmProjects/fullstack2/6_20/test.py 這個是一個測試文檔 文檔名稱為test C:\Users\zhou\PycharmProjects\fullstack2\6_20\__pycache__\index.cpython-35.pyc
四. 反射
1. 反射的定義
反射就是通過字元串的形式去某個對象中操作它的成員。
2. __import__方法和import的區別
<1>. __import__可以通過字元串導入模塊
<2>. import 不能通過字元串來導入模塊
簡單的import和__import__
# 此處s3是一個函數的名字 # 對於字元串,直接import導入會報錯, # 需要用__import__去導入,就相當於是import s3 # import "s3" module = __import__("s3") module.f3()
擴展的__import__, 當我們需要導入層級的模塊的時候,需要用到fromlist參數
# lib目錄下有個模塊order,要導入的話就需要以下方法 module = __import__("lib.order", fromlist=True) print(module.add_order())
3. 反射的方法
<1>. hasattr(模塊, 關鍵字) 判斷關鍵字是否在模塊中,在的話返回true,不在的話返回false
<2>. getattr(模塊, 關鍵字) 如果關鍵字是一個函數,則返回函數,如果是一個變數,就返回變數(裡面的關鍵字傳遞的都是字元串,如果是函數,字元串預設是使用不了的,通過這個函數可以轉換成使用的函數)
<3>. setattr(模塊, 關鍵字, 值) 往模塊中加入關鍵字,加入的可以是變數, 可以是函數,加入和刪除都是在記憶體中完成的,並不會影響文件的內容
<4>. delattr(模塊,關鍵字) 從模塊中刪除關鍵字
s3的內容 def f1(): print("f1") ============================= # 導入s3,判斷關鍵字是否在s3中 import s3 ret1 = hasattr(s3, "f1") ret2 = hasattr(s3, "f11") print(ret1) print(ret2) 結果: True Falsehasattr()
# 導入模塊,通過字元串得到模塊內函數 # 然後執行函數 # 字元串f1 是執行不了的,只能通過getattr得到函數在執行 import s3 func = getattr(s3, 'f1') func()getattr()
# setattr傳遞的是一個鍵值對,而hasattr判斷的只是鍵,而不是值, # 因為剛開始還沒有這個“name”,所以返回的是false,通過setattr設置了這個鍵,所以返回的是True import s3 print(hasattr(s3, "name")) setattr(s3, "name", "hu") print(hasattr(s3, "name")) 結果: False Truesetattr()
# 開始f1是存在的,所以返回True # 通過del刪除之後,在返回的就是False了 import s3 print(hasattr(s3, "f1")) delattr(s3, "f1") print(hasattr(s3, "f1")) 結果: True Falsedelattr()
url = input("請輸入url:") target_module, target_func = url.split("/") print(target_func, target_module) module = __import__("lib."+target_module, fromlist=True) print(module) if hasattr(module, target_func): # module.target_func() target_func = getattr(module, target_func) target_func() else: print("404")Python實例(基於web框架的路由系統)
五. 面向對象編程
1. 編程
其實在我們日常生活中,編程的方式有很多,例如:面向過程,面向對象,或者是函數式編程,他們的區別還蠻大的,但是最終的目的只有一個,那就是簡化工作量。就像是蓋房子,面向過程就是我要自己去買磚買瓦,自己壘砌,然後函數式編程就是我自己買磚買瓦,然後找木匠工人給我做,面向對象就是,我要直接買一套房子,省的自己做了。
2. 面向對象編程
(1). 定義類
類是什麼呢?類嚴格的定義是由某種特定的元數據所組成的內聚的包。他是由多個函數共同組成的為了完成某種功能的組合。既然有了函數,為什麼還要類呢?當我們的函數出現大量的相同的參數或者相同的功能的時候,就需要類來簡化其操作了
# 關鍵字class創建了一個類,類名為Foo # 定義了三個方法,__init__ f1和f2 # 方法裡面的self為預設的參數,必須帶 class Foo: def __init__(self): self.Name = "hu" def f1(self): print("f1") def f2(self): print("f1")
(2). 執行類(創建對象)
對象是什麼呢?在Python中,一切皆對象,當我們創建了一類數據之後,他只是一類數據,其中的方法,參數都都是泛華的東西,我們需要有一個對象來對其進行實例化。也就是說,當我們說:這有個人。你肯定不知道他是誰,因為他只代表了一類數據,當我們說:他是李剛,你就會恍然大悟,哦 ,他是李剛啊,這是因為我們吧類實例化了。
__init__方法用來創建對象和封裝內容
每一個方法中的self變數都是Python中預設添加的,用來傳遞對象的。當我們創建了一個obj對象的時候,會自動的調用類中的__init__方法,然後把obj當做參數傳遞給self。
# 通過類名加括弧去創建一個對象,並用對象去調用方法 class Foo: def __init__(self): self.Name = "hu" def f1(self): print("f1") def f2(self): print("f1") obj = Foo() obj.f1()
創建對象的圖示:都在記憶體中,創建一個對象的時候,預設的會去執行類中的__init__方法,通過init方法來產生右邊的對象。
(3). 三大特性
在面向對象的語言中,一般都具有以下三種特性,封裝,繼承和多態。也正是因為這樣,才構成了一個龐大的面向對象的系統,以至於你可以通過它來表述任何事物。千變萬化。
<1>. 封裝
封裝就是把一系列相同的功能封裝到對象中,從而簡化類的方法。在介紹封裝之前,我們先來比較一下封裝和不封裝的區別。
由下麵的例子我們就可以看出來,封裝其實就是把一些重覆的量統一的在一個地方進行定義,然後在利用。
# 沒有封裝數據 class Person: def chifan(self, name, age, gender): print(name, "吃飯") def shuijiao(self, name, age, gender): print(name, "睡覺") def dadoudou(self, name, age, gender): print(name,"打豆豆")沒有封裝
class Person: def __init__(self, name, age, gender): self.Name = name self.Age = age self.Gender = gender def chifan(self): print(self.Name,"吃飯") def shujiao(self): print(self.Name,"睡覺") def dadoudou(self): print(self.Name,"打豆豆")封裝
使用場景:
a. 當同一類型的方法具有多個模板的時候,直接封裝成對象即可
b. 把類當做模板,創建多個對象(對象內封裝的數不一樣)
例:定義了一個類Person,用__init__去封裝了三個參數,以供下麵的兩個方法來調用,通過pickle模塊來存檔。
import pickle class Person: def __init__(self, name, age, weight): self.Name = name self.Age = age self.Weight = weight def chi(self): self.Weight += 2 def jianshen(self): self.Weight -= 1 ret = pickle.load(open('youxi', 'rb')) if ret: print(ret.Weight) obj1 = Person(ret.Name, ret.Age, ret.Weight) else: obj1 = Person('xiaoming', 12, 200) obj1.chi() obj1.chi() obj1.chi() obj1.jianshen() pickle.dump(obj1, open('youxi', 'wb'))
<2>. 繼承
我們都聽說過子承父業,其實繼承就是這個意思,當我們定義了幾個類之後,發現這幾個類都有一些共同的屬性和方法,這個時候我們就可以把這幾個共同的屬性和方法定義成一個類來當做這幾個類的父親,然後這幾個類就可以繼承父親的屬性和方法來當做自己的方法。如下麵這個例子,定義了三個類,一個父類,一個兒子,一個女兒,父類的方法有吃和喝,兒子的方法是票,女兒的方法是賭,當兒子繼承了父親,就會把父親的方法繼承下來,自然也就會了吃和喝,女兒也一樣。
class Parent: def chi(self): print("吃") def he(self): print("喝") class son(Parent): def piao(self): print("票") class nver(Parent): def du(self): print("賭") obj = son() obj.chi() obj.he() obj.piao() obj1 = nver() obj1.chi() obj1.he() obj1.du()View Code
繼承的規則
1. 子類會預設的繼承父類的所有方法
2. 如果子類和父類有同樣的方法,會優先的去用子類的方法
3. Python中可以繼承多個類(這個是Python的特點, C#和java都不具備)
Python中繼承多個類的順序規則
因為Python中可以多繼承,因此當子繼承父類的時候,它的規則一般是先執行左邊的,後執行右邊的,當有嵌套的時候,每次還要重新回到子類中去遞歸查找。如下麵的例子
例:當子類中的方法沒有的時候就會依次的向上進行查找
# 創建了幾個類,繼承關係如上圖中的一 class A: def f1(self): print("A") class B: def f1(self): print("B") class C(A): def f1(self): print("C") class D(B): def f1(self): print("D") class E(C, D): def f1(self): print("E") obj = E() obj.f1()上圖一
class Hu: def f1(self): print("Hu") class A(Hu): def f1(self): print("A") class B(Hu): def f1(self): print("B") class C(A): def f1(self): print("C") class D(B): def f1(self): print("D") class E(C, D): def f1(self): print("E") obj = E() obj.f1()上圖二
<3>. 多態
因為在Python傳參的時候本身就沒有類型的約束,因此它本身就是多態的,我們可以把任意的數據傳進去。
(4). 成員
方法: 靜態方法(無需使用對象封裝的內容@staticmethod,直接用類進行調用),普通方法(使用對象進行封裝),類方法
欄位: 靜態欄位(每一個對象都會有一份),普通欄位(使用對象中進行封裝的)
特性: 只有一種,將方法偽造成欄位
調用成員的方式:
1. 如果沒有self, 就用類進行調用
2. 如果有self, 就用對象進行調用
3. 異常處理
在程式執行的過程中,會遇到一些未知的錯誤,但是我們總是希望把這些錯誤的以我們能控的方式返回給用戶,這是就用到了異常處理。
異常處理的格式:
# 當try後面的語句發生錯誤之後,就會觸發後面的語句,返回一個我們可以控制的錯誤信息 a = input("輸入一個數:") try: a = int(a) except Exception as e: print("出錯了....")