python3知识点汇总_35个高级Python知识点总结
No.1 一切皆對象
眾所周知,Java中強調“一切皆對象”,但是Python中的面向對象比Java更加徹底,因為Python中的類(class)也是對象,函數(function)也是對象,而且Python的代碼和模塊也都是對象。
Python中函數和類可以賦值給一個變量
Python中函數和類可以存放到集合對象中
Python中函數和類可以作為一個函數的參數傳遞給函數
Python中函數和類可以作為返回值
Step.1
# 首先創建一個函數和一個Python3.x的新式類
class Demo(object):
def __init__(self):
print("Demo Class")
# 定義一個函數
def function():
print("function")
# 在Python無論是函數,還是類,都是對象,他們可以賦值給一個變量
class_value = Demo
func_value = function
# 并且可以通過變量調用
class_value() # Demo Class
func_value() # function
Step.2
# 將函數和類添加到集合中
obj_list = []
obj_list.append(Demo)
obj_list.append(function)
# 遍歷列表
for i in obj_list:
print(i)
#
#
Step.3
# 定義一個具體函數
def test_func(class_name, func_name):
class_name()
func_name()
# 將類名和函數名傳入形參列表
test_func(Demo, function)
# Demo Class
# function
Step.4
# 定義函數實現返回類和函數
def test_func2():
return Demo
def test_func3():
return function
# 執行函數
test_func2()() # Demo Class
test_func3()() # function
No.2 關鍵字type、object、class之間的關系
在Python中,object的實例是type,object是頂層類,沒有基類;type的實例是type,type的基類是object。Python中的內置類型的基類是object,但是他們都是由type實例化而來,具體的值由內置類型實例化而來。在Python2.x的語法中用戶自定義的類沒有明確指定基類就默認是沒有基類,在Python3.x的語法中,指定基類為object。
# object是誰實例化的?
print(type(object)) #
# object繼承自哪個類?
print(object.__bases__) # ()
# type是誰實例化的?
print(type(type)) #
# type繼承自哪個類?
print(type.__bases__) # (,)
# 定義一個變量
value = 100
# 100由誰實例化?
print(type(value)) #
# int由誰實例化?
print(type(int)) #
# int繼承自哪個類?
print(int.__bases__) # (,)
# Python 2.x的舊式類
class OldClass():
pass
# Python 3.x的新式類
class NewClass(object):
pass
No.3 Python的內置類型
在Python中,對象有3個特征屬性:
在內存中的地址,使用id()函數進行查看
對象的類型
對象的默認值
Step.1 None類型
在Python解釋器啟動時,會創建一個None類型的None對象,并且None對象全局只有一個。
Step.2 數值類型
ini類型
float類型
complex類型
bool類型
Step.3 迭代類型
在Python中,迭代類型可以使用循環來進行遍歷。
Step.4 序列類型
list
tuple
str
array
range
bytes, bytearray, memoryvie(二進制序列)
Step.5 映射類型
dict
Step.6 集合類型
set
frozenset
Step.7 上下文管理類型
with語句
Step.8 其他類型
模塊
class
實例
函數
方法
代碼
object對象
type對象
ellipsis(省略號)
notimplemented
NO.4 魔法函數
Python中的魔法函數使用雙下劃線開始,以雙下劃線結尾。關于詳細介紹請看我的文章——《全面總結Python中的魔法函數》。
No.5 鴨子類型與白鵝類型
鴨子類型是程序設計中的推斷風格,在鴨子類型中關注對象如何使用而不是類型本身。鴨子類型像多態一樣工作但是沒有繼承。鴨子類型的概念來自于:“當看到一只鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那么這只鳥就可以被稱為鴨子。”
# 定義狗類
class Dog(object):
def eat(self):
print("dog is eatting...")
# 定義貓類
class Cat(object):
def eat(self):
print("cat is eatting...")
# 定義鴨子類
class Duck(object):
def eat(self):
print("duck is eatting...")
# 以上Python中多態的體現
# 定義動物列表
an_li = []
# 將動物添加到列表
an_li.append(Dog)
an_li.append(Cat)
an_li.append(Duck)
# 依次調用每個動物的eat()方法
for i in an_li:
i().eat()
# dog is eatting...
# cat is eatting...
# duck is eatting...
白鵝類型是指只要 cls 是抽象基類,即 cls 的元類是 abc.ABCMeta ,就可以使用 isinstance(obj, cls)。
No.6 協議、 抽象基類、abc模塊和序列之間的繼承關系
協議:Python中的非正式接口,是允許Python實現多態的方式,協議是非正式的,不具備強制性,由約定和文檔定義。
接口:泛指實體把自己提供給外界的一種抽象化物(可以為另一實體),用以由內部操作分離出外部溝通方法,使其能被內部修改而不影響外界其他實體與其交互的方式。
我們可以使用猴子補丁來實現協議,那么什么是猴子補丁呢?
猴子補丁就是在運行時修改模塊或類,不去修改源代碼,從而實現目標協議接口操作,這就是所謂的打猴子補丁。
Tips:猴子補丁的叫法起源于Zope框架,開發人員在修改Zope的Bug時,經常在程序后面追加更新的部分,這些雜牌軍補丁的英文名字叫做guerilla patch,后來寫成gorllia,接著就變成了monkey。
猴子補丁的主要作用是:
在運行時替換方法、屬性
在不修改源代碼的情況下對程序本身添加之前沒有的功能
在運行時對象中添加補丁,而不是在磁盤中的源代碼上
應用案例:假設寫了一個很大的項目,處處使用了json模塊來解析json文件,但是后來發現ujson比json性能更高,修改源代碼是要修改很多處的,所以只需要在程序入口加入:
import json
# pip install ujson
import ujson
def monkey_patch_json():
json.__name__ = 'ujson'
json.dumps = ujson.dumps
json.loads = ujson.loads
monkey_patch_json()
Python 的抽象基類有一個重要實用優勢:可以使用 register 類方法在終端用戶的代碼中把某個類 “聲明” 為一個抽象基類的 “虛擬” 子 類(為此,被注冊的類必腨滿足抽象其類對方法名稱和簽名的要求,最重要的是要滿足底 層語義契約;但是,開發那個類時不用了解抽象基類,更不用繼承抽象基類 。有時,為了讓抽象類識別子類,甚至不用注冊。要抑制住創建抽象基類的沖動。濫用抽象基類會造成災難性后果,表明語言太注重表面形式 。
抽象基類不能被實例化(不能創建對象),通常是作為基類供子類繼承,子類中重寫虛函數,實現具體的接口。
判定某個對象的類型
強制子類必須實現某些方法
抽象基類的定義與使用
import abc
# 定義緩存類
class Cache(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get(self, key):
pass
@abc.abstractmethod
def set(self, key, value):
pass
# 定義redis緩存類實現Cache類中的get()和set()方法
class RedisCache(Cache):
def set(self, key):
pass
def get(self, key, value):
pass
值得注意的是:Python 3.0-Python3.3之間,繼承抽象基類的語法是class ClassName(metaclass=adc.ABCMeta),其他版本是:class ClassName(abc.ABC)。
collections.abc模塊中各個抽象基類的UML類圖
No.7 isinstence和type的區別
class A(object):
pass
class B(A):
pass
b = B()
print(isinstance(b, B))
print(isinstance(b, A))
print(type(b) is B)
print(type(b) is A)
# True
# True
# True
# False
No.8 類變量和實例變量
實例變量只能通過類的實例進行調用
修改模板對象創建的對象的屬性,模板對象的屬性不會改變
修改模板對象的屬性,由模板對象創建的對象的屬性會改變
# 此處的類也是模板對象,Python中一切皆對象
class A(object):
#類變量
number = 12
def __init__(self):
# 實例變量
self.number_2 = 13
# 實例變量只能通過類的實例進行調用
print(A.number) # 12
print(A().number) # 12
print(A().number_2) # 13
# 修改模板對象創建的對象的屬性,模板對象的屬性不會改變
a = A()
a.number = 18
print(a.number) # 18
print(A().number) # 12
print(A.number) # 12
# 修改模板對象的屬性,由模板對象創建的對象的屬性會改變
A.number = 19
print(A.number) # 19
print(A().number) # 19
No.9 類和實例屬性以及方法的查找順序
在Python 2.2之前只有經典類,到Python2.7還會兼容經典類,Python3.x以后只使用新式類,Python之前版本也會兼容新式類
Python 2.2 及其之前類沒有基類,Python新式類需要顯式繼承自object,即使不顯式繼承也會默認繼承自object
經典類在類多重繼承的時候是采用從左到右深度優先原則匹配方法的.而新式類是采用C3算法
經典類沒有MRO和instance.mro()調用的
假定存在以下繼承關系:
class D(object):
def say_hello(self):
pass
class E(object):
pass
class B(D):
pass
class C(E):
pass
class A(B, C):
pass
采用DFS(深度優先搜索算法)當調用了A的say_hello()方法的時候,系統會去B中查找如果B中也沒有找到,那么去D中查找,很顯然D中存在這個方法,但是DFS對于以下繼承關系就會有缺陷:
class D(object):
pass
class B(D):
pass
class C(D):
def say_hello(self):
pass
class A(B, C):
pass
在A的實例對象中調用say_hello方法時,系統會先去B中查找,由于B類中沒有該方法的定義,所以會去D中查找,D類中也沒有,系統就會認為該方法沒有定義,其實該方法在C中定義了。所以考慮使用BFS(廣度優先搜索算法),那么問題回到第一個繼承關系,假定C和D具備重名方法,在調用A的實例的方法時,應該先在B中查找,理應調用D中的方法,但是使用BFS的時候,C類中的方法會覆蓋D類中的方法。在Python 2.3以后的版本中,使用C3算法:
# 獲取解析順序的方法
類名.mro()
類名.__mro__
inspect.getmro(類名)
使用C3算法后的第二種繼承順序:
class D(object):
pass
class B(D):
pass
class C(D):
def say_hello(self):
pass
class A(B, C):
pass
print(A.mro()) # [, , , , ]
使用C3算法后的第一種繼承順序:
class D(object):
pass
class E(object):
pass
class B(D):
pass
class C(E):
pass
class A(B, C):
pass
print(A.mro())
# [, , , , , ]
在這里僅介紹了算法的作用和演變歷史,關于深入詳細解析,請看我的其他文章——《從Python繼承談起,到C3算法落筆》。
No.10 類方法、實例方法和靜態方法
class Demo(object):
# 類方法
@classmethod
def class_method(cls, number):
pass
# 靜態方法
@staticmethod
def static_method(number):
pass
# 對象方法/實例方法
def object_method(self, number):
pass
實例方法只能通過類的實例來調用;靜態方法是一個獨立的、無狀態的函數,緊緊依托于所在類的命名空間上;類方法在為了獲取類中維護的數據,比如:
class Home(object):
# 房間中人數
__number = 0
@classmethod
def add_person_number(cls):
cls.__number += 1
@classmethod
def get_person_number(cls):
return cls.__number
def __new__(self):
Home.add_person_number()
# 重寫__new__方法,調用object的__new__
return super().__new__(self)
class Person(Home):
def __init__(self):
# 房間人員姓名
self.name = 'name'
# 創建人員對象時調用Home的__new__()方法
tom = Person()
print(type(tom)) #
alice = Person()
bob = Person()
test = Person()
print(Home.get_person_number())
No.11 數據封裝和私有屬性
Python中使用雙下劃線+屬性名稱實現類似于靜態語言中的private修飾來實現數據封裝。
class User(object):
def __init__(self, number):
self.__number = number
self.__number_2 = 0
def set_number(self, number):
self.__number = number
def get_number(self):
return self.__number
def set_number_2(self, number2):
self.__number_2 = number2
# self.__number2 = number2
def get_number_2(self):
return self.__number_2
# return self.__number2
u = User(25)
print(u.get_number()) # 25
# 真的類似于Java的反射機制嗎?
print(u._User__number) # 25
# 下面又是啥情況。。。想不明白了T_T
u.set_number_2(18)
print(u.get_number_2()) # 18
print(u._User__number_2)
# Anaconda 3.6.3 第一次是:u._User__number_2 第二次是:18
# Anaconda 3.6.5 結果都是 0
# 代碼我改成了正確答案,感謝我大哥給我指正錯誤,我保留了錯誤痕跡
# 變量名稱寫錯了,算是個寫博客突發事故,這問題我找了一天,萬分感謝我大哥,我太傻B了,犯了低級錯誤
# 留給和我一樣的童鞋參考我的錯我之處吧!
# 正確結果:
# 25 25 18 18
No.12 Python的自省機制
自省(introspection)是一種自我檢查行為。在計算機編程中,自省是指這種能力:檢查某些事物以確定它是什么、它知道什么以及它能做什么。自省向程序員提供了極大的靈活性和控制力。
dir([obj]):返回傳遞給它的任何對象的屬性名稱經過排序的列表(會有一些特殊的屬性不包含在內)
getattr(obj, attr):返回任意對象的任何屬性 ,調用這個方法將返回obj中名為attr值的屬性的值
... ...
No.13 super函數
Python3.x 和 Python2.x 的一個區別是: Python 3 可以使用直接使用 super().xxx 代替 super(type[, object-or-type]).xxx 。
super()函數用來調用MRO(類方法解析順序表)的下一個類的方法。
No.14 Mixin繼承
在設計上將Mixin類作為功能混入繼承自Mixin的類。使用Mixin類實現多重繼承應該注意:
Mixin類必須表示某種功能
職責單一,如果要有多個功能,就要設計多個Mixin類
不依賴子類實現,Mixin類的存在僅僅是增加了子類的功能特性
即使子類沒有繼承這個Mixin類也可以工作
class Cat(object):
def eat(self):
print("I can eat.")
def drink(self):
print("I can drink.")
class CatFlyMixin(object):
def fly(self):
print("I can fly.")
class CatJumpMixin(object):
def jump(self):
print("I can jump.")
class TomCat(Cat, CatFlyMixin):
pass
class PersianCat(Cat, CatFlyMixin, CatJumpMixin):
pass
if __name__ == '__main__':
# 湯姆貓沒有跳躍功能
tom = TomCat()
tom.fly()
tom.eat()
tom.drink()
# 波斯貓混入了跳躍功能
persian = PersianCat()
persian.drink()
persian.eat()
persian.fly()
persian.jump()
No.25 上下文管理器with語句與contextlib簡化
普通的異常捕獲機制:
try:
pass
except Exception as err:
pass
else:
pass
finally:
pass
with簡化了異常捕獲寫法:
class Demo(object):
def __enter__(self):
print("enter...")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("exit...")
def echo_hello(self):
print("Hello, Hello...")
with Demo() as d:
d.echo_hello()
# enter...
# Hello, Hello...
# exit...
import contextlib
# 使用裝飾器
@contextlib.contextmanager
def file_open(file_name):
# 此處寫__enter___函數中定義的代碼
print("enter function code...")
yield {}
# 此處寫__exit__函數中定義的代碼
print("exit function code...")
with file_open("json.json") as f:
pass
# enter function code...
# exit function code...
No.26 序列類型的分類
容器序列:list tuple deque
扁平序列:str bytes bytearray array.array
可變序列:list deque bytearray array
不可變序列:str tuple bytes
No.27 +、+=、extend()之間的區別于應用場景
首先看測試用例:
# 創建一個序列類型的對象
my_list = [1, 2, 3]
# 將現有的序列合并到my_list
extend_my_list = my_list + [4, 5]
print(extend_my_list) # [1, 2, 3, 4, 5]
# 將一個元組合并到這個序列
extend_my_list = my_list + (6, 7)
# 拋出異常 TypeError: can only concatenate list (not "tuple") to list
print(extend_my_list)
# 使用另一種方式合并
extend_my_list += (6, 7)
print(extend_my_list) # [1, 2, 3, 4, 5, 6, 7]
# 使用extend()函數進行合并
extend_my_list.extend((7, 8))
print(extend_my_list) # [1, 2, 3, 4, 5, 6, 7, 7, 8]
由源代碼片段可知:
class MutableSequence(Sequence):
__slots__ = ()
"""All the operations on a read-write sequence.
Concrete subclasses must provide __new__ or __init__,
__getitem__, __setitem__, __delitem__, __len__, and insert().
"""
# extend()方法內部使用for循環來append()元素,它接收一個可迭代序列
def extend(self, values):
'S.extend(iterable) -- extend sequence by appending elements from the iterable'
for v in values:
self.append(v)
# 調用 += 運算的時候就是調用該函數,這個函數內部調用extend()方法
def __iadd__(self, values):
self.extend(values)
return self
No.28 使用bisect維護一個已排序的序列
import bisect
my_list = []
bisect.insort(my_list, 2)
bisect.insort(my_list, 9)
bisect.insort(my_list, 5)
bisect.insort(my_list, 5)
bisect.insort(my_list, 1)
# insort()函數返回接收的元素應該插入到指定序列的索引位置
print(my_list) # [1, 2, 5, 5, 9]
No.29 deque類詳解
deque是Python中一個雙端隊列,能在隊列兩端以$O(1)$的效率插入數據,位于collections模塊中。
from collections import deque
# 定義一個雙端隊列,長度為3
d = deque(maxlen=3)
deque類的源碼:
class deque(object):
"""
deque([iterable[, maxlen]]) --> deque object
一個類似列表的序列,用于對其端點附近的數據訪問進行優化。
"""
def append(self, *args, **kwargs):
""" 在隊列右端添加數據 """
pass
def appendleft(self, *args, **kwargs):
""" 在隊列左端添加數據 """
pass
def clear(self, *args, **kwargs):
""" 清空所有元素 """
pass
def copy(self, *args, **kwargs):
""" 淺拷貝一個雙端隊列 """
pass
def count(self, value):
""" 統計指定value值的出現次數 """
return 0
def extend(self, *args, **kwargs):
""" 使用迭代的方式擴展deque的右端 """
pass
def extendleft(self, *args, **kwargs):
""" 使用迭代的方式擴展deque的左端 """
pass
def index(self, value, start=None, stop=None): __doc__
"""
返回第一個符合條件的索引的值
"""
return 0
def insert(self, index, p_object):
""" 在指定索引之前插入 """
pass
def pop(self, *args, **kwargs): # real signature unknown
""" 刪除并返回右端的一個元素 """
pass
def popleft(self, *args, **kwargs): # real signature unknown
""" 刪除并返回左端的一個元素 """
pass
def remove(self, value): # real signature unknown; restored from __doc__
""" 刪除第一個與value相同的值 """
pass
def reverse(self): # real signature unknown; restored from __doc__
""" 翻轉隊列 """
pass
def rotate(self, *args, **kwargs): # real signature unknown
""" 向右旋轉deque N步, 如果N是個負數,那么向左旋轉N的絕對值步 """
pass
def __add__(self, *args, **kwargs): # real signature unknown
""" Return self+value. """
pass
def __bool__(self, *args, **kwargs): # real signature unknown
""" self != 0 """
pass
def __contains__(self, *args, **kwargs): # real signature unknown
""" Return key in self. """
pass
def __copy__(self, *args, **kwargs): # real signature unknown
""" Return a shallow copy of a deque. """
pass
def __delitem__(self, *args, **kwargs): # real signature unknown
""" Delete self[key]. """
pass
def __eq__(self, *args, **kwargs): # real signature unknown
""" Return self==value. """
pass
def __getattribute__(self, *args, **kwargs): # real signature unknown
""" Return getattr(self, name). """
pass
def __getitem__(self, *args, **kwargs): # real signature unknown
""" Return self[key]. """
pass
def __ge__(self, *args, **kwargs): # real signature unknown
""" Return self>=value. """
pass
def __gt__(self, *args, **kwargs): # real signature unknown
""" Return self>value. """
pass
def __iadd__(self, *args, **kwargs): # real signature unknown
""" Implement self+=value. """
pass
def __imul__(self, *args, **kwargs): # real signature unknown
""" Implement self*=value. """
pass
def __init__(self, iterable=(), maxlen=None): # known case of _collections.deque.__init__
"""
deque([iterable[, maxlen]]) --> deque object
A list-like sequence optimized for data accesses near its endpoints.
# (copied from class doc)
"""
pass
def __iter__(self, *args, **kwargs): # real signature unknown
""" Implement iter(self). """
pass
def __len__(self, *args, **kwargs): # real signature unknown
""" Return len(self). """
pass
def __le__(self, *args, **kwargs): # real signature unknown
""" Return self<=value. """
pass
def __lt__(self, *args, **kwargs): # real signature unknown
""" Return self
pass
def __mul__(self, *args, **kwargs): # real signature unknown
""" Return self*value.n """
pass
@staticmethod # known case of __new__
def __new__(*args, **kwargs): # real signature unknown
""" Create and return a new object. See help(type) for accurate signature. """
pass
def __ne__(self, *args, **kwargs): # real signature unknown
""" Return self!=value. """
pass
def __reduce__(self, *args, **kwargs): # real signature unknown
""" Return state information for pickling. """
總結
以上是生活随笔為你收集整理的python3知识点汇总_35个高级Python知识点总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python为什么是蟒蛇_Python
- 下一篇: python能做哪些客户端_发布一个Ht