好吧,这是现实世界的场景:我正在编写一个应用程序,我有一个代表某种类型文件的类(在我的例子中,这是照片,但细节与问题无关).Photos类的每个实例对于照片的文件名应该是唯一的.
问题是,当用户告诉我的应用程序加载文件时,我需要能够识别文件何时已加载,并使用现有实例作为该文件名,而不是在同一文件名上创建重复实例.
对我而言,使用memoization似乎是一个很好的情况,并且有很多例子,但在这种情况下,我不只是记住一个普通的函数,我需要记忆__init__().这造成了一个问题,因为在__init__()被调用的时候已经太晚了,因为已经创建了一个新实例.
在我的研究中,我发现了Python的__new__()方法,我实际上能够编写一个简单的工作示例,但是当我尝试在我的真实世界对象上使用它时它就崩溃了,我不知道为什么(我唯一可以做到的)我想到的是我的真实世界对象是我无法控制的其他对象的子类,因此这种方法存在一些不兼容性.这就是我所拥有的:
class Flub(object):
instances = {}
def __new__(cls, flubid):
try:
self = Flub.instances[flubid]
except KeyError:
self = Flub.instances[flubid] = super(Flub, cls).__new__(cls)
print 'making a new one!'
self.flubid = flubid
print id(self)
return self
@staticmethod
def destroy_all():
for flub in Flub.instances.values():
print 'killing', flub
a = Flub('foo')
b = Flub('foo')
c = Flub('bar')
print a
print b
print c
print a is b, b is c
Flub.destroy_all()
Run Code Online (Sandbox Code Playgroud)
哪个输出:
making a new one! …Run Code Online (Sandbox Code Playgroud) 所以我最近问了一个关于memoization的问题,得到了一些很好的答案,现在我想把它提升到一个新的水平.经过相当多的谷歌搜索后,我找不到memoize装饰器的参考实现,它能够缓存一个带有关键字参数的函数.事实上,它们中的大多数只是用作*args缓存查找的关键,这意味着如果你想要记住一个接受列表或dicts作为参数的函数,它也会破坏.
在我的例子中,函数的第一个参数本身就是一个唯一的标识符,适合用作缓存查找的dict键,但是我希望能够使用关键字参数并仍然访问相同的缓存.我的意思是,my_func('unique_id', 10)并且my_func(foo=10, func_id='unique_id')应该返回相同的缓存结果.
为了做到这一点,我们需要的是一种清洁和pythonic的方式来说'检查kwargs是否与第一个参数相对应的关键字''.这就是我想出的:
class memoize(object):
def __init__(self, cls):
if type(cls) is FunctionType:
# Let's just pretend that the function you gave us is a class.
cls.instances = {}
cls.__init__ = cls
self.cls = cls
self.__dict__.update(cls.__dict__)
def __call__(self, *args, **kwargs):
"""Return a cached instance of the appropriate class if it exists."""
# This is some dark magic we're using here, but it's how we discover
# that the first argument to Photograph.__init__ is …Run Code Online (Sandbox Code Playgroud) 我需要一些帮助来理解Python中描述符协议的细微之处,因为它特别涉及staticmethod对象的行为.我将从一个简单的例子开始,然后迭代地扩展它,检查它在每一步的行为:
class Stub:
@staticmethod
def do_things():
"""Call this like Stub.do_things(), with no arguments or instance."""
print "Doing things!"
Run Code Online (Sandbox Code Playgroud)
在这一点上,这表现得如预期的那样,但这里发生的事情有点微妙:当你打电话时Stub.do_things(),你不是直接调用do_things.相反,它Stub.do_things指的是一个staticmethod实例,它将我们想要的函数包装在它自己的描述符协议中,这样你实际上就是调用它staticmethod.__get__,它首先返回我们想要的函数,然后被调用.
>>> Stub
<class __main__.Stub at 0x...>
>>> Stub.do_things
<function do_things at 0x...>
>>> Stub.__dict__['do_things']
<staticmethod object at 0x...>
>>> Stub.do_things()
Doing things!
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.接下来,我需要将类包装在将用于自定义类实例化的装饰器中 - 装饰器将确定是允许新的实例化还是提供缓存的实例:
def deco(cls):
def factory(*args, **kwargs):
# pretend there is some logic here determining
# whether to make a new instance or not
return cls(*args, …Run Code Online (Sandbox Code Playgroud) 我最近升级到了Emacs24,由于它,我的一些自定义键绑定被破坏了.
根据该精细的手工,有可能使Emacs的停止混为一谈与他们的ASCII控制码的功能键(例如,它可能有C-m,并RET绑定到不同的东西,或C-i和TAB,等等).这一直是我用Emacs的一个大小的烦恼,这种有价值的"第一级"键盘快捷键浪费在我已经在键盘上有专用键的东西上.在我的例子中,我希望将它们绑定到不同的东西,通过模仿gedit来"现代化"键绑定.在Emacs23中,这很漂亮:
(global-set-key (kbd "C-i") 'goto-line)
(global-set-key (kbd "C-m") 'comment-or-uncomment-region)
(global-set-key (kbd "C-d") 'kill-whole-line)
;; Fix some stuff broken by the above
(global-set-key [delete] 'delete-char)
(global-set-key (kbd "TAB") 'indent-for-tab-command)
(global-set-key (kbd "RET") 'newline)
Run Code Online (Sandbox Code Playgroud)
然后,我升级到Emacs24,它破了,有点.它仍然"工作",在某种意义上C-m肯定做一件事,RET做另一件事,但问题是返回键在终端模式或迷你缓冲器中不再正常运行.在两种情况下,返回键只是将光标向下移动到下一行,而不是激活我输入的命令,而不是激活我输入迷你缓冲区或终端的命令.
具有讽刺意味的是,Emacs24对删除行为进行了很多更改,并且在这个过程中它们分离C-d,DEL以便实际上现在可以安全地绑定C-d到某些东西而不需要绑定DEL回预期的行为,所以如果我能实现它会很棒类似的"它只是工作"我的返回键的行为,而C-m绑定到别的东西.
所以,我可以设想两个可能的解决方案来解决这个问题.一个可能看起来像这样:
(global-set-key (kbd "C-m") 'comment-or-uncomment-region)
(global-set-key (kbd "RET") 'do-what-i-expect-the-return-key-to-do-in-any-mode)
Run Code Online (Sandbox Code Playgroud)
或者,这样的事情会更好:
(setq decouple-ascii-control-codes-from-function-keys t)
Run Code Online (Sandbox Code Playgroud)
但我不知道任何这样的变量或函数可以帮助我在这种情况下.
我已经做了几次尝试使用模式挂钩在终端和迷你缓冲模式下恢复正确绑定的尝试失败,但我似乎无法得到任何工作.救命!
谢谢.
我正在使用PyGObject编写一个小型/中型GUI应用程序(基于Gtk的新的基于内省的绑定).我开始使用一个合理的测试套件,nose它能够通过简单地导入模块并调用各种函数并检查结果来测试我的应用程序的大部分功能.
但是,最近我开始利用一些Gtk功能,比如GLib.timeout_add_seconds一个相当简单的回调机制,它只是在一个计时器到期后调用指定的回调.我现在面临的问题是我的代码似乎在我使用应用程序时起作用,但是测试套件的封装很差,所以当一个测试检查它是以干净状态开始时,它发现它的状态已被全部踩踏了由其他测试注册的回调.具体来说,测试成功检查没有加载文件,然后加载一些文件,然后检查文件在加载后是否未被修改,测试失败!
我花了一段时间来弄清楚发生了什么,但基本上一个测试会修改一些文件(启动计时器)然后关闭它们而不保存,然后另一个测试将重新打开未修改的文件并发现它们被修改,因为定时器启动后,回调改变了文件.
我已经阅读了Python reload()内置用于重新加载模块的内容,希望我可以将其卸载并重新加载我的应用程序以获得一个新的开始,但它似乎似乎没有工作.
我担心我可能不得不求助于将应用程序作为子进程启动,修补它,然后结束子进程并在需要保证新状态时重新启动它.是否有任何测试框架可以使这很容易,特别是对于pygobject代码?
我试图建立一个新的Django项目,我已经配置TEST_RUNNER的settings.py是django_nose.NoseTestSuiteRunner。
我选择这个测试运行器是因为它似乎是我能找到的唯一一个具有以下功能的测试运行器:
但是我听说鼻子没有保养,我很难找到合适的替代品。据我所知,标准测试运行程序不会捕获日志记录,也不会写入 xunit(希望被证明是错误的!)
我像这样运行测试:
python -m coverage run manage.py test --noinput
python -m coverage report --include="app/*" --show-missing --fail-under=100
python -m coverage xml --include="app/*" -o ./reports/coverage.xml
Run Code Online (Sandbox Code Playgroud)
在 settings.py 中有这个:
TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
Run Code Online (Sandbox Code Playgroud)
而这个 setup.cfg:
[nosetests]
verbosity=0
with-xunit=1
xunit-file=./reports/xunit.xml
logging-clear-handlers=1
Run Code Online (Sandbox Code Playgroud)
最后两行是我在其他测试运行程序中似乎找不到的真正多汁的部分。鼻子捕获日志并清除其他日志处理程序(例如,转储到标准输出的处理程序),因此测试运行输出更清晰(您只能看到失败测试的日志记录)。
在其他非 django 项目中,我通常使用nose2,但 django-nose2 项目似乎已有 6 年历史并且缺乏 python3 支持?
请让我知道哪个测试运行器是 Django 支持的“推荐”(例如,最受欢迎的)测试运行器,谢谢。
最近,StackOverflow社区帮助我开发了一个相当简洁的@memoize装饰器,它不仅能够以一般方式装饰函数,还能够装饰方法和类,即,无需预先知道它将装饰什么类型的东西.
我遇到的一个问题是,如果你用一个类装饰一个类@memoize,然后尝试用它来装饰其中一个方法@staticmethod,这将无法按预期工作,即你根本无法调用ClassName.thestaticmethod().我提出的原始解决方案看起来像这样:
def memoize(obj):
"""General-purpose cache for classes, methods, and functions."""
cache = obj.cache = {}
def memoizer(*args, **kwargs):
"""Do cache lookups and populate the cache in the case of misses."""
key = args[0] if len(args) is 1 else args
if key not in cache:
cache[key] = obj(*args, **kwargs)
return cache[key]
# Make the memoizer func masquerade as the object we are memoizing.
# This makes class attributes and static methods behave …Run Code Online (Sandbox Code Playgroud)