help
如果說能夠通過一個函數就能夠學會 Python,那這個函數一定就是 Python 提供的第一 個自帶說明 help()。help 函數的作用就是查看對象的幫組文檔。比如:
>>> help(123)
Help on int object:
class int(object)
-
| int(x=0) -> integer
-
| int(x, base=10) -> integer |
-
| Convert a number or string to an integer, or return 0 if no arguments
-
| are given. If x is a number, return x.__int__(). For floating point
-
| numbers, this truncates towards zero.
(此處有省略)。
help 函數其實就是查看對象的幫助文檔,類似於把幫助文檔放到 linux 命令的 less 中的效果,按下 q 退出。
上面的例子,顯示了 int 對象的幫助文檔,int 是內置類型,代碼在編譯 Python 的時候已經 編譯過了,沒有.py 的源代碼。
那么我們來看看,help 到底有啥用呢,讓 Python 來告訴你。
>>> help(help)
Help on _Helper in module _sitebuiltins object:class _Helper(builtins.object)
-
| Define the builtin 'help'. |
-
| This is a wrapper around pydoc.help that provides a helpful message
-
| when 'help' is typed at the Python interactive prompt.
|
-
| Calling help() at the Python prompt starts an interactive help session.
-
| Calling help(thing) prints help for the python object 'thing'.
還可以不加參數額。試試吧
>>> help()
Welcome to Python 3.5's help utility!If this is your first time using Python, you should definitely check out the tutorial on the Internet at http://docs.python.org/3.5/tutorial/.
Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and return to the interpreter, just type "quit".
To get a list of available modules, keywords, symbols, or topics, type
"modules", "keywords", "symbols", or "topics". Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam". 輸入上面標紅的關鍵字試試。。
modules:顯示模塊
keywords:顯示關鍵字
symbols:顯示操作符
topics:顯示常見主題
進去試試吧。。。。
那么問題來了,我們怎么知道 Python 的世界中還有哪些元素等待着我們去探索呢?我們怎 么找到這些元素呢?答案就是 Python 自帶說明的第二個函數:dir。
dir
告訴我這個函數有啥用呢?先用上面的知識 help 來會會這個 dir。 >>> help(dir)
Help on built-in function dir in module builtins:
dir(...)
dir([object]) -> list of strings
If called without an argument, return the names in the current scope.
Else, return an alphabetized list of names comprising (some of) the attributes of the given object, and of attributes reachable from it.
If the object supplies a method named __dir__, it will be used; otherwise
the default dir() logic is used and returns:
for a module object: the module's attributes.
for a class object: its attributes, and recursively the attributes
of its bases.
for any other object: its attributes, its class's attributes, and
recursively the attributes of its class's base classes.
簡單的講,dir 就是把這個對象有的屬性(非模塊對象也包括類屬性,父類屬性等)都
列出來放到一個 list 中,不知道啥是 list,那就先復習下上面的知識。若對象有__dir__方法, 就調用該方法,否則就用默認的方法。就拿上面的 help 實驗一把:
>>> dir(help)
['__call__', '__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__']
可以看到 help 這個函數有這些屬性。
這樣知道的還是不夠多啊,只有 help 和 dir 函數。別急,dir 不接參數試試。 >>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__'] 這個__builtins__不是內置的意思嗎?看看他有什么貨。
>>> dir(__builtins__)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__', '_format', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'xrange', 'zip']
一下子出來這么多,小心臟激動了吧。找找 help,dir 是不是都在里面,那其他別的是 不是也是 Python 提供給我們的呢,試試才知道。
>>> abs
<built-in function abs>
是吧,內置函數。老師,這么多怎么學啊?前面的知識剛學完就忘了啊。help,help, help 重要的事情說三遍。
好了這么多函數慢慢學吧,學到這個幾個函數的時候是否有點小激動呢?callable, hasattr,getattr,setattr,delattr,type,isinstance,issubclass。
callable
首先看看這個 callable 是不是講的就是我們常說的調用,help 一下。 Help on built-in function callable in module builtins:
callable(obj, /)
Return whether the object is callable (i.e., some kind of function).
Note that classes are callable, as are instances of classes with a
__call__() method. 講的很詳細,字面意思也能明白,返回對象能不能調用,能調用就返回 True,不能就返
回 False。 >>> def f():
... pass
...
>>> callable(f)
True
在試試匿名函數。
>>> callable(lambda x:x)
True
幫助文檔說了類可調用,類的實例若有__call__屬性也能調用。 那么怎么知道對象有沒有__call__屬性呢?下面就是另一個內置函數,hasattr。
hasattr
繼續套路,先 help 一下。 >>> help(hasattr)
Help on built-in function hasattr in module builtins:
hasattr(obj, name, /)
Return whether the object has an attribute with the given name.
This is done by calling getattr(obj, name) and catching AttributeError.
hasattr(obj,name)返回 obj 對象是否有 name 屬性,那么上面的 callable==lambda x:hasattr(x,’__call__’)?????這個內部實現在源碼,我也沒看。
上面的幫助文檔說他是通過調用 getattr 來實現的,那 getattr 是個什么鬼? getattr
套路啊,記得。
>>> help(getattr)
Help on built-in function getattr in module builtins:
getattr(...)
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
文檔看出 getattr(object,name[,default])就是獲取 object 對象的 name 屬性,若 name 不
存在,若定義了 default 參數返回 default,否則拋出異常。 那么這樣對嗎?????
def hasattr(obj, name):
try:
getattr(obj,name)
except AttributeError: return False
return True
setattr,delattr 現在我們學會了判斷屬性是否存在,獲取屬性,那我們怎么設置屬性,刪除屬性呢?之
前 dir(‘__builtins__’)返回的列表中找找,setattr,delattr 一看就是這兩個,長的太像了。具體
用法,help 吧,不講了。。 type
現在知道對象的屬性怎么操作了,然后是不是就想知道這個對象到底是個什么玩意啊, 那么 type 就出場了。
>>> help(type)
Help on class type in module builtins:
class type(object)
-
| type(object_or_name, bases, dict)
-
| type(object) -> the object's type
-
| type(name, bases, dict) -> a new type |
-
| Methods defined here: |
-
| __call__(self, /, *args, **kwargs)
-
| Call self as a function. |
(此處有省略。。)
顯示一個對象的類型,還可以創建一個類型。
type 只提供一個參數,返回對象的類型,提供三個參數返回一個新類型。>>> type('123')
<class 'str'>
>>> type(123)
<class 'int'>
>>> a=type('mylist',(list,),{‘n’:1}) #第一個參數為類型名,第二個參數為類型的父類,用 tuple, 可以有多個,第三個參數為默認類屬性組成的字典。>>> a
<class '__main__.mylist'>
>>> type(a)
<class 'type'>
>>> a.n
1
>>> dir(a)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'n', 'pop', 'remove', 'reverse', 'sort']是不是有 list 的所有屬性和 n 屬性?type 還有一些屬性很有意思,比如 __subclasses__,__bases__留給大家研究。
isinstance
那么上面生成的 a 和 type 是個什么關系呢?以及,之前的學的 int,list 這些和 type 是什 么關系呢,答案是他們都是 type 的實例。怎么證明?答案在內置函數中找。isinstance
help 步驟略。自行 help。。
isinstance(obj, class_or_tuple)就是判斷對象 obj 是否為 class_or_tuple 的實例或者其中一 個類的實例。
>>> isinstance(a,type) True
>>> isinstance(int,type) True
issubclass
剩下一個 issubclass,用法自行 help。。。。
之前討論的 bool 和 int 的關系,就可以用這個函數解釋。
>>> issubclass(bool,int) True
bool 是 int 的子類。
類中的常見自省屬性 既然說到類,那我們就看看常見的類中到底是怎么做自帶說明的。
>>> class A:
... def __init__(self,data):
...
...
>>> dir(A)
['__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__']
看到熟悉了的吧__delattr__,__getattribute__,__setattr__,和之前學的是不是很像?再來看 看第一個屬性__class__
>>> A.__class__
<class 'type'>
原來 A 是 type 的實例,還不相信,再復習下。 >>> isinstance(A,type)
True
然后可以看到__dict__是不是很熟悉,試試 >>> A.__dict__
mappingproxy({'__module__': '__main__', '__init__': <function A.__init__ at 0x007CAC90>, '__doc__': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>})
原來是類的基本屬性,dict 為啥不是字典呢?別急用實例試試。 >>> A(123).__dict__
{'data': 123}
既然是類,那么能不能知道有哪些基類子類之類的,當然可以。試過了 A 的所有屬性還 沒有看到額~怎么辦?那有可能 dir 出問題了,沒有顯示全額~那就再底層點,用 object.__dir__ >>> object.__dir__(A)
['__abstractmethods__', '__setattr__', 'mro', '__eq__', '__doc__', '__str__', '__subclasshook__', '__le__', '__prepare__', '__subclasses__', '__dict__', '__gt__', '__qualname__',
self.data=data
'__text_signature__', '__repr__', '__dir__', '__init__', '__dictoffset__', '__instancecheck__', '__ge__', '__base__', '__sizeof__', '__module__', '__basicsize__', '__itemsize__', '__call__', '__new__', '__mro__', '__hash__', '__reduce_ex__', '__getattribute__', '__class__', '__bases__', '__subclasscheck__', '__delattr__', '__lt__', '__reduce__', '__format__', '__weakrefoffset__', '__flags__', '__ne__', '__name__']
試試里面的屬性吧~
>>> A.__name__ #類的本名 'A'
>>> A.__subclasses__()
[]
>>> A.__base__
<class 'object'>
>>> A.__module__
'__main__'
>>> A.__bases__
(<class 'object'>,)
#類的子類 #類的基類 #類所在的模塊 #類的基類集
之前用到了實例,看看實例中還有些啥玩意。
>>> A(123).__module__ '__main__'
>>> A(123).__class__ <class '__main__.A'> >>> A
<class '__main__.A'>
>>> A(123).__class__ is A True
>>> A.__doc__
#實例的類所在的模塊 #實例的類
#實例的類的幫助文檔 拿到實例就知道他是什么類的實例,不信試試
>>> r = range(10) >>> r.__class__ <class 'range'>
函數中的自省屬性
類玩完了,(其實沒有玩完,很多可以挖掘的),是不是躍躍欲試的玩下函數?馬上就來。 >>> def func(a,b):
... c=a+b
-
... print(c)
-
... return c+1 ...
>>> dir(func)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']之前說過函數之所以會叫調用是因為有__call__屬性,這里可以看到,再試試其他屬性。
>>> func.__class__ <class 'function'>
函數是 function 類的實例。
>>> func.__closure__ #閉包,這個留給老司機 >>> func.__code__ #code 對象
<code object func at 0x007B4250, file "<stdin>", line 1>
>>> func.__doc__ >>> func.__name__ 'func'
>>> f = func
>>> f.__name__ 'func'
#函數的幫助文檔 #函數的本名
函數的主要內容在 code 對象,
>>> dir(func.__code__)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_kwonlyargcount', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
看看里面都有些啥。
>>> func.__code__.co_consts (None, 1)
>>> func.__code__.co_argcount 2
>>> func.__code__.co_nlocals
3
>>> func.__code__.co_filename '<stdin>'
>>> func.__code__.co_names ('print',)
>>> func.__code__.co_name 'func'
>>> func.__code__.co_varnames ('a', 'b', 'c')
>>> func.__code__.co_stacksize 2
>>> func.__code__.co_stacksize 2
還有其他屬性,自行探索。。。
inspect
#函數用到的常量 #函數的參數個數
#函數局部變量的個數 #函數所在文件的文件名
#函數用到的函數名 #函數本名
#函數中變量名 #函數中棧大小
#編譯之后的字節碼
有了這么多讓 Python 做自我說明的方法,還不滿足?Good boy!再來重頭戲,inspect 模塊。
help> inspect
Help on module inspect:
NAME
inspect - Get useful information from live Python objects.
DESCRIPTION
This module encapsulates the interface provided by the internal special attributes (co_*, im_*, tb_*, etc.) in a friendlier fashion.
It also provides some help for examining source code and class layout.
Here are some of the useful functions provided by this module:
ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(), isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(), isroutine() - check object types
getmembers() - get members of an object that satisfy a given condition
getfile(), getsourcefile(), getsource() - find an object's source code getdoc(), getcomments() - get documentation on an object getmodule() - determine the module that an object came from getclasstree() - arrange classes so as to represent their hierarchy
getargspec(), getargvalues(), getcallargs() - get info about function arguments getfullargspec() - same, with support for Python 3 features
formatargspec(), formatargvalues() - format an argument spec getouterframes(), getinnerframes() - get info about frames
currentframe() - get the current stack frame
stack(), trace() - get info about frames on the stack or in a traceback
signature() - get a Signature object for the callable
上面的介紹都夠詳細了,我就只舉兩個例子。
>>> import threading
>>> import inspect
>>> inspect.getsourcefile(threading)
'/usr/lib/python3.5/threading.py'
>>> inspect.getsource(threading)
'"""Thread module emulating a subset of Java\'s threading model."""\n\nimport sys as _sys\nimport _thread\n\nfrom time import monotonic as _time\nfrom traceback import format_exc as _format_exc\nfrom _weakrefset import WeakSet\nfrom itertools import islice as _islice, count as _count\ntry:\n
(此處有省略......)
對函數也可以,但是要記住,這兩個方法對內置的對象是行不通的,因為之前說過內置 對象,是在編譯 Python 的時候寫入的沒有 py 的代碼。怎么判斷是不是內置對象?又沒有好 好看前面的文檔啊..............................inspect.isbuiltin()或者 obj.__name__ in dir(‘__builtins__’)
dis 還感覺不夠么,那只能發絕招了~~~~~~~dis 模塊
>>> >>> 1
>>> ... ... ... >>>
2
3
import dis dis.dis('a=1')
def f(a):
for i in range(a):
print(i) dis.dis(f)
>>
>> >>
0 SETUP_LOOP
3 LOAD_GLOBAL
6 LOAD_FAST
9 CALL_FUNCTION
12 GET_ITER 13 FOR_ITER 16 STORE_FAST
19 LOAD_GLOBAL 22 LOAD_FAST
25 CALL_FUNCTION 28 POP_TOP
29 JUMP_ABSOLUTE 32 POP_BLOCK
33 LOAD_CONST
36 RETURN_VALUE
0 LOAD_CONST
3 STORE_NAME
6 LOAD_CONST
9 RETURN_VALUE
0 (1) 0 (a)
1 (None)
30 (to 33) 0 (range)
0 (a)
1 (1 positional, 0 keyword pair)
16 (to 32) 1 (i)
1 (print) 1 (i)
1 (1 positional, 0 keyword pair) 13
0 (None)
有沒有熟悉匯編的童鞋,講解下啥意思。貌似不用熟悉匯編英文好就可以了。這個 函數展現了函數代碼或者函數對象編譯之后變成字節碼之后的執行過程。是不是越來越 接近底層了?
總結
講了這么多,講下這個 Python 的自帶說明的名字叫自省。(反射是 java 的說法,我 們叫自省)
那么自省是什么?總結下
自省簡單的說,就是用 python 的代碼自己告訴這個對象是什么,有什么,以及祖 宗是什么,子孫是什么....
好了總結下 python 提供的自省機制:help,dir 。沒了么?是的沒了其他的可以用 這兩個找到,但是每次用的時候再去找嗎?當然不是,所以多用多積累,多記憶吧。謝 謝大家。