草庐IT

python - 在函数属性中访问 self

coder 2023-08-26 原文

我正在尝试添加一个装饰器,该装饰器将可调用属性添加到函数,这些函数返回的对象与函数的返回值略有不同,但会在某个时候执行该函数。

我遇到的问题是,当函数对象被传递到装饰器时,它是未绑定(bind)的并且不包含隐式的 self 参数。当我调用创建的属性函数(即 string())时,我无法访问 self,也无法将其传递给原始函数。

def deco(func):
    """
    Add an attribute to the function takes the same arguments as the
    function but modifies the output.
    """
    def string(*args, **kwargs):
        return str(func(*args, **kwargs))
    func.string = string
    return func


class Test(object):

    def __init__(self, value):
        self._value = 1

    @deco
    def plus(self, n):
        return self._value + n

当我去执行装饰器创建的属性时,这是我得到的错误,因为 args 不包含 self 引用。

>>> t = Test(100)
>>> t.plus(1)         # Gets passed self implicitly
101
>>> t.plus.string(1)  # Does not get passed self implicitly
...
TypeError: plus() takes exactly 2 arguments (1 given)

有没有一种方法可以创建这样的装饰器,它可以获得对self 的引用?或者有没有办法绑定(bind)添加的属性函数 (string()) 以便它被隐式 self 调用 参数?

最佳答案

您可以使用 descriptors这里:

class deco(object):

    def __init__(self, func):
        self.func = func
        self.parent_obj = None

    def __get__(self, obj, type=None):
        self.parent_obj = obj
        return self

    def __call__(self, *args, **kwargs):
        return self.func(self.parent_obj, *args, **kwargs)

    def string(self, *args, **kwargs):
        return str(self(*args, **kwargs))


class Test(object):

    def __init__(self, value):
        self._value = value

    @deco
    def plus(self, n):
        return self._value + n

这样:

>>> test = Test(3)
>>> test.plus(1)
4
>>> test.plus.string(1)
'4'

这需要一个解释。 deco 是一个装饰器,但它也是一个 descriptor .描述符是一个对象,它定义了在将该对象作为其父对象的属性进行查找时调用的替代行为。有趣的是,边界方法本身是使用描述符协议(protocol)实现的

那是一口。让我们看看运行示例代码时会发生什么。首先,当我们定义 plus 方法时,我们应用了 deco 装饰器。现在通常我们把函数看作装饰器,函数的返回值就是装饰后的结果。这里我们使用类作为装饰器。因此,Test.plus 不是函数,而是 deco 类型的实例。该实例包含对我们希望包装的 plus 函数的引用。

deco 类有一个__call__ 方法,允许它的实例像函数一样工作。此实现只是将给定的参数传递给它引用的 plus 函数。请注意,第一个参数将是对 Test 实例的引用。

棘手的部分在于实现 test.plus.string(1)。为此,我们需要引用 test 实例,其中 plus 实例是一个属性。为此,我们使用描述符协议(protocol)。也就是说,我们定义了一个 __get__ 方法,只要 deco 实例作为某个父类实例的属性被访问,该方法就会被调用。发生这种情况时,它将父对象存储在自身内部。然后我们可以简单地将 plus.string 实现为 deco 类的方法,并使用对存储在 deco 实例中的父对象的引用获取 plus 所属的 test 实例。

这有很多魔法,所以这里有一个免责声明:虽然这看起来很酷,但实现这样的东西可能不是一个好主意。

关于python - 在函数属性中访问 self,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40185890/

有关python - 在函数属性中访问 self的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  4. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  5. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  6. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  7. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  8. ruby - Nokogiri 剥离所有属性 - 2

    我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

  9. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  10. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

    对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

随机推荐