如何在不明确接受的情况下将自己变成Python方法 [英] How to get self into a Python method without explicitly accepting it

查看:77
本文介绍了如何在不明确接受的情况下将自己变成Python方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个文档测试框架-基本上是PDF的单元测试.测试是框架定义的类的实例的(修饰)方法,它们在运行时定位和实例化,并调用这些方法来执行测试.

我的目标是减少编写测试的人需要关注的古怪的Python语法,因为这些人可能是也可能不是Python程序员,甚至根本不是很多程序员.因此,我希望他们能够为方法编写"def foo():"而不是"def foo(self):",但仍然能够使用"self"访问成员.

在一个普通程序中,我会认为这是一个可怕的想法,但是在像这样的领域特定语言的程序中,似乎值得尝试.

我已经通过使用装饰器成功地从方法签名中消除了self(实际上,由于我已经在测试用例中使用了装饰器,因此我将其放入其中),但是"self"并不表示测试用例方法中的任何内容.

我已经考虑过使用全局自变量,甚至提出了一个或多或少有效的实现,但是我宁愿污染最小的命名空间,这就是为什么我更愿意将变量直接注入测试中的原因case方法的本地名称空间.有什么想法吗?

解决方案

这里是一个单行方法修饰器,似乎无需修改任何

请注意,除非采取预防措施,否则副作用的功能可能是eval()函数的自动添加到传递给它的dict的一些条目,例如在__builtins__键下对__builtin__模块的引用. >

@kendall:根据您对容器类中的方法如何使用它的评论(但暂时不考虑其他变量的注入)-以下是您正在做的事情吗?对于我来说,很难理解框架和用户编写的内容之间是如何划分的.对我来说,这听起来像是一种有趣的设计模式.

# method decorator -- makes undeclared 'self' argument available to method
injectself = lambda f: lambda self: eval(f.func_code, dict(self=self))

class methodclass:
    def __call__():
        print 'in methodclass::__call__(): self.attr = %r' % self.attr
        return 42

class TestClass:
    def __init__(self, thing):
        self.attr = thing

    method = injectself(methodclass.__call__)

test = TestClass("attribute's value")
ret = test.method()
print 'return value:', ret

# output
# in methodclass::__call__(): self.attr = "attribute's value"
# return value: 42

I'm developing a documentation testing framework -- basically unit tests for PDFs. Tests are (decorated) methods of instances of classes defined by the framework, and these are located and instantiated at runtime and the methods are invoked to execute the tests.

My goal is to cut down on the amount of quirky Python syntax that the people who will write tests need to be concerned about, as these people may or may not be Python programmers, or even very much programmers at all. So I would like them to be able to write "def foo():" instead of "def foo(self):" for methods, but still be able to use "self" to access members.

In an ordinary program I would consider this a horrible idea, but in a domain-specific-languagey kind of program like this one, it seems worth a try.

I have successfully eliminated the self from the method signature by using a decorator (actually, since I am using a decorator already for the test cases, I would just roll it into that), but "self" does not then refer to anything in the test case method.

I have considered using a global for self, and even come up with an implementation that more or less works, but I'd rather pollute the smallest namespace possible, which is why I would prefer to inject the variable directly into the test case method's local namespace. Any thoughts?

解决方案

Here's a one line method decorator that seems to do the job without modifying any Special attributes of Callable types* marked Read-only:

# method decorator -- makes undeclared 'self' argument available to method
injectself = lambda f: lambda self: eval(f.func_code, dict(self=self))

class TestClass:
    def __init__(self, thing):
        self.attr = thing

    @injectself
    def method():
        print 'in TestClass::method(): self.attr = %r' % self.attr
        return 42

test = TestClass("attribute's value")
ret = test.method()
print 'return value:', ret

# output:
# in TestClass::method(): self.attr = "attribute's value"
# return value: 42

Note that unless you take precautions to prevent it, a side-effect of the eval() function may be it adding a few entries -- such as a reference to the __builtin__ module under the key __builtins__ -- automatically to the dict passed to it.

@kendall: Per your comment about how you're using this with methods being in container classes (but ignoring the injection of additional variables for the moment) -- is the following something like what you're doing? It's difficult for me to understand how things are split up between the framework and what the users write. It sounds like an interesting design pattern to me.

# method decorator -- makes undeclared 'self' argument available to method
injectself = lambda f: lambda self: eval(f.func_code, dict(self=self))

class methodclass:
    def __call__():
        print 'in methodclass::__call__(): self.attr = %r' % self.attr
        return 42

class TestClass:
    def __init__(self, thing):
        self.attr = thing

    method = injectself(methodclass.__call__)

test = TestClass("attribute's value")
ret = test.method()
print 'return value:', ret

# output
# in methodclass::__call__(): self.attr = "attribute's value"
# return value: 42

这篇关于如何在不明确接受的情况下将自己变成Python方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆