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 operatedirectly 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 filewill 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 becomepublic 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 = fooA workaround if you need private/protected accessDogOnlyProperty = bar
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 = plughDogOnlyProperty = 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
Loading Initial Data with Django 1.7 and Data Migrations
How to Include Image Files in Django Templates
What Is the Default _Hash_ in Python
Asyncio: How to Cancel a Future Been Run by an Executor
How to Save Final Model Using Keras
Use Index in Pandas to Plot Data
Python Observer Pattern: Examples, Tips
Saving Plots (Axessubplot) Generated from Python Pandas with Matplotlib's Savefig
How to Use a Default Namespace in an Lxml Xpath Query
In Python, What Happens When You Import Inside of a Function
How to Query Multiindex Index Columns Values in Pandas
How to Limit the Maximum Value of a Numeric Field in a Django Model
How to Modify Procfile to Run Gunicorn Process in a Non-Standard Folder on Heroku
Python Running as Windows Service: Oserror: [Winerror 6] the Handle Is Invalid
Parallelize Apply After Pandas Groupby