假使從『裝置的程式介面』 API 來觀察『裝置』是什麼?『裝置』不過就是透過那個『 API 規範』存取的 □□○○!這可引發了一個『大哉問』?如果說某種『物理裝置』事實上沒有連上系統,但是它的『API 介面』卻『存在』且能『運作』,那麼我們『能不能』知道那個『裝置』實際上不存在的呢??這個問題其實比表面深沈 的多,一直延伸到『知識論』的哲學爭議之上。比方說,什麼是『蘋果樹 』?如何判定『某個水果』是『蘋果』?最終總容易落入用『外在屬性』來作『歸類』的事實裡。更不要講過去的『接枝』到現今的『基改』,所作的『跨界』之事!也許當『界線』越來越模糊,『什麼是什麼』的問題終將越來越不清楚的耶!!
這『何謂鴨子』之事也發生在『物件導向』的語言中。維基百科的『鴨子型別』講︰
當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。
In computer programming with object-oriented programming languages, duck typing is a layer of programming language and design rules on top of typing. Typing is concerned with assigning a type to any object. Duck typing is concerned with establishing the suitability of an object for some purpose. With normal typing, suitability is assumed to be determined by an object’s type only. In duck typing, an object’s suitability is determined by the presence of certain methods and properties (with appropriate meaning), rather than the actual type of the object.
The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows:
When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.[1]
In duck typing, a programmer is only concerned with ensuring that objects behave as demanded of them in a given context, rather than ensuring that they are of a specific type. For example, in a non-duck-typed language, one would create a function that requires that the object passed into it be of type Duck, in order to ensure that that function can then use the object’s walk and quack methods. In a duck-typed language, the function would take an object of any type and simply call its walk and quack methods, producing a run-time error if they are not defined. Instead of specifying types formally, duck typing practices rely on documentation, clear code, and testing to ensure correct use.
───
Criticism
One issue with duck typing is that it forces programmers to have a much wider understanding of the code they are working with at any given time. For instance, in Python, one could easily create a class called Wine, which expects a class implementing the “press” attribute as an ingredient. However, a class called Trousers might also implement the press() method. With duck typing, in order to prevent strange, hard-to-detect errors, the developer needs to be aware of each potential use of the method “press”, even when it’s conceptually unrelated to what they are working on. By way of contrast, in a strongly and statically typed language that uses type hierarchies and parameter type checking, it’s much harder to supply an unexpected object type to a class. For example, in a language like Java, the ambiguity in the above reuse of the method name press() would not be a problem unless one of the two classes was deliberately defined as a child of the other.
Proponents of duck typing, such as Guido van Rossum, argue that the issue is handled by testing, and the necessary knowledge of the codebase required to maintain it.[4][5]
Criticisms around duck typing tend to be special cases of broader points of contention regarding dynamically typed versus statically typed programming language semantics.
所以,什麼是『電腦滑鼠』的呢?若是以『核心輸入子系統』以及『python-evdev 程式庫』的觀點而言,就是能『產生』某些『事件型別』的東東罷了!
【滑鼠參考說明】
pi@raspberrypi ~ python3
Python 3.2.3 (default, Mar 1 2013, 11:53:50)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from evdev import InputDevice, list_devices, categorize, ecodes
>>> 鍵盤 = InputDevice('/dev/input/event0')
>>> 鍵盤.capabilities(verbose=True)
{('EV_LED', 17): [('LED_NUML', 0), ('LED_CAPSL', 1), ('LED_SCROLLL', 2), ('LED_COMPOSE', 3), ('LED_KANA', 4)], ('EV_MSC', 4): [('MSC_SCAN', 4)], ('EV_KEY', 1): [('KEY_ESC', 1), ('KEY_1', 2), ('KEY_2', 3), ('KEY_3', 4), ('KEY_4', 5), ('KEY_5', 6), ('KEY_6', 7), ('KEY_7', 8), ('KEY_8', 9), ('KEY_9', 10), ('KEY_0', 11), ('KEY_MINUS', 12), ('KEY_EQUAL', 13), ('KEY_BACKSPACE', 14), ('KEY_TAB', 15), ('KEY_Q', 16), ('KEY_W', 17), ('KEY_E', 18), ('KEY_R', 19), ('KEY_T', 20), ('KEY_Y', 21), ('KEY_U', 22), ('KEY_I', 23), ('KEY_O', 24), ('KEY_P', 25), ('KEY_LEFTBRACE', 26), ('KEY_RIGHTBRACE', 27), ('KEY_ENTER', 28), ('KEY_LEFTCTRL', 29), ('KEY_A', 30), ('KEY_S', 31), ('KEY_D', 32), ('KEY_F', 33), ('KEY_G', 34), ('KEY_H', 35), ('KEY_J', 36), ('KEY_K', 37), ('KEY_L', 38), ('KEY_SEMICOLON', 39), ('KEY_APOSTROPHE', 40), ('KEY_GRAVE', 41), ('KEY_LEFTSHIFT', 42), ('KEY_BACKSLASH', 43), ('KEY_Z', 44), ('KEY_X', 45), ('KEY_C', 46), ('KEY_V', 47), ('KEY_B', 48), ('KEY_N', 49), ('KEY_M', 50), ('KEY_COMMA', 51), ('KEY_DOT', 52), ('KEY_SLASH', 53), ('KEY_RIGHTSHIFT', 54), ('KEY_KPASTERISK', 55), ('KEY_LEFTALT', 56), ('KEY_SPACE', 57), ('KEY_CAPSLOCK', 58), ('KEY_F1', 59), ('KEY_F2', 60), ('KEY_F3', 61), ('KEY_F4', 62), ('KEY_F5', 63), ('KEY_F6', 64), ('KEY_F7', 65), ('KEY_F8', 66), ('KEY_F9', 67), ('KEY_F10', 68), ('KEY_NUMLOCK', 69), ('KEY_SCROLLLOCK', 70), ('KEY_KP7', 71), ('KEY_KP8', 72), ('KEY_KP9', 73), ('KEY_KPMINUS', 74), ('KEY_KP4', 75), ('KEY_KP5', 76), ('KEY_KP6', 77), ('KEY_KPPLUS', 78), ('KEY_KP1', 79), ('KEY_KP2', 80), ('KEY_KP3', 81), ('KEY_KP0', 82), ('KEY_KPDOT', 83), ('KEY_ZENKAKUHANKAKU', 85), ('KEY_102ND', 86), ('KEY_F11', 87), ('KEY_F12', 88), ('KEY_RO', 89), ('KEY_KATAKANA', 90), ('KEY_HIRAGANA', 91), ('KEY_HENKAN', 92), ('KEY_KATAKANAHIRAGANA', 93), ('KEY_MUHENKAN', 94), ('KEY_KPJPCOMMA', 95), ('KEY_KPENTER', 96), ('KEY_RIGHTCTRL', 97), ('KEY_KPSLASH', 98), ('KEY_SYSRQ', 99), ('KEY_RIGHTALT', 100), ('KEY_HOME', 102), ('KEY_UP', 103), ('KEY_PAGEUP', 104), ('KEY_LEFT', 105), ('KEY_RIGHT', 106), ('KEY_END', 107), ('KEY_DOWN', 108), ('KEY_PAGEDOWN', 109), ('KEY_INSERT', 110), ('KEY_DELETE', 111), (['KEY_MIN_INTERESTING', 'KEY_MUTE'], 113), ('KEY_VOLUMEDOWN', 114), ('KEY_VOLUMEUP', 115), ('KEY_POWER', 116), ('KEY_KPEQUAL', 117), ('KEY_PAUSE', 119), ('KEY_KPCOMMA', 121), (['KEY_HANGEUL', 'KEY_HANGUEL'], 122), ('KEY_HANJA', 123), ('KEY_YEN', 124), ('KEY_LEFTMETA', 125), ('KEY_RIGHTMETA', 126), ('KEY_COMPOSE', 127), ('KEY_STOP', 128), ('KEY_AGAIN', 129), ('KEY_PROPS', 130), ('KEY_UNDO', 131), ('KEY_FRONT', 132), ('KEY_COPY', 133), ('KEY_OPEN', 134), ('KEY_PASTE', 135), ('KEY_FIND', 136), ('KEY_CUT', 137), ('KEY_HELP', 138), ('KEY_F13', 183), ('KEY_F14', 184), ('KEY_F15', 185), ('KEY_F16', 186), ('KEY_F17', 187), ('KEY_F18', 188), ('KEY_F19', 189), ('KEY_F20', 190), ('KEY_F21', 191), ('KEY_F22', 192), ('KEY_F23', 193), ('KEY_F24', 194), ('KEY_UNKNOWN', 240)], ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('?', 4), ('?', 17), ('?', 20)]}
>>> 鍵盤.capabilities()
{0: [0, 1, 4, 17, 20], 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 119, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 240], 4: [4], 17: [0, 1, 2, 3, 4]}
>>> 鍵盤.leds(verbose=True)
[]
>>> for 事件 in 鍵盤.read_loop():
... if 事件.type == ecodes.EV_KEY:
... print(categorize(事件))
... print(事件)
...
key event at 1439784566.338788, 20 (KEY_T), down
event at 1439784566.338788, code 20, type 01, val 01
key event at 1439784566.418811, 20 (KEY_T), up
event at 1439784566.418811, code 20, type 01, val 00
key event at 1439784568.283038, 18 (KEY_E), down
event at 1439784568.283038, code 18, type 01, val 01
key event at 1439784568.387043, 18 (KEY_E), up
event at 1439784568.387043, code 18, type 01, val 00
key event at 1439784569.291174, 31 (KEY_S), down
event at 1439784569.291174, code 31, type 01, val 01
key event at 1439784569.395174, 31 (KEY_S), up
event at 1439784569.395174, code 31, type 01, val 00
key event at 1439784569.659215, 20 (KEY_T), down
event at 1439784569.659215, code 20, type 01, val 01
key event at 1439784569.763225, 20 (KEY_T), up
event at 1439784569.763225, code 20, type 01, val 00
key event at 1439784575.187941, 58 (KEY_CAPSLOCK), down
event at 1439784575.187941, code 58, type 01, val 01
key event at 1439784575.291938, 58 (KEY_CAPSLOCK), up
event at 1439784575.291938, code 58, type 01, val 00
key event at 1439784582.908932, 58 (KEY_CAPSLOCK), down
event at 1439784582.908932, code 58, type 01, val 01
key event at 1439784583.044951, 58 (KEY_CAPSLOCK), up
event at 1439784583.044951, code 58, type 01, val 00
key event at 1439784585.613291, 69 (KEY_NUMLOCK), down
event at 1439784585.613291, code 69, type 01, val 01
key event at 1439784585.709302, 69 (KEY_NUMLOCK), up
event at 1439784585.709302, code 69, type 01, val 00
key event at 1439784588.661688, 69 (KEY_NUMLOCK), down
event at 1439784588.661688, code 69, type 01, val 01
key event at 1439784588.765693, 69 (KEY_NUMLOCK), up
event at 1439784588.765693, code 69, type 01, val 00
^CTraceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.2/dist-packages/evdev/device.py", line 280, in read_loop
r, w, x = select([self.fd], [], [])
KeyboardInterrupt
>>>