- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
例如,在 jQuery 中,您可以这样做
$(input).on("change", callback);
有没有办法在 Python 中使用列表来执行类似的操作?像这样的东西(伪代码):
from watch import Watchman
enemies = ["Moloch", "Twilight Lady", "Big Figure", "Captain Carnage", "Nixon"]
owl = Watchman()
def enemies_changed(old, new):
print(f"Enemies was {old}, now are {new}")
owl.watch(enemies, enemies_changed)
enemies.append("Alien")
# Enemies was ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon'], now are ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Alien']
最佳答案
您可以使用生成器和子类化 list
来实现此目的。您必须重写您想要观看的每个方法。这是一个简单的例子。
def watcher(name=''):
while True:
x = yield
msg = f'{name} was {x}'
y = yield
if y is not None:
msg += f', now is {y}'
print(msg)
class List(list):
def __init__(self, *args, gen=None, **kwargs):
self.__gen = gen
next(gen)
super().__init__(*args, **kwargs)
def __add__(self, other):
try:
self.__gen.send(self)
super().__add__(other)
self.__gen.send(self)
except:
next(self.__gen)
raise
def __setitem__(self, *args, **kwargs):
try:
self.__gen.send(self)
super().__setitem__(*args, **kwargs)
self.__gen.send(self)
except:
next(self.__gen)
raise
def append(self, value):
self.__gen.send(self)
super().append(value)
self.__gen.send(self)
示例:
owl = watcher('Enemies')
enemies = List(["Moloch", "Twilight Lady", "Big Figure", "Captain Carnage", "Nixon"], gen=owl)
enemies.append('Alien')
# prints:
Enemies was ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon'], now is ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Alien']
enemies[-1] = 'Aliens'
# prints:
Enemies was ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Alien'], now is ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Aliens']
list
这是一个对 list
内置类型进行猴子修补以添加包装方法的示例。在这种情况下,我们只是添加改变列表的方法的大写版本;即 .append
变为 .Append`。
猴子补丁代码来自https://gist.github.com/bricef/1b0389ee89bd5b55113c7f3f3d6394ae 。您只需将其复制到名为 patch.py
的文件中,然后使用 from patch import Monkey_patch_list
import ctypes
from types import MappingProxyType, MethodType
# figure out side of _Py_ssize_t
if hasattr(ctypes.pythonapi, 'Py_InitModule4_64'):
_Py_ssize_t = ctypes.c_int64
else:
_Py_ssize_t = ctypes.c_int
# regular python
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
# python with trace
if object.__basicsize__ != ctypes.sizeof(_PyObject):
class _PyObject(ctypes.Structure):
pass
_PyObject._fields_ = [
('_ob_next', ctypes.POINTER(_PyObject)),
('_ob_prev', ctypes.POINTER(_PyObject)),
('ob_refcnt', _Py_ssize_t),
('ob_type', ctypes.POINTER(_PyObject))
]
class _DictProxy(_PyObject):
_fields_ = [('dict', ctypes.POINTER(_PyObject))]
def reveal_dict(proxy):
if not isinstance(proxy, MappingProxyType):
raise TypeError('dictproxy expected')
dp = _DictProxy.from_address(id(proxy))
ns = {}
ctypes.pythonapi.PyDict_SetItem(ctypes.py_object(ns),
ctypes.py_object(None),
dp.dict)
return ns[None]
def get_class_dict(cls):
d = getattr(cls, '__dict__', None)
if d is None:
raise TypeError('given class does not have a dictionary')
if isinstance(d, MappingProxyType):
return reveal_dict(d)
return d
class Listener:
def __init__(self):
self._g = None
def __call__(self, x=None):
if x is None:
return self._g
self._g = x
def send(self, val):
if self._g:
self._g.send(val)
def monkey_patch_list(decorator, mutators=None):
if not mutators:
mutators = (
'append', 'clear', 'extend', 'insert', 'pop', 'remove',
'reverse', 'sort'
)
d_list = get_class_dict(list)
d_list['_listener'] = Listener()
for m in mutators:
d_list[m.capitalize()] = decorator(d_list.get(m))
现在我们基本上可以使用上面的内容,即定义一个装饰器,它包装列表方法并在突变之前和突变之后产生列表的 str
表示形式。然后,您可以传递任何接受两个参数和 name
关键字参数的函数来处理警报。
def before_after(clsm):
'''decorator for list class methods'''
def wrapper(self, *args, **kwargs):
self._listener.send(self)
out = clsm(self, *args, **kwargs)
self._listener.send(self)
return out
return wrapper
class Watchman:
def __init__(self):
self.guarding = []
def watch(self, lst, fn, name='list'):
self.guarding.append((lst, name))
w = self._watcher(fn, name)
lst._listener(w)
@staticmethod
def _watcher(fn, name):
def gen():
while True:
x = yield
x = str(x)
y = yield
y = str(y)
print(fn(x, y, name=name))
g = gen()
next(g)
return g
现在您可以通过标准列表构造函数修补和使用新方法。
def enemies_changed(old, new, name='list'):
print(f"{name} was {old}, now are {new}")
# update the list methods with the wrapper
monkey_patch_list(before_after)
enemies = ["Moloch", "Twilight Lady", "Big Figure", "Captain Carnage", "Nixon"]
owl = Watchman()
owl.watch(enemies, enemies_changed, 'Enemies')
enemies.Append('Alien')
# prints:
Enemies was ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon'],
now are ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Alien']
list
此方法与方法 1 类似,但您仍然可以照常使用 list
构造函数。我们基本上将用我们自己的子类版本覆盖内置的 list
类。这些方法具有相同的语法,我们只是添加一个监听器和接收器属性,我们还包装了变异方法,以便监听器接收它们并向接收器发送信号(设置完毕后)。
# save the built-in list
_list = list
class list(_list):
def __init__(self, *args, emit_change=False, **kwargs):
super().__init__(*args, **kwargs)
self._emit = emit_change
self._listener = self._make_gen() if emit_change else None
self._init_change_emitter()
self._receiver = None
@property
def emit_change(self):
return self._emit
@property
def emitter(self):
return self._emitter
def _make_gen(self):
def gen():
while True:
x = yield
x = str(x)
y = yield
y = str(y)
yield (x, y)
g = gen()
next(g)
return g
def _init_change_emitter(self):
def before_after(clsm):
def wrapper(*args, **kwargs):
if self._listener:
self._listener.send(self)
out = clsm(*args, **kwargs)
before, after = self._listener.send(self)
if self._receiver:
self._receiver.send((before, after))
else:
out = clsm(*args, **kwargs)
return out
return wrapper
mutators = (
'append', 'clear', 'extend', 'insert', 'pop', 'remove',
'reverse', 'sort'
)
for m_str in mutators:
m = self.__getattribute__(m_str)
self.__setattr__(m_str, before_after(m))
此时 list
的工作方式与以前一样。使用 list('abc')
返回输出 ['a', 'b', 'c']
,如您所料,list 也是如此('abc',emit_change=True)
。附加关键字参数允许 Hook 接收器,该接收器在列表突变时在列表片段之前和之后发送。
使用括号构造的列表需要通过 list
构造函数传递以打开监听/发射。
示例:
class Watchman:
def __init__(self):
self.guarding = []
def watch(self, lst, fn, name='list'):
if not lst._listener:
raise ValueError(
'Can only watch lists initialized with `emit_change=True`.'
)
r = self._make_receiver(fn, name)
lst._receiver = r
self.guarding.append((lst, name, r))
def _make_receiver(self, fn, name):
def receiver():
while True:
x, y = yield
print(fn(x, y, name=name))
r = receiver()
next(r)
return r
def enemies_changed(old, new, name):
return f"{name} was {old}\nNow is {new}"
enemies = ["Moloch", "Twilight Lady", "Big Figure", "Captain Carnage", "Nixon"]
enemies = list(enemies, emit_change=True)
owl = Watchman()
owl.watch(enemies, enemies_changed, 'Enemies')
enemies.append('Alien')
# prints:
Enemies was: ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon']
Now is: ['Moloch', 'Twilight Lady', 'Big Figure', 'Captain Carnage', 'Nixon', 'Alien']
希望其中之一能有所帮助!
关于python - 有没有办法将回调与列表的更改相关联?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60017068/
我正在研究 learnyounode 的 HTTP 客户端作业。 我想知道为什么控制台记录来自response.on(“end”,callback)的数据仅输出预期输出的最后一部分,而控制台记录来自r
我正在尝试创建一个对象列表(在我的示例中为 List),我在其中使用 json 将对象添加到此列表,但该列表仍为空。这是我的代码: public List readCardsFromJson() {
我有一个 JavaScript 函数“print_something”,它在大约 300 个 jsp 帮助页面中实现。我发现这个“print_something”函数必须被纠正。所以我正在寻找一个不更
有 2 个 HTML 下拉列表,一个用于 12 小时时间,一个用于每小时 5 分钟的时间间隔。 .. 1 .. 12 .. 0 .. 55 .. 一直在尝试使用 if/
我有一个 A 类,我打算在它与设备驱动程序交互时将其放入共享库中。 我有一个 B 类,将来可能是 C、D、E...,它将使用共享库中的 A 类。 我想要在类 A 中设置回调函数的功能,以便当特定事件发
我需要能够在处理完 Observable.next() 之后执行回调。 我有一个组件“A”,它有一个主题使用 Subject.next() 发送通知。我有一个组件“B”,它订阅了 Subject.as
我有一张在顶部和底部单元格下方带有阴影的表格(此处使用 Matt Gallagher 的解决方案:http://cocoawithlove.com/2009/08/adding-shadow-effe
有人可以向我解释一下为什么这段代码有效 renderSquare(i) { return ( this.handleClick(i)} /> ); } 但
我可以让两个不同的客户端监听相同的 WCF 回调并让它们都接收相同的数据而不必进行两次处理吗? 最佳答案 不是真的 - 至少不是直接的。你所描述的听起来很像发布/订阅模式。 WCF 服务基本上在任何给
我是 SignalR 的新手,如果这个问题太明显,我深表歉意,但我在文档中找不到任何答案。 这是我的代码。 /*1*/ actions.client.doActionA = function (r
我有这个应用程序,您可以在其中输入一些文本并按下一个按钮,将此文本添加到自定义小部件中。这是代码: import 'dart:core'; import 'package:flutter/materi
我读到当您还想使用模型回调时不能使用 Keras 进行交叉验证,但是 this post表明这毕竟是可能的。但是,我很难将其纳入我的上下文。 为了更详细地探讨这个问题,我正在关注 machinelea
我尝试在重力表单中提交表单失败后运行一些 jQuery 代码,也就是验证发现错误时。 我尝试使用 Ajax:complete 回调,但它根本不触发。 我尝试运行的代码基本上将监听器添加到选择下拉列表中
我有一个 $image,我 .fadeIn 和 .fadeOut,然后 .remove .fadeOut 完成。这是我的代码: $image .fadeIn() .fadeOut(func
我正在处理一个自定义文件路径类,它应该始终执行一个函数 写入相应的系统文件及其文件对象后 关闭。该函数将文件路径的内容上传到远程位置。 我希望上传功能完全在用户的幕后发生 透视,即用户可以像使用其他任
这里是 javascript 新手,所以回调在我的大脑中仍然有点不确定。 我想做的是:给定一个“菜单”,它是一个 objectId 数组,查询与该 objectId 相对应的每个 foodItem,获
我正在学习回调,我编写了以下代码: var http = require('http'); var str = ""; var count = 2; function jugglingAsync(ca
这是我的困境,我有一系列被调用的函数,我正在使用回调函数在它们完成时执行函数。回调返回一个值并且效果也很好,我的问题是当我向回调添加参数时我无法再访问返回值。这是一个有效的例子: function m
This question already has answers here: Explanation of function pointers (4个答案) 上个月关闭。 如何将函数指针作为参数传递
我无法让以下代码工作。假设 ajax 调用有效,并且 msg['username'] 预设为 'john'。我想我对如何将变量传递给回调感到困惑。编辑:我认为我的主要困惑是如何从 Ajax 中获取“m
我是一名优秀的程序员,十分优秀!