Table of Contents
01 全局對象與內嵌模塊
什麼是類?類是一個對象(類對象-創建實例對象的模子對象),用它創建的對象爲實例對象
class ObjectCreater(object): |
Py中萬物皆對象,Linux萬物皆文件
Python中有內嵌函數(可以直接調用的函數),如:
input("請輸入>>") print("XXX") list() tuple() dict() set() |
Python運行時默認加載了內建/內嵌模塊,其中帶有這些常用函數
查看到底有哪些函數可以直接用,globals返回可調用的一個字典:
globals() |
新定義一個全局變量:
a=100 |
再查看globals,會增加一行
'a':100, |
新定義一個全局函數:
def AA(): pass |
再查看globals,最新一行會增加
'AA':<function __main__.AA> |
新定義一個類:
class BB(): pass |
globals
'BB':__main__.BB |
定義類時,會給這個類創建內存空間,globals中的名字指向剛剛創建的對象空間
萬物皆對象,這個變量也是對象
在字典中不能出現兩個相同的key,所以最後導入的、最後賦引用的會覆蓋,類、函數、變量不能重名
同理,類的名字指向了這個類對象
類與普通對象的區別只是,它擁有創建其他實例對象空間的能力
但是這個globals中沒有print函數,在內嵌模塊builtin中。查看這個模塊:
xx=globals()#xx指向了這個字典 xx['__builtin__'].__dict__ 'input':<function input> 'print':<function print> |
調用其中函數
yy=xx['__builtin__'].__dict__#保存這個字典 yy['print']("hah") |
輸出:hah
ipython比單用python時有更多命令可以直接用
把所有輸出過的東西存儲在Out字典中,把所有輸入過的東西存儲在In字典中
ipython有一個sqlite數據庫,內嵌型(它不需要建立服務器,讀取時打開文件)
02 元類
需求-改變類空間內容,如:添加一個屬性
類:創建實例對象,實例對象有自己的內存空間,同時也有一部分共享類對象中的數據
元類(python造物主):可以創建類
類也是對象,你可以在運行時創建它們,就像其他任何對象一樣。
可以在函數中創建類,使用class關鍵字即可
>>> def choose_class(name): if name == 'foo': class Foo(object): pass return Foo # 返回的是類,不是類的實例 else: class Bar(object): pass return Bar
>>> MyClass = choose_class('foo') >>> print(MyClass) # 函數返回的是類,不是類的實例 <class '__main__'.Foo> >>> print(MyClass()) # 可以通過這個類創建類實例,也就是對象 <__main__.Foo object at 0x89c6d4c> |
比較標準的創建類的方式是type(一般type用來返回一個對象的類型type(100)
type(類名, 由父類名稱組成的元組(針對無繼承的情況,可以爲空),包含屬性的字典(名稱和值))
B = type("B", (), {"num":100,"num2":200}) |
查看類:
print(help(B)) |
輸出: num=100 num2=200 |
Type是一個元類,Type的返回值是一個類對象
字典不一樣,則屬性不一樣
03 type使用
如果元類創建類時需要繼承
B = type("B", (), {"num":100,"num2":200}) Test22=type("Test22",(B,),{})#元組中至少要放一個',' |
查看新類
print(help(Test22)) |
class Test22(B) ... num = 100 num2 = 200 |
有繼承的類、屬性
添加方法:添加屬性時指向方法引用
def test_2(self): print(">>實例方法") Test3=type("Test3",(),{"test_2":test_2}) |
創建實例對象
t3=Test3() t3.test_2() |
輸出: >>實例方法 |
添加類方法
#類方法 @classmethod def test_3(cls): print(">>類方法") |
Test4=type("Test4",(),{"test_2":test_2,"test_3":test_3}) |
添加靜態方法
#靜態方法 @staticmethod def test_4(): print(">>靜態方法") |
Test5=type("Test5",(),{"test_2":test_2,"test_3":test_3,"test_4":test_4}) |
Demo
class T(object): pass t=T() t.__class__#查看是哪個類創建的 |
輸出 __main__.T |
t.__class__.__class__ |
輸出 type |
即使直接寫,類還是type創建的
元類創建類對象,類對象創建實例對象
元類的功能:
#-*- coding:utf-8 -*- def upper_attr(class_name, class_parents, class_attr):
# 遍歷屬性字典,把不是__開頭的屬性名字變爲大寫 new_attr = {} for name,value in class_attr.items(): if not name.startswith("__"):#過濾掉隱藏的默認屬性 new_attr[name.upper()] = value
# 調用type來創建一個類 return type(class_name, class_parents, new_attr)
class Foo(object, metaclass=upper_attr): bar = 'bip'
print(hasattr(Foo, 'bar')) print(hasattr(Foo, 'BAR'))
f = Foo() print(f.BAR) |
在定義普通類Foo時,如果形如:
class Foo(object): bar = 'bip' |
就調用默認的Type創建類對象,等價於:
Foo=type("Foo",(object,),{"bar":'bip'}) |
Python3:添加參數metaclass=upper_attr:不管在類中定義什麼屬性名,通通變成大寫
Python2:
class Foo(object): __metaclass__ = upper_attr # 設置Foo類的元類爲upper_attr |
不直接調用默認type創建,調用自定義函數創建
自定義函數的返回值:一個類對象
# 調用type來創建一個類 return type(class_name, class_parents, new_attr) |
函數被調用後能像type一樣獲取類名、父類、類屬性,就可以在創建時對他們進行修改後再給type
04 元類應用補充
一般情況不會使用元類
裝飾器在不修改原來函數條件下,調用函數前後加新功能
元類不修改原來類定義中內容,但可以修改類屬性等
之前一直使用的函數當作元類使用,修改爲類:
class UpperAttrMetaClass(type): # __new__ 是在__init__之前被調用的特殊方法 # __new__是用來創建對象並返回的方法 # 而__init__只是用來將傳入的參數初始化給對象 # 你很少用到__new__,除非希望能夠控制對象的創建 # 這裏,創建的對象是類,我們希望能夠自定義它,所以改寫__new__ # 還有一些高級的用法會涉及到改寫__call__特殊方法,但是這裏不用 def __new__(cls, class_name, class_parents, class_attr): # 遍歷屬性字典,把不是__開頭的屬性名字變爲大寫 new_attr = {} for name, value in class_attr.items(): if not name.startswith("__"): new_attr[name.upper()] = value
return type(class_name, class_parents, new_attr) |
在定義了多個類,想要統一修改某些功能屬性時,可以考慮元類
__new__也涉及到單例
Python中沒有數組