Basic Method Chaining

Basic method chaining

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'

Method chaining - why is it a good practice, or not?

I agree that this is subjective. For the most part I avoid method chaining, but recently I also found a case where it was just the right thing - I had a method which accepted something like 10 parameters, and needed more, but for the most time you only had to specify a few. With overrides this became very cumbersome very fast. Instead I opted for the chaining approach:

MyObject.Start()
.SpecifySomeParameter(asdasd)
.SpecifySomeOtherParameter(asdasd)
.Execute();

The method chaining approach was optional, but it made writing code easier (especially with IntelliSense). Mind you that this is one isolated case though, and is not a general practice in my code.

The point is - in 99% cases you can probably do just as well or even better without method chaining. But there is the 1% where this is the best approach.

Basic method chaining with DOM elements

As already explained in a comment this is not the selected element. With minimal refactoring in your code what you can do is adding a new element property to your object, setting it in getId and using that element in text. For instance:

'use strict'let chain = {  element: null,  getId(id) {    this.element = document.getElementById(id);    return this  },  text(content) {    this.element.textContent = content;    return this;  }}window.addEventListener('load', function() {  let dummy = chain.getId('dummy').text('works');})
<div id='dummy'></div>

Dataclasses - Basic method chaining

Instead of calling export_json directly from query, save the result in an instance attribute and return self to enable chaining. Then export_json looks for the saved query on the instance, rather than taking it as an argument.

@dataclass
class Data_Query:
hierarchic: str
sku: bool
pred_lenght: int

def query(self, db):
if (self.hierarchic == 'store' and self.sku == True):
self.x = db.aggregate([{...}]);
# self.export_json(x)
return self
def export_json(self, file):
try:
x = self.x
except AttributeError:
return

with open(f'/home/Documents/dataset/{file}', 'w') as fp:
for i in x:
json.dump(i, fp)
fp.write('\n')
del self.x

Now you can write data.query(db).export_json('abc.json'), and the JSON file
will only be written if, in fact, a query takes place.

However, this isn't the greatest design. Nothing about export_json is specific to your class; it should be a regular function that takes a result and a file name
and that you call after you make a query, if the query returns any results. Something more like

@dataclass
class Data_Query:
hierarchic: str
sku: bool
pred_lenght: int

def query(self, db):
if (self.hierarchic == 'store' and self.sku == True):
return db.aggregate([{...}])

def export_json(self, x, file):
with open(f'/home/Documents/dataset/{file}', 'w') as fp:
for i in x:
json.dump(i, fp)
fp.write('\n')

result = data.query(db)
if result is not None:
export_json(result, 'abc.json')

You might argue "Of course export_json is related to my class; it assumes that x is an iterable of objects, which is something defined by the query method." In that case, you might consider defining a QueryResult class, and make export_json a method of that class. Then DataQuery.query returns an instance of QueryResult, and chaining feels a little less arbitrary: you are exporting the result, not the query.

# By the way, I am assuming there is more to this class than a query
# method; otherwise, there should probably just be a regular function
# that takes the db, hierarchic, and sku as arguments.
@dataclass
class DataQuery:
hierarchic: str
sku: bool
pred_length: int

def query(self, db):
result = None
if self.hierarchic == 'store' and self.sku:
result = db.aggregate(...)
return QueryResult(result)

class QueryResult:
def __init__(self, result):
self.result = result

def export_json(self, file):
if self.result is None:
return

with open(f'/home/Documents/dataset/{file}', 'w') as fp:
for i in x:
json.dump(i, fp)
fp.write('\n')

data.query(db).export_json('abc.json')

How to do method chaining in Java? o.m1().m2().m3().m4()

This pattern is called "Fluent Interfaces" (see Wikipedia)

Just return this; from the methods instead of returning nothing.

So for example

public void makeText(String text) {
this.text = text;
}

would become

public Toast makeText(String text) {
this.text = text;
return this;
}

method chaining in python

Caveat: This only works on class methods() that do not intend to return any data.

I was looking for something similar for chaining Class functions and found no good answer, so here is what I did and thought was a very simple way of chaining: Simply return the self object.

So here is my setup:

class Car:
def __init__(self, name=None):
self.name = name
self.mode = 'init'

def set_name(self, name):
self.name = name
return self

def drive(self):
self.mode = 'drive'
return self

And now I can name the car and put it in drive state by calling:

my_car = Car()
my_car.set_name('Porche').drive()

Hope this helps!

Python class methods chaining

These are not class methods, they are instance methods. For method chaining, it is imperative that each method returns an object that implements the next method in the chain. Since all of your methods are instance methods of BaseModel, you need to return an instance of BaseModel (or a descendant of it). That obviously means that you cannot return df (since presumably df is not an object of BaseClass). Store it in the instance and retrieve it at the end of the chain.

class BaseModel:

def __init__(self):
pass

def read_data(self):
self.df = ...
return self

def transform_input(self):
self.df = ...
return self

def execute(self):
self.df = ...
return self

def run(self):
data = self.read_data().transform_input().execute().df

For difference between instance methods and class methods, this answer gives a nice overview.

chaining methods in base and derived class

Use generic extension methods

Fluent/chaining methods work best as generic extension methods. A generic extension method knows the type of the instance variable and can return it as the same type that was passed in.

class Animal
{
public string CommonProperty { get; set; }
}

class Dog : Animal
{
public string DogOnlyProperty { get; set; }
}

static class ExtensionMethods
{
static public T AnimalMethod<T>(this T o) where T : Animal
{
o.CommonProperty = "foo";
return o;
}
static public T DogMethod<T>(this T o) where T : Dog
{
o.DogOnlyProperty = "bar";
return o;
}

}

class Example
{
static public void Test()
{
var dog = new Dog();
dog.DogMethod().AnimalMethod(); // 1 - this works
dog.AnimalMethod().DogMethod(); // 2 - this works now

Console.WriteLine("CommonProperty = {0}", dog.CommonProperty);
Console.WriteLine("DogOnlyProperty = {0}", dog.DogOnlyProperty);

var animal = new Animal();
animal.AnimalMethod();
//animal.DogMethod(); //Does not compile
//animal.AnimalMethod().DogMethod(); //Does not compile
}
}

Output:

CommonProperty = foo

DogOnlyProperty = bar

A workaround if you need private/protected access

One disadvantage of extension methods is that they cannot access private or protected members. Your instance method could. This hasn't been a problem for me (and it seems it's not an issue for the entire LINQ library either, which are written as extension methods). But there is a workaround if you need access.

You will need to implement the "chaining" method twice-- once as an interface method on the instance and a simple wrapper (one line of code) as an extension method that simply calls the first method. We use an interface method on the instance so that the compiler won't try to pick the instance method over the extension method.

interface IPrivateAnimal
{
Animal AnimalMethod();
}

interface IPrivateDog
{
Dog DogMethod();
}

class Animal : IPrivateAnimal
{
protected virtual string CommonProperty { get; set; } //notice this is nonpublic now

Animal IPrivateAnimal.AnimalMethod() //Won't show up in intellisense, as intended
{
this.CommonProperty = "plugh";
return this;
}
}

class Dog : Animal, IPrivateDog
{
private string DogOnlyProperty { get; set; } //notice this is nonpublic now

Dog IPrivateDog.DogMethod() //Won't show up in intellisense
{
this.DogOnlyProperty = "xyzzy";
return this;
}
}

static class ExtensionMethods
{
static public T AnimalMethod<T>(this T o) where T : class, IPrivateAnimal
{
return o.AnimalMethod() as T; //Just pass control to our hidden instance method
}
static public T DogMethod<T>(this T o) where T : class, IPrivateDog
{
return o.DogMethod() as T; //Just pass control to the instance method
}
}

class Example
{
static public void Test()
{
var dog = new Dog();
dog.DogMethod().AnimalMethod();
dog.AnimalMethod().DogMethod();

Console.WriteLine("CommonProperty = {0}", typeof(Dog).GetProperty("CommonProperty", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dog));
Console.WriteLine("DogOnlyProperty = {0}", typeof(Dog).GetProperty("DogOnlyProperty", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(dog));
}
}

Output:

CommonProperty = plugh

DogOnlyProperty = xyzzy

Method chaining, which is run first?

Methods are called from left to right.

D3.js is a particular case, this article explains nicely what happens:
Thinking with Joins



Related Topics



Leave a reply



Submit