Basic method chaining

后端 未结 3 1293
暗喜
暗喜 2020-12-01 00:41

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

Here the goals are two: solve the coding problem and under

相关标签:
3条回答
  • 2020-12-01 01:14

    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()__).

    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 foo objects in a non-chained way by ignoring their returned values:

    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 concept from method chaining. If you want chain properties, and have those properties mutate their object, use the @property decorator. (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.)

    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'
    
    0 讨论(0)
  • 2020-12-01 01:27

    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.

    0 讨论(0)
  • 2020-12-01 01:29

    ther's an another interesting way of achieving this

    class Foo:
        def __init__(self, kind=[]):
            self.kind = kind
    
        def __getattr__(self, attrs):
            self.attrs = attrs
            return Foo(self.kind + [attrs]) 
    
        def __call__(self):
            return self.kind[::-1][0]
    
    
    my_obj = Foo()
    print(my_obj.bar.line.bar.bar.line())
    

    with this code u don't have to pass .my_print() but one thing to note here is the Foo class will take anything as argument like if we try print(my_obj.bar.line.bar.bar.circle()) it will return circle.

    You can also edit this code to take the args while calling any function.

    0 讨论(0)
提交回复
热议问题