我最近在和一些人谈论我正在编写的程序时听到了“hook”这个词。我不确定这个术语到底意味着什么,尽管我从对话中推断钩子是一种函数类型。我寻找一个定义,但无法找到一个好的答案。有没有人能告诉我这个术语的一般含义,或者举个小例子来说明这个定义?


当前回答

在Drupal内容管理系统中,“hook”有一个相对特定的含义。当内部事件发生时(例如内容创建或用户登录),模块可以通过实现一个特殊的“钩子”函数来响应该事件。这是通过命名约定完成的——例如,用户登录事件的[your-plugin-name]_user_login()。

由于这种惯例,底层事件被称为“钩子”,并在Drupal的API文档中以“hook_user_login”和“hook_user_authenticate()”这样的名称出现。

其他回答

当遇到某些条件时,可以执行钩子。例如,一些变量发生了变化,或者调用了一些动作,或者发生了一些事件。hook可以进入过程并更改内容或对更改作出反应。

钩子是软件为用户提供的功能,在特定情况下调用他们自己的代码。该代码可以增加或替换当前代码。

在电脑真正属于个人的时代,病毒还不那么流行(我说的是80年代),它就像打补丁操作系统软件本身来调用你的代码一样简单。我记得我在Apple II上写了一个Applesoft BASIC语言的扩展,它在任何一行被处理之前,通过向我的代码注入一个调用,简单地将我的代码连接到BASIC解释器中。

一些计算机预先设计了钩子,苹果II上的I/O流就是一个例子。它使用这样一个钩子注入整个磁盘子系统(Apple II rom最初是在盒式磁带是个人电脑主要存储介质的年代制造的)。你通过打印ASCII码4 (CTRL-D)来控制磁盘,后面跟着你想要执行的命令,然后是一个CR,它被磁盘子系统拦截,它已经将自己连接到苹果ROM打印例程中。

例如,这几行:

PRINT CHR(4);"CATALOG"
PRINT CHR(4);"IN#6"

会列出磁盘内容,然后重新初始化计算机。这样就可以通过设置第一行来保护你的BASIC程序:

123 REM XIN#6

然后使用POKE在X所在的位置插入CTRL-D字符。然后,任何试图列出源代码的人都会通过磁盘子系统检测到的输出例程发送重新初始化序列。

这通常是我们为了得到我们想要的行为而不得不采取的手段。

现在,由于操作系统更加安全,它为钩子本身提供了便利,因为您不再需要“在运行中”或在磁盘上修改操作系统。

它们已经存在很长时间了。大型机有这些功能(称为出口),甚至现在还有大量的大型机软件使用这些功能。例如,z/OS附带的免费源代码控制系统(称为SCLM)允许您通过在出口中放置自己的代码来完全替换安全子系统。

通常挂钩指的是Win32消息挂钩或Linux/OSX的等等物,但更一般的挂钩只是通知另一个对象/窗口/程序等,当指定的操作发生时,你想被通知。例如:让系统上的所有窗口在即将关闭时通知您。

作为一般规则,钩子有点危险,因为在不了解它如何影响系统的情况下这样做可能会导致不稳定或至少是意想不到的行为。在某些情况下,它也非常有用。例如:FRAPS使用它来确定应该在哪个窗口显示FPS计数器。

编程中的钩子是一种技术,它使用所谓的钩子来创建一个过程链作为事件处理程序。

答案很多,但没有例子,所以添加一个虚拟的:下面的complated_func提供了两个钩子来修改它的行为

from typing import List, Callable


def complicated_func(
    lst: List[int], hook_modify_element: Callable[[int], int], hook_if_negative=None
) -> int:
    res = sum(hook_modify_element(x) for x in lst)
    if res < 0 and hook_if_negative is not None:
        print("Returning negative hook")
        return hook_if_negative
    return res


def my_hook_func(x: int) -> int:
    return x * 2


if __name__ == "__main__":
    res = complicated_func(
        lst=[1, 2, -10, 4],
        hook_modify_element=my_hook_func,
        hook_if_negative=0,
    )
    print(res)