深入了解Python的類與模塊化
學(xué)習(xí)目標(biāo)
Python 是簡潔、易學(xué)、面向?qū)ο蟮木幊陶Z言。它不僅擁有強大的原生數(shù)據(jù)類型,也提供了簡單易用的控制語句。本節(jié)的主要目標(biāo)是介紹 Python 中的面向?qū)ο缶幊谭妒揭约澳K化思想,為接下來的學(xué)習(xí)奠定基礎(chǔ),本文會完整的介紹學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)和算法所需的 Python 基礎(chǔ)知識及基本思想,并給出相應(yīng)的實戰(zhàn)示例及解釋。
掌握 Python 面向?qū)ο缶幊痰幕靖拍?,并會編?Python 自定義類
掌握 Python 模塊化的編程思想
1. 面向?qū)ο缶幊蹋侯?/h2>
1.1 面向?qū)ο缶幊痰幕靖拍?/h3>
一個完善的程序是由數(shù)據(jù)和指令組成的。過程式編程利用“分而治之”的思想,使用函數(shù)對數(shù)據(jù)進行處理,數(shù)據(jù)與函數(shù)之前的關(guān)系是松散的,即同樣的數(shù)據(jù)可以被程序中的所有函數(shù)訪問,而一個函數(shù)也可以訪問程序中的不同數(shù)據(jù)。這導(dǎo)致了,如果出現(xiàn)異常,需要在整個系統(tǒng)中查找錯誤代碼。
為了解決這一問題,面向?qū)ο缶幊?(Object Oriented Programming, OOP) 將系統(tǒng)劃分為不同對象,每個對象包含自身的信息數(shù)據(jù)以及操作這些數(shù)據(jù)的方法。例如,每個字符串對象具有字符數(shù)據(jù),同時還具有改變大小寫、查找等方法。
面向?qū)ο缶幊淌褂妙惷枋銎渌乃袑ο蟮墓餐匦?屬性),即數(shù)據(jù)屬性(也稱數(shù)據(jù)成員或成員變量)和功能屬性(也稱成員函數(shù)或方法)。
一個類的對象也稱為這個類的一個實例。例如,32 就是一個整數(shù)類 int 的對象,可以使用函數(shù) type()
來獲取對象所屬類:
>>> type(32) <class 'int'>
可以利用內(nèi)置函數(shù) dir()
查詢類的屬性:
>>> dir(32) ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'as_integer_ratio', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
在繼續(xù)講解之前,我們首先來快速介紹下面向?qū)ο蟮娜筇匦浴鄳B(tài)、封裝和繼承。
1.1.1 多態(tài)
多態(tài):可對不同類型的對象執(zhí)行相同的操作。
多態(tài)其實很常見,例如列表對象和元組對象都具有 count
方法,使用變量調(diào)用 count
方法時,我們無需知道它究竟是列表還是元組,這就是多態(tài)的作用。這不僅僅適用于方法,許多內(nèi)置運算符和函數(shù)也使用了多態(tài):
>>> [1,3,3,3].count(3) 3 >>> (1,3,3,3).count(3) 3 >>> [1,3]+[1,3] [1, 3, 1, 3] >>> 'hello' + ' world!' 'hello world!'
1.1.2 封裝
封裝:對外部隱藏有關(guān)對象具體操作的細節(jié)。
封裝與多態(tài)類似,都屬于抽象原則,都用于處理程序的組成部分而無需關(guān)心不必要的細節(jié),但不同的是,多態(tài)使我們無需知道對象所屬的類就能調(diào)用其方法,而封裝使我們無需知道對象的內(nèi)部構(gòu)造就能使用它。例如我們將虛數(shù)的實部和虛部作為對象的數(shù)據(jù)屬性,就是將對象的屬性“封裝”在對象中。
1.1.3 繼承
繼承:用于建立類的層次結(jié)構(gòu),基于上層的類創(chuàng)建出新類。
如果我們有了一些類,再創(chuàng)建新的類時發(fā)現(xiàn)與已存在的類十分相似,只需要添加一些新方法,那么我們可能不想復(fù)制舊類的代碼至新類中,這時我們就要用到繼承了。例如,我們有了一個 Fruit
類,具有描述外觀的方法 show_shape
,如果想要新建一個 Apple
類,除了描述外觀外,我們還想知道如何計算總價,那么我們就可以讓 Apple
類繼承 Fruit
的方法,使得對 Apple
對象調(diào)用方法 show_shape
時,將自動調(diào)用 Fruit
類的這個方法。
1.2 自定義類
我們已經(jīng)知道抽象數(shù)據(jù)類型就是一個由對象以及對象上的操作組成的集合,對象和操作被捆綁為一個整體,不但可以使用對象的數(shù)據(jù)屬性,還可以使用對象上的操作。操作(在類中稱為方法)定義了抽象數(shù)據(jù)類型和程序其他部分之間的接口。接口定義了操作要做什么,但沒有說明如何做,因此我們可以說抽象的根本目標(biāo)是隱藏操作的細節(jié)。而類就是為了實現(xiàn)數(shù)據(jù)抽象類型。
Python 用關(guān)鍵字 class
定義一個類,格式如下,其中方法定義與函數(shù)定義語法類似:
class 類名:
方法定義
接下來構(gòu)建實現(xiàn)抽象數(shù)據(jù)類型 Imaginary
(虛數(shù))的類,用于展示如何實現(xiàn)自定義類。
定義類時首先需要提供構(gòu)造方法,構(gòu)造方法定義了數(shù)據(jù)對象的創(chuàng)建方式。要創(chuàng)建一個 Imaginary
對象,需要提供實部和虛部兩部分數(shù)據(jù),Python 中,__init__()
作為構(gòu)造方法名:
class Imaginary: def __init__(self, real, imag): self.real = real self.imag = imag
形式參數(shù)列表的第一項是一個指向?qū)ο蟊旧淼奶厥鈪?shù)(習(xí)慣上通常使用 self
),在調(diào)用時不需要提供相應(yīng)的實際參數(shù),而構(gòu)造方法中的剩余參數(shù)必須提供相應(yīng)的實參,使得新創(chuàng)建的對象能夠知道其初始值,與函數(shù)定義一樣,可以通過默認值為形參提供默認實參。如在 Imaginary
類中,self.real
定義了 Imaginary
對象有一個名為 real
的內(nèi)部數(shù)據(jù)對象作為其實部數(shù)據(jù)屬性,而self.imag
則定義了虛部。
創(chuàng)建 Imaginary
類的實例時,會調(diào)用類中定義的構(gòu)造方法,使用類名并且傳入數(shù)據(jù)屬性的實際值完成調(diào)用:
>>> imaginary_a = Imaginary(6, 6) >>> imaginary_a <__main__.Imaginary object at 0x0000020CF1B80160>
以上代碼創(chuàng)建了一個對象,名為 imaginary_a
,值為 6+6i,這就是封裝的示例,將數(shù)據(jù)屬性和操作數(shù)據(jù)屬性的方法打包在對象中。
除了實例化外,類還支持另一操作:屬性引用(包括數(shù)據(jù)屬性和功能屬性),通過點標(biāo)記法訪問與類關(guān)聯(lián)的屬性:
>>> imaginary_a.real 6 >>> imaginary_a.imag 6
除了數(shù)據(jù)屬性外,還需要實現(xiàn)抽象數(shù)據(jù)類型所需要的方法(功能屬性),需要牢記的是,方法的第一個參數(shù) self
是必不可少的,例如要實現(xiàn)打印實例化的虛數(shù)對象,編寫類方法 display()
:
class Imaginary: def __init__(self, real, imag): self.real = real self.imag = imag def display(self): print('{}{:+}i'.format(self.real, self.imag))
調(diào)用類方法打印實例化的虛數(shù)對象:
>>> imaginary_a = Imaginary(6, 6) >>> imaginary_a.display() 6+6i >>> print(imaginary_a) <__main__.Imaginary object at 0x0000020CF1B72D90>
可以看到,如果使用 print()
函數(shù)只能打印存儲在變量中的地址,這是由于將對象轉(zhuǎn)換成字符串的方法 __str__()
的默認實現(xiàn)是返回實例的地址字符串,如果想要使用 print
函數(shù)打印對象,需要重寫默認的 __str__()
方法,或者說重載該方法:
>>> imaginary_a = Imaginary(6, 6) >>> imaginary_a.display() 6+6i >>> print(imaginary_a) <__main__.Imaginary object at 0x0000020CF1B72D90>
此時如果再次使用 print()
函數(shù),就可以直接打印對象了:
>>> imaginary_a = Imaginary(6, 6) >>> print(imaginary_a) 6+6i
可以重載類中的很多方法,最常見的是重載運算符,這是由于人們習(xí)慣使用熟悉的運算符對數(shù)據(jù)進行運算,這要比使用函數(shù)對數(shù)據(jù)進行運算更加直觀且易于理解,如表達式:8 + 6 / 3,如果用函數(shù)則為:add(8, div(6, 3)),顯然前者比后者更加符合習(xí)慣。 如果某種類型的對象要使用常見運算符,就必須對這種類型重新定義相應(yīng)的運算符函數(shù),例如,Python 對于 int 整型、float 浮點型、str 字符串類型等都重新定義了乘法運算符函數(shù),對一個類型重新定義運算符函數(shù)的也稱“運算符重載”。我們可以編寫 Imaginary
類的 __mul__()
方法重載乘法運算:
class Imaginary: def __init__(self, real, imag): self.real = real self.imag = imag def display(self): print('{}{:+}i'.format(self.real, self.imag)) def __str__(self): print('{}{:+}i'.format(self.real, self.imag)) def __mul__(self, other): new_real = self.real * other.real - self.imag * other.imag new_imag = self.real * other.imag + self.imag * other.real return Imaginary(new_real, new_imag)
還可以重載其他運算符,如比較運算符 ==,即 __eq__()
方法,重載 Imaginary
類的 __eq__()
方法允許兩個虛數(shù)進行比較,查看它們的值是否相等,這也稱為深相等;而根據(jù)引用進行判斷的淺相等,只有兩個變量是同一個對象的引用時才相等:
# shallow_and_deep_equal.py class ImaginaryFirst: def __init__(self, real, imag): self.real = real self.imag = imag def display(self): print('{}{:+}i'.format(self.real, self.imag)) def __str__(self): print('{}{:+}i'.format(self.real, self.imag)) class Imaginary: def __init__(self, real, imag): self.real = real self.imag = imag def display(self): print('{}{:+}i'.format(self.real, self.imag)) def __str__(self): print('{}{:+}i'.format(self.real, self.imag)) def __eq__(self, other): return self.real == other.real and self.imag == self.imag print('淺相等:只有兩個變量是同一個對象的引用時才相等。') imag_1 = imag_2 = ImaginaryFirst(6, 6) print('imag_1 == imag_2 ', imag_1 == imag_2) imag_1 = ImaginaryFirst(6, 6) imag_2 = ImaginaryFirst(6, 6) print('imag_1 == imag_2 ', imag_1 == imag_2) print('深相等:兩個變量的值相等即表示對象相等。') imag_1 = imag_2 = Imaginary(6, 6) print('imag_1 == imag_2 ', imag_1 == imag_2) imag_1 = Imaginary(6, 6) imag_2 = Imaginary(6, 6) print('imag_1 == imag_2 ', imag_1 == imag_2)
程序運行結(jié)果如下所示:
淺相等:只有兩個變量是同一個對象的引用時才相等。
imag_1 == imag_2? ?True
imag_1 == imag_2? ?False
深相等:兩個變量的值相等即表示對象相等。
imag_1 == imag_2? ?True
imag_1 == imag_2? ?True
1.3 再談繼承
1.3.1 繼承實例
繼承可以建立一組彼此相關(guān)的抽象,能夠建立一個類的層次結(jié)構(gòu),這樣的關(guān)系結(jié)構(gòu)也稱為繼承層次結(jié)構(gòu),每個類都可以從上層的類繼承屬性。在 Python 中,object
類位于最頂層。
下層的新類會繼承已有類的屬性,同時添加自己特有的一些屬性,這個新的類就稱為“派生類”或“子類”,而原有的類稱為“基類”、“父類”或“超類”。利用父類定義子類,需要在定義的類名后添加圓括號,圓括號內(nèi)寫入父類名。如果沒有顯式地說明一個類的父類,則默認其父類為 object
。
例如三角形,包括銳角三角形、直角三角形和鈍角三角形,因此定義類時,除了定義一般三角形的類 Triangle
外,還可以定義銳角三角形的類 AcuteTriangle
等,這時我們就可以令 AcuteTriangle
類繼承 Triangle
類:
class Triangle: def __init__(self, edge_1, edge_2, edge_3): self.edge_1 = edge_1 self.edge_2 = edge_2 self.edge_3 = edge_3 def __str__(self): return str((self.edge_1, self.edge_2, self.edge_3)) def print_info(self): print('The three sides of a triangle are {}, {} and {}'.format(self.edge_1, self.edge_2, self.edge_3)) def perimeter(self): return self.edge_1 + self.edge_2 + self.edge_3 class AcuteTriangle(Triangle): def __init__(self, edge_1, edge_2, edge_3, max_angle): # 使用父類構(gòu)造函數(shù)進行初始化 Triangle.__init__(self, edge_1, edge_2, edge_3) self.max_angle = max_angle def print_info(self): Triangle.print_info(self) print('The max angle is {}'.format(self.max_angle)) def get_max_angle(self): return self.max_angle
可以看到子類除了繼承外,還可以:
- 添加新屬性,例如子類
AcuteTriangle
中新增了數(shù)據(jù)屬性max_angle
以及方法屬性get_max_angle
; - 替換(覆蓋)父類中的屬性,例如AcuteTriangle覆蓋了父類的__init__()和
print_info()
方法。以AcuteTriangle.__init__()
方法為例,首先調(diào)用Triangle.__init__()
初始化被繼承的實例變量 self.edge_1,self.edge_2,self.edge_3, 然后初始化self.max_angle
,這個實例變量只在AcuteTriangle
實例中才有,而Triangle
實例中沒有。
>>> triangle_a = Triangle(3, 4, 6) >>> triangle_a.print_info() The three sides of a triangle are 3, 4 and 6 >>> triangle_b = AcuteTriangle(3, 3, 3, 60) >>> triangle_b.print_info() The three sides of a triangle are 3, 3 and 3 The max angle is 60
在子類中可以通過 super()
方法來調(diào)用父類的方法,這種方法可以省略父類名:
class AcuteTriangle(Triangle): def __init__(self, edge_1, edge_2, edge_3, max_angle): # 使用父類構(gòu)造函數(shù)進行初始化 super().__init__(self, edge_1, edge_2, edge_3) self.max_angle = max_angle def print_info(self): super().print_info(self) print('The max angle is {}'.format(self.max_angle)) def get_max_angle(self): return self.max_angle
使用內(nèi)置函數(shù) isinstance()
可以檢查一個對象是否是某個類的實例(對象),而要確定一個類是否是另一個類的子類,則可以使用內(nèi)置方法 issubclass()
:
>>> triangle_a = Triangle(3, 4, 6) >>> triangle_b = AcuteTriangle(3, 3, 3, 60) >>> print(isinstance(triangle_a, Triangle)) True >>> print(isinstance(triangle_a, AcuteTriangle)) False >>> print(isinstance(triangle_b, AcuteTriangle)) True >>> print(isinstance(triangle_b, Triangle)) True >>> print(issubclass(AcuteTriangle, Triangle)) True >>> print(issubclass(Triangle, AcuteTriangle)) False
因為類 AcuteTriangle
是從類 Triangle
派生出來的,所以一個類 AcuteTriangle
對象當(dāng)然也是一個類 Triangle
對象,正如“一個銳角三角形也是一個三角形”。
1.3.2 多繼承
一個類可以繼承多個類的特性,這也稱為多繼承,例如:
class RightTriangle(Triangle): def area(self): return self.edge_1 * self.edge_2 * 0.5 def print_name(self): print('This is a right triangle!') class IsoscelesTriangle(Triangle): def print_name(self): print('This is an isosceles triangle!') class IsoscelesRightTriangle(RightTriangle, IsoscelesTriangle): pass
以上示例中,pass
語句不做任何事,其作用相當(dāng)于占位符,以等待后續(xù)補充代碼;也可以用于語法上需要語句而實際不需要做任何工作的地方。
2. 模塊
我們已經(jīng)知道,函數(shù)和類都是可以重復(fù)調(diào)用的代碼塊。在程序中使用位于不同文件的代碼塊的方法是:導(dǎo)入 (import
) 該對象所在的模塊 (mudule
)。
在之前的示例中,我們總是使用 shell
,或假設(shè)整個程序保存在一個文件中,這在程序比較小時可能沒有什么問題。但程序變得越來越大時,將程序的不同部分根據(jù)不同分類方法保存在不同文件中通常會更加方便。
2.1 導(dǎo)入模塊
Python 模塊允許我們方便地使用多個文件中的代碼來構(gòu)建程序。模塊就是一個包含 Python 定義和語句的 .py 文件。
例如我們創(chuàng)建一個 hello_world.py 文件,就可以理解為創(chuàng)建了一個名為 hello_world 的模塊:
# hello_world.py def print_hello(): print('Hello World!') class Triangle: def __init__(self, edge_1, edge_2, edge_3): self.edge_1 = edge_1 self.edge_2 = edge_2 self.edge_3 = edge_3 def __str__(self): return str((self.edge_1, self.edge_2, self.edge_3)) def print_info(self): print('The three sides of a triangle are {}, {} and {}'.format(self.edge_1, self.edge_2, self.edge_3)) def perimeter(self): return self.edge_1 + self.edge_2 + self.edge_3
可將模塊視為擴展,要導(dǎo)入模塊,需要使用關(guān)鍵字 import,導(dǎo)入模塊的一般格式如下:
import module_1[, module_2....] # 可以同時導(dǎo)入多個模塊
例如在 test.py 文件要導(dǎo)入 hello_world 模塊:
import hello_world
導(dǎo)入的模塊只要說明模塊名即可,不需要也不能帶有文件擴展名 .py。如果要使用模塊中的對象,如函數(shù)、類等,需要用使用句點運算符 (.),即使用“模塊名.對象”進行訪問。例如,使用 hello_worl.Triangle 訪問模塊 hello_world 中的類 Triangle:
# test_1.py import hello_world hello_world.print_hello() tri_a = hello_world.Triangle(3, 4, 5) print(tri_a)
程序輸出如下所示:
Hello World!
(3, 4, 5)
需要注意的是,導(dǎo)入的模塊要位于相同的目錄層次下,否則需要添加目錄結(jié)構(gòu),例如,如果 hello_world 位于子目錄 module 下,則需要使用如下方式:
# test_2.py import module.hello_world module.test.print_hello()
程序輸出如下所示:
Hello World!
2.2 導(dǎo)入Python標(biāo)準(zhǔn)模塊
Python 提供了許多標(biāo)準(zhǔn)模塊,這些模塊文件位于 Python 安裝目錄的 lib 文件夾中??梢韵駥?dǎo)入自己編寫的模塊一樣導(dǎo)入標(biāo)準(zhǔn)模塊,例如導(dǎo)入 math 模塊,使用其中的對象:
# test_3.py import math print('sqrt(4) = ', math.sqrt(4)) print('sin(π/6) = ', math.sin(math.pi /6))
程序輸出如下所示:
sqrt(4) = 2.0
sin(π/6) = 0.49999999999999994
這里可能大家會有一個疑問,這里導(dǎo)入的模塊和當(dāng)前文件并不在同一目錄下,為什么不需要使用模塊路徑?這個問題也可以轉(zhuǎn)換為——當(dāng)我們使用 import 語句的時候,Python 解釋器是怎樣找到對應(yīng)的文件的呢?
這就涉及到 Python 的搜索路徑,搜索路徑是由一系列目錄名組成的,Python 解釋器就依次從這些目錄中去尋找所引入的模塊。搜索路徑被存儲在 sys 模塊中的 path 變量中:
>>> import sys >>> sys.path ['', 'D:\\Program Files\\Python39\\python39.zip', 'D:\\Program Files\\Python39\\DLLs', 'D:\\Program Files\\Python39\\lib', 'D:\\Program Files\\Python39', 'D:\\Program Files\\Python39\\lib\\site-packages'
2.3 單獨導(dǎo)入模塊中所需對象
我們可能不想每次調(diào)用模塊中的對象時都指定模塊名,這時,我們可以使用 from module import object,從模塊中單獨導(dǎo)入所需對象,同時使用這個單獨導(dǎo)入的對象時就不需要在前面添加“模塊名.”前綴了:
# test_4.py from math import pi, sin print('sqrt(4) = ', sqrt(4)) print('sin(π/6) = ', sin(math.pi /6))
2.4 導(dǎo)入模塊中的所有對象
可以通過 from module import *導(dǎo)入模塊中的所有對象,同樣不再需要模塊名前綴:
# test_5.py from math import * print('sqrt(4) = ', sqrt(4)) print('sin(π/6) = ', sin(math.pi /6))
不同程序代碼中不可避免地可能會使用了同一個名字來命名不同對象,這時就會引起沖突,但如果這些名字屬于不同的模塊,就可以通過模塊名來區(qū)分它們,因此為了避免名字沖突,應(yīng)盡量避免使用 from module import object 或 from module import * 導(dǎo)入對象。
2.5 重命名導(dǎo)入模塊或?qū)ο?/h3>
另一種避免名字沖突的方法是重命名導(dǎo)入模塊或?qū)ο螅?/p>
# test_6.py import math as m from datetime import date as d print(d.today()) print('sqrt(4) = ', m.sqrt(4)) print('sin(π/6) = ', m.sin(math.pi /6))
程序輸出如下所示:
datetime.date(2021, 12, 3)
sqrt(4) = 2.0
sin(π/6) = 0.49999999999999994
可以看到附加的好處是可以使用簡寫,減少編碼工作量。
2.6 導(dǎo)入第三方模塊
除了標(biāo)準(zhǔn)庫外,Python 也具有規(guī)模龐大的第三方庫,覆蓋了信息技術(shù)幾乎所有領(lǐng)域,這也是 Python 的其中一個巨大優(yōu)勢。下面以常用可視化庫 matplotlib 為例介紹第三方庫的使用。和標(biāo)準(zhǔn)庫不同,使用第三方庫首先要進行安裝,在 shell 命令中使用 pip 命令可以快速安裝所需庫:
pip install matplotlib
安裝完成后,使用第三方庫就和標(biāo)準(zhǔn)庫沒有任何差別了:
# cos_1.py import math from matplotlib import pyplot as plt scale = range(100) x = [(2 * math.pi * i) / len(scale) for i in scale] y = [math.cos(i) for i in x] plt.plot(x, y) plt.show()
以上就是深入了解Python的類與模塊化的詳細內(nèi)容,更多關(guān)于Python 類 模塊化的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
閉包在python中的應(yīng)用之translate和maketrans用法詳解
這篇文章主要介紹了閉包在python中的應(yīng)用之translate和maketrans用法,是比較實用的技巧,需要的朋友可以參考下2014-08-08Python 獲取命令行參數(shù)內(nèi)容及參數(shù)個數(shù)的實例
今天小編就為大家分享一篇Python 獲取命令行參數(shù)內(nèi)容及參數(shù)個數(shù)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12Python json模塊與jsonpath模塊區(qū)別詳解
這篇文章主要介紹了Python json模塊與jsonpath模塊區(qū)別詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03django創(chuàng)建超級用戶時指定添加其它字段方式
這篇文章主要介紹了django創(chuàng)建超級用戶時指定添加其它字段方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05