工作中,我們使用一些之前沒用到過的模塊,使用時需要了解一下這個模塊中的一些類的方法或屬性,怎么做呢?目前我比較常用的兩款IDE“Pycharm”和“VSCode”,都可以通過先導包,然后通過“Ctrl+鼠標左鍵”,進入源碼后觀看並膜拜一下大神們的代碼,當然也可以進入我們在項目中自己所定義的,然后進行快速修改,真的是很方便呢。但是有的時候,我們使用的環境沒有這類的IDE,那該怎么學習我們要用的這些類方法和屬性呢?方法當然很多,無論是小白,還是大神,百度谷歌大法都是比較快速和方便的。但是對於一些剛開源的或者是我們自己定義的呢,這里我們就聊聊Python 中的內建函數——dir 函數
首先可以先通過簡單的源碼解讀,可以得知:
1.他的返回值是一個元素為字符串的列表
2.當傳入一個模塊對象時,返回的是模塊里面所有的屬性(變量名和方法)
我在function_use 這個文件夾或者包中創建了一個模塊(demo01.py),內容隨便定義幾個變量和函數及類,如:
1 a = 10 2 b = 'test' 3 4 def c(x): 5 print(x) 6 7 class D(object): 8 def __init__(self): 9 self.name = 'name' 10 self.age = 18 11 12 def get_name(self): 13 return self.name 14 15 class E(D): 16 pass
然后再創建一個模塊(demo02.py),並在"demo02.py"中引用"demo01.py“,然后打印dir(demo01),如:
1 from function_use import demo01 2 3 print(dir(demo01)) 4 5 6 ['D', 'E', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b', 'c']
3.當傳入的對象是一個類時,返回這個類及其所有父類(包括父類的父類)的屬性和方法
就上面的例子,無論是在當前模塊“demo01.py”下面調用:
1 ... 2 if __name__ == '__main__': 3 print(dir(D)) 4 5 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_name']
還是在“demo02.py” 中引用的調用
1 from function_use import demo01 2 3 # print(dir(demo01)) 4 print(dir(demo01.D)) 5 6 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_name']
可以看出,結果是一樣的。
4.當傳入的對象是其他的時候(照我的理解,這個其他對象,就是一個實例對象),則返回這個實例對象的屬性和方法,實例對象類的屬性和方法,以及這個類的所有基類的屬性和方法
相對於第三種情況(傳入的對象是一個類時)其實只是多了這個實例對象的屬性,感覺繞的話,就看下面的例子:
老樣子,在”demo01.py“ 里面
1 ... 2 if __name__ == '__main__': 3 e = E() 4 print(dir(e)) 5 6 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'get_name', 'name']
或者在”demo02.py“ 里面
1 from function_use import demo01 2 3 # print(dir(demo01)) 4 e = demo01.E() 5 print(dir(e)) 6 7 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'get_name', 'name']
可以看到,只是多了E 的實例對象的兩個屬性“age” 和“name”
===================問題分割線===================
這里就有一個待解決的問題,就上面的例子,我嘗試了在demo01.py 模塊的D 這個類里面加了一個類方法及類屬性

1 a = 10 2 b = 'test' 3 4 5 def c(x): 6 print(x) 7 8 9 class D(object): 10 dd = 123 11 12 def __init__(self): 13 self.name = 'name' 14 self.age = 18 15 16 def get_name(self): 17 return self.name 18 19 @classmethod 20 def print_x(cls): 21 print("x") 22 23 24 class E(D): 25 pass 26 27 28 if __name__ == '__main__': 29 # e = E() 30 # print(dir(e)) 31 print(dir(E)) 32 E.print_x() 33 # print(E.get_name()) 34 35 36 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'dd', 'get_name', 'print_x'] 37 38 x # E.print_x()
這都沒問題,但是我去調用dir 函數返回的“get_name” 函數時,卻提示我必須要傳入一個必傳的參數“self”這樣就需要
print(E.get_name(E()))了,但是這樣的話,為什么這個方法可以出現在dir(E)的返回值里面呢?
有點暈
===================問題分割線===================
說完這個函數的返回值,我們再聊聊其中具體的內容,這里用自定義的例子不好說明,就搬來廖老師的例子吧
首先對一個字符串對象,比如“ABC” 使用dir()函數,查看他的所有屬性和方法
1 print(dir("ABC")) 2 3 ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
可以看出來,字符串對象的屬性和方法還是很多的,類似__xx__的屬性和方法在Python 中都是有特殊用途的,比如__len__方法返回長度。在Python 中,如果你調用len() 函數試圖獲得一個對象的長度,實際上,在len() 函數內部,它自動去調用該對象的__len__() 方法,所以得到兩個結論:
1.下面的代碼是等價的
1 print(len("ABC")) # 3 2 print("ABC".__len__()) # 3
2.對一個對象使用dir 函數,返回的列表里面,如果沒有__len__ 方法,我們去對這個對象使用len 函數,就會報TypeError 的錯
比如對整數類型使用len 函數,或者是上面我們"demo01.py" 里面的"e" 使用len 函數,如果我們想用len(e) 的話,就要自己寫一個__len__() 方法:
1 class D(object): 2 dd = 123 3 4 def __init__(self): 5 self.name = 'name' 6 self.age = 18 7 8 def __len__(self): 9 return 100 10 11 def get_name(self): 12 return self.name 13 14 @classmethod 15 def print_x(cls): 16 print("x") 17 18 19 class E(D): 20 pass 21 22 if __name__ == '__main__': 23 e = E() 24 print(len(e)) # 100
除了這些“__xx__” 特殊格式的方法,剩下的都是普通屬性或方法,比如lower() 返回小寫的字符串
1 print("ABC".lower()) # 'abc'
未完