Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Basic method chaining

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 understand method chaining (given that I am still not 100% confident with callables).

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'.

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.

like image 450
Pezze Avatar asked Jan 23 '17 23:01

Pezze


People also ask

How do you use chaining method?

Method Chaining is the practice of calling different methods in a single line instead of calling other methods with the same object reference separately. Under this procedure, we have to write the object reference once and then call the methods by separating them with a (dot.).

What is method chaining in C#?

Method chaining is a technique in which methods are called on a sequence to form a chain and each of these methods return an instance of a class. These methods can then be chained together so that they form a single statement. A fluent interface is an object-oriented API that depends largely on method chaining.

What is method chaining Why is it bad?

Method chaining just means chaining multiple method calls into a single expression, rather than using multiple statements. Because the find method returns a different object from the click method. It also encourages people to write code that silently fails.

What is method chaining in Python with example?

Method chaining is a technique that is used for making multiple method calls on the same object, using the object reference just once. Example − Assume we have a class Foo that has two methods, bar and baz. We create an instance of the class Foo − foo = Foo()


2 Answers

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' 
like image 82
Robᵩ Avatar answered Oct 02 '22 14:10

Robᵩ


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.

like image 24
Eli Korvigo Avatar answered Oct 02 '22 15:10

Eli Korvigo