如何在现有的python函数中添加一行代码

时间:2014-04-13 15:03:15

标签: python

我最近一直在阅读有关房产的信息(即property装饰师),我得出的结论是,我不太喜欢它实施的方式在python中。好吧,我知道它不是语言本身的内部部分(例如,它没有像C#那样内置于语言中),但我真的认为它们可以更好地实现它(即使只有装饰器) )。我想以我认为应该实施的方式进行概念验证,并且我有一点障碍(虽然......但是没有什么可以克服的。)

以下是我的想法: 假设我们有一个Person类,其属性为name。我定义属性的方式如下:

class Person():
    def __init__(self, name, age):
        self._name = name
        self._age = age

    @my_property
    def name(self):
        def getter(self):
            return self._name

        def setter(self, value):
            self._name = value

        def deleter(self):
             del self._name

        return getter, setter, deleter

我们将装饰器my_property定义如下:

def my_property(f):
    d = {g.__name__: g for g in f(None)}
    p = property(d.get('getter'), d.get('setter'), d.get('deleter'))
    return p

现在,这很好用,但我真的想通过允许用户不显式添加代码行来改进它: return getter, setter, deleter。相反,我希望装饰器将该行添加到传递给它的函数f(在我们的例子中是name方法)。我想我必须使用f的代码对象(即f.__code__),但我无法弄清楚如何完成我想要的东西。

我的属性应该是什么样的方式与属性的C#语法非常相似。我相信相同字段的getter,setter和deleter应该在一些代码块中组合在一起(在我的例子中我选择了一个函数定义),而不是在(最多)3个单独的方法中遍布整个类(即使它们具有相同的名称,它们仍然在语法上分离)...此外,我认为它现在的定义方式 - 首先通过{{1}将getter声明为属性装饰器,然后使用getter的名称来装饰setter和删除器非常难看。但那只是我:)。

更新

接受 @User 的答案后,我重新实现了我的属性装饰器,使用了从包装器方法的代码对象中获取代码对象的想法。这是我的新实现,它仍然只是一个原型(我相信它可以进一步改进)。我决定使用我的新装饰器(它使用原始的property装饰器)来遮蔽内置property装饰器,但它可以随心所欲地调用...总的来说,我认为它是'非常酷,我希望Python有一个property关键字用于定义属性,而不是使用方法定义或类定义(在他的回答中由 @User 建议)。 / p>

property

1 个答案:

答案 0 :(得分:3)

现在你可以让它变得更漂亮:

>>> def dec(f):
    import types
    codes = []
    for code in f.__code__.co_consts:
        if isinstance(code, types.CodeType):
            codes.append(code)
    getter = types.FunctionType(codes[0], f.__globals__)
    setter = types.FunctionType(codes[1], f.__globals__)
    detter = types.FunctionType(codes[2], f.__globals__)
    return property(getter, setter, detter, f.__doc__)

>>> class X:
    @dec
    def f():
        def g(*args):
            print('get', args)
        def h(*args):
            print('set', args)
        def j(*args):
            print('del', args)


>>> X().f
get (<__main__.X object at 0x02DFD870>,)
>>> X().f = 1
set (<__main__.X object at 0x02E13750>, 1)
>>> del X().f
del (<__main__.X object at 0x02DFD870>,)

我对你的想法感兴趣。

但也许使用类装饰器

会更好
@dec
class attribute: 
     # ... functions

也许还有with声明:

with makeProperty:
     # ... functions