print 底層 和 input 底層如何實現的?

print()

先提前說下 print() 用 sys.stdout.write() 實現後面解釋…

描述

print() 方法用於打印輸出,最常見的一個函數。

在 Python3.3 版增加了 flush 關鍵字參數。

print 在 Python3.x 是一個函數,但在 Python2.x 版本不是一個函數,只是一個關鍵字。

語法

以下是 print() 方法的語法:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
參數

objects -- 複數,表示可以一次輸出多個對象。輸出多個對象時,需要用 , 分隔。
sep -- 用來間隔多個對象,默認值是一個空格。
end -- 用來設定以什麼結尾。默認值是換行符 \n,我們可以換成其他字符串。
file -- 要寫入的文件對象。
flush -- 輸出是否被緩存通常決定於 file,但如果 flush 關鍵字參數爲 True,流會被強制刷新。

返回值

無。

接下來,我們來看他的底層 是怎麼寫的。

def print(self, *args, sep=' ', end='\n', file=None): # known special case of print
    """
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.
    """
    pass

我們可以看到這句話:Prints the values to a stream, or to sys.stdout by default.

  • 譯:將值打印到流或sys中。stdout默認情況下

我們再來看 sys 中的 stdout 的底層

stdout = None # (!) forward: __stdout__, real value is "<_io.TextIOWrapper name='<stdout>' mode='w' encoding='cp1252'>"

我們可以看到 mode 代表的是 寫 ‘w’,也就是 write

接着我們再看 sys.stdont都可以接受什麼參數?

print(dir(sys.stdout))

hello['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 'readable', 'readline', 'readlines', 'reconfigure', 'seek', 'seekable', 'tell', 'truncate', 'writable', 
'write' # look here
, 'write_through', 'writelines']

我們看到了 有 write方法。

  • 測試:

    import sys
     
    print('hello')
    sys.stdout.write('hello')
    print('new')
     	 
    # 結果:
    # hello
    # hellonew
    

此時 可以看到,sys.stdout.write 同樣的將數據 打印出來了。

所以 print() 用 sys.stdout.write() 實現

但還是可以看到兩者還是有不同的。

  • sys.stdout.write()結尾沒有換行,而print()是自動換行的。另外,write()只接收字符串格式的參數。

  • print()能接收多個參數輸出,write()只能接收一個參數。

還記得剛纔 print底層的這句話嘛: end: string appended after the last value, default a newline.

  • 譯:結束:最後一個值後面的字符串,默認是一個換行符。

既然都說到這裏了,大家肯定會問 剛纔的 flash參數是什麼鬼?

  • flush – 輸出是否被緩存通常決定於 file,但如果 flush 關鍵字參數爲 True,流會被強制刷新。

使用 flush 參數生成一個 Loading 的效果:

import time

print("---RUNOOB EXAMPLE : Loading 效果---")

print("Loading",end = "")
for i in range(20):
    print(".",end = '',flush = True)
    time.sleep(0.5)

效果圖:
在這裏插入圖片描述



input()

先說下 Python3中的input() 用 sys.stdin.readline() 實現。接線來解釋

  • Python3.x 中 input() 函數接受一個標準輸入數據,返回爲 string 類型。

  • Python2.x 中 input() 相等於 eval(raw_input(prompt)) ,用來獲取控制檯的輸入。

raw_input() 將所有輸入作爲字符串看待,返回字符串類型。而 input() 在對待純數字輸入時具有自己的特性,它返回所輸入的數字的類型( int, float )。

注意:input()raw_input() 這兩個函數均能接收 字符串 ,
但 raw_input() 直接讀取控制檯的輸入(任何類型的輸入它都可以接收)。
而對於 input() ,它希望能夠讀取一個合法的 python 表達式,
即你輸入字符串的時候必須使用引號將它括起來,否則它會引發一個 SyntaxError 。

除非對 input() 有特別需要,否則一般情況下我們都是推薦使用 raw_input() 來與用戶交互。

注意:python3 裏 input() 默認接收到的是 str 類型。

函數語法

input([prompt])

參數說明:

prompt: 提示信息

我們看一下 input()底層的書寫:

def input(*args, **kwargs): # real signature unknown
    """
    Read a string from standard input.  The trailing newline is stripped.
    
    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.
    
    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.
    """
    pass

大家看註釋中的這一句 On *nix systems, readline is used if available.

  • 譯:在 * nix system上 ,如果可用 則使用readline。

\*nix 就是unix 操作系統和 linux操作系統。就是說只要你的操作系統是Unix或者linux,無論哪個開發商或者版本,就是屬於*nix。
這種命名方式主要是用於軟件兼容性說明或者網絡建站上傳服務器文件時需要確認的信息。

所以 input 是 sys.readline()實現的?
no no no...

大家都知道 readline()是讀一行,可是 讀誰呢?

大家 在電腦中輸入的東西 都是要通過鍵盤來輸入的吧,所以
此時會有一個監聽 鍵盤 輸入的函數(方法)stdin

stdin是標準輸入,一般指鍵盤輸入到緩衝區裏的東西。

# sys 支持的所有方法
print(dir(sys))

['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_enablelegacywindowsfsencoding', '_framework', '_getframe', '_git', '_home', '_xoptions', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dllhandle', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth', 'get_coroutine_wrapper', 'getallocatedblocks', 'getcheckinterval', 'getdefaultencoding', 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettrace', 'getwindowsversion', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'is_finalizing', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'set_coroutine_wrapper', 'setcheckinterval', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 
'stderr', 'stdin', # look here
'stdout', 'thread_info', 'version', 'version_info', 'warnoptions', 'winver']
sys.stdin 底層源碼:

stdin = None # (!) real value is "<_io.TextIOWrapper name=3 mode='r' encoding='cp1252'>"

大家看到了 mode 類型是 讀了吧 ‘r’,看下 sys.stdin 所支持的方法

print(dir(sys.sdtin))

['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', '_finalizing', 'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 
'read', 'readable', 'readline', 'readlines', # 我們在這裏
'reconfigure', 'seek', 'seekable', 'tell', 'truncate', 'writable', 'write', 'write_through', 'writelines']

Python3中的 input() 用 sys.stdin.readline() 實現。

import sys
 
a = sys.stdin.readline()
print(a, len(a))
 
b = input()
print(b, len(b))
 
 
# 結果:
# hello
# hello
#  6
# hello
# hello 5
  • readline()會把結尾的換行符也算進去。

  • readline()可以給定整型參數,表示獲取從當前位置開始的幾位內容。當給定值小於0時,一直獲取這一行結束。

import sys
 
a = sys.stdin.readline(3)
print(a, len(a))
 
# 結果:
# hello
# hel 3

readline()如果給定了整型參數結果又沒有把這一行讀完,那下一次readline()會從上一次結束的地方繼續讀,和讀文件是一樣的。

import sys
 
a = sys.stdin.readline(3)
print(a, len(a))
 
b = sys.stdin.readline(3)
print(b, len(b))
 
# 結果
# abcde
# abc 3
# de
#  3

input()可以接收字符串參數作爲輸入提示,readline()沒有這個功能。

參考原址:https://blog.csdn.net/lnotime/article/details/81385646
參考原址 菜鳥教程:https://www.runoob.com/python/python-func-input.html



真的希望 CSDN 能夠推出 代碼縮放的功能,這些 底層源碼 展示太佔用屏幕空間了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章