Python 基本方法链

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41817578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 01:40:18  来源:igfitidea点击:

Basic method chaining

pythoncallablemethod-chaining

提问by Pezze

I found this method chaining in python, but even with it I couldn't understand method chaining in Python.

在 python 中发现了这个方法链,但即使有了它,我也无法理解 Python 中的方法链。

Here the goals are two: solve the coding problem and understand method chaining (given that I am still not 100% confident with callables).

这里的目标有两个:解决编码问题并理解方法链(鉴于我对可调用对象仍然不是 100% 有信心)。

Down to the problem definition.

归结为问题定义。

I want a class that has two methods: one sets a parameter of the object = 'line' and the other overwrites to 'bar'.

我想要一个具有两种方法的类:一个设置对象 = 'line' 的参数,另一个覆盖为 'bar'。

This is what I got so far:

这是我到目前为止得到的:

class foo():
    def __init__(self, kind=None):
        self.kind = kind

    def __call__(self, kind=None):
        return foo(kind=kind)

    def my_print(self):
        print (self.kind)

    def line(self):
        return self(kind='line')
    def bar(self):
        return self(kind='bar')

Sadly, with this code I can achieve my goal doing this

可悲的是,使用此代码我可以实现我的目标

a = foo()
a.bar().line().bar().bar().line().my_print()

But I would like to obtain the same result by writing this code

但我想通过编写此代码获得相同的结果

a = foo()
a.bar.line.bar.bar.line.my_print()

How do I achieve this? I guess is something wrong in how I defined the __call__method. Thanks in advance for your help.

我如何实现这一目标?我想我定义__call__方法的方式有问题。在此先感谢您的帮助。

回答by Rob?

Method chaining is simply being able to add .second_func()to whatever .first_func()returns. It is fairly easily implemented by ensuring that all chainable methods return self. (Note that this has nothing to do with __call()__).

方法链只是能够添加.second_func()到任何.first_func()返回。通过确保所有可链接的方法都返回,它很容易实现self。(请注意,这与 无关__call()__)。

class foo():
    def __init__(self, kind=None):
        self.kind = kind
    def my_print(self):
        print (self.kind)
        return self
    def line(self):
        self.kind = 'line'
        return self
    def bar(self):
        self.kind='bar'
        return self

You can use fooobjects in a non-chained way by ignoring their returned values:

您可以foo通过忽略对象的返回值以非链接方式使用对象:

a = foo()
a.line()
a.my_print()
a.bar()
a.my_print()

assert a.kind == 'bar'

Or, since every function now returns the object itself, you can operate directly on the returned value. You can use method chaining with this equivalent code:

或者,由于每个函数现在都返回对象本身,您可以直接对返回值进行操作。您可以使用具有以下等效代码的方法链:

b = foo()
b.line().my_print().bar().my_print()
assert b.kind == 'bar'

Or even:

甚至:

c = foo().line().my_print().bar().my_print()
assert c.kind == 'bar'

The question of getting rid of the ()calling syntax is a completely separate conceptfrom method chaining. If you want chain properties, and have those properties mutate their object, use the @propertydecorator. (But mutating objects via a property seems dangerous. Better to use a method and name it with a verb: .set_line()instead of .line, for example.)

摆脱()调用语法的问题是与方法链完全不同的概念。如果您想要链属性,并让这些属性改变它们的对象,请使用@property装饰器。(但是通过属性改变对象似乎很危险。最好使用一个方法并用动词命名它:.set_line()而不是.line,例如。)

class foo():
    def __init__(self, kind=None):
        self.kind = kind
    def my_print(self):
        print (self.kind)
        return self
    @property
    def line(self):
        self.kind = 'line'
        return self
    @property
    def bar(self):
        self.kind='bar'
        return self

a = foo()
a.line
a.my_print()
a.bar
a.my_print()

assert a.kind == 'bar'

b = foo()
b.line.my_print().bar.my_print()
assert b.kind == 'bar'

c = foo().line.my_print().bar.my_print()
assert c.kind == 'bar'

回答by Eli Korvigo

Use properties (descriptors).

使用属性(描述符)。

class foo:
    def __init__(self, kind=None):
        self.kind = kind

    def __call__(self, kind=None):
        return foo(kind=kind)

    def my_print(self):
        print (self.kind)

    @property
    def line(self):
        return self(kind='line')

    @property
    def bar(self):
        return self(kind='bar')

Note, though, that you overwrite nothing, the modification doesn't work inplace (which is arguably good, btw). Anyway, this doesn't look like a good design choice for most real-world cases, because at some point your methods will require arguments.

但是请注意,您没有覆盖任何内容,修改不会就地起作用(顺便说一句,这可以说是好的)。无论如何,对于大多数实际情况来说,这看起来不是一个好的设计选择,因为在某些时候您的方法将需要参数。