Method Chaining Classes in Python

preview_player
Показать описание
Method chaining, cascading, or the "Fluent API".

This style of programming involves having methods of a class return the object they operate on in order to allow a subsequent method call. This is used to chain mutations of an instance or can also be used creating copies for immutable objects. This is not the most common style of programming, but it does have some niche uses, which we explore in this video.

SUPPORT ME ⭐
---------------------------------------------------

Top patrons and donors: Jameson, Laura M, Dragos C, Vahnekie, John Martin, Casey G

BE ACTIVE IN MY COMMUNITY 😄
---------------------------------------------------

CHAPTERS
---------------------------------------------------
0:00 Intro
0:12 Basic example
1:20 Immutable examples
2:21 SQLAlchemy select
3:18 Pyjanitor example
Рекомендации по теме
Комментарии
Автор

Can you do more videos related to sql + python? This is 80-90% of the type of usage at work.

giovannifuentes
Автор

I see this pattern all the time in other OOP languages. I think Python's whitespace syntax discourages people from doing it in Python quite as often

tassaron
Автор

One of the main disadvantages of the method chaining pattern is that it makes one single expression out of several statements. Why is this a disadvantage?

1. If you have an exception somewhere in one of the called methods, the line number in the stack trace for this frame will be the line number where the whole expression begins. As a result, you do not have the information which of the calls produced the problem. (Mostly relevant if you call one method more than once, e.g., foo.bar(arg1).bar(arg2) of course.)

2. If you want to do anything between the calls (e.g., printf-debugging), you have to split it up at this point, which makes inserting and commenting out the inserted code way less simple.

3. If any of the calls should be wrapped in a try/except construct, you again will have to split it up, and if you prefer chaining, you can only wrap the complete chain into one try/except. This will catch more exceptions than you originally intended.

Though Python allows this design pattern, I cannot really recommend it in most cases. Python, in its core, still is an imperative language, and the method chaining is stolen from the realm of the functional languages (in which it makes perfect sense). It only should be used if what you create is an aggregated build-up like in the SQL example.

alfeberlin
Автор

I love chaining very much, but I would love it even more if there was an explicit naming convention about methods that return copies vs ones that modify in place, without reading the docs.

In fact, the sort() vs sorted() pattern could be followed so that verb-names modify in place, whereas past-tense-names return copies.

Unfortunately, pandas and numpy, which are probably the most profound examples of chaining, don't follow this one already, so maybe nothing can be done.

stkyriakoulisdr
Автор

Chaining this way is more like cleaning up for a final version because in development you're gonna want to test and debug each method.

jdal
Автор

Your pandas example is not very idiomatic. All of that can easily be done in pandas itself:
(pd.DataFrame
.from_dict(company_sales)
.drop(columns=['Company1'])
.dropna(subset=['Company2', 'Company3'])
.rename(columns={'Company2': 'Amazon', 'Company3': 'Facebook'})
.assign(Google=[450, 550, 800])
) Pandas actually has awesome method chaining capabilities.

minutiomusicolo
Автор

LINQ in C# and filters in other languages (and ofc in string manipulations) this chaining is just insanely useful and one of my favourite techniques that has become popular in last 2 decades

Especially the first time I saw LINQ in action when it was first show cased to the public during the start of my career in the mid 2000s-ish absolutely blew me away

Songfugel
Автор

Thank you! I moved from python to R because I loved the flow of data mangling with the tidyverse, but I still need to use python for some things so this will help out tremendously!

JBRD
Автор

When I see you I think: "Finally, actually advanced tutorials and good explanations". Super good video!

knut-olaihelgesen
Автор

I see this all the time in frameworks, but usually doesn't come up much on private projects unless they're fairly large.

For those of you who dislike having to use parens to separate statements in their own lines I suggest try 'black' for auto formatting.

However, you'll find that it some times refuses to separate things that can go in a single line and imho that's the right way. If it's short enough is usually more readable as a one liner

virtualraider
Автор

You come here expeciting to learn about method chaining, but instead after 5 years i´v learned that strings have a built in center function and type(x)(y) is valid syntax

Boothiepro
Автор

hands down my favorite coding channel on yt

marcegger
Автор

Related topic: I work at a data science company and just wrote a library that lets you chain function calls together using the bitshift operator >>. I honestly think the chaining syntax makes more sense for functional styles (monads anyone?). So basically you decorate your functions and then you can do f1 >> f2 >> f3 ≈ lambda x: f3(f2(f1(x)))

austinnar
Автор

Thanks for the video. I have recently seen this when dealing with Selenium+Page Object Model.
While this style of code looks cleaner, it may be more difficult to debug, at least before PEP-657 (Include Fine Grained Error Locations in Tracebacks) arrives in Python 3.11, because tracebacks of Python 3.10 and before currently only show the line of error but not the exact location of the error.

Yesterday, I read something related to monad in Python. And the author suggests to use method chaining for his `bind(self, func)` method too.
One interesting idea in the article is to overload the bitwise or operator ( | ), __or__, to do the chaining.
For his example, to do error handling for `str(neg(int(x)))`, he could do:
(1) `ErrorHandled(x).bind(int).bind(neg).bind(str)`,
or (2) `ErrorHandled(x) | int | neg | str`.

NicolasChanCSY
Автор

makes me remember my years with smalltalk... everything with cascades, and its beautiful

daknyx
Автор

I think python should allow this to work by just indenting the extra lines in the expression so you don't need any of the fancy \ or ()

Example:
Turtle()
.left(90)
.forward(100)

This would usually throw an error and I don't think anyone would write code like this by mistake.

_dot_
Автор

I first made major use of this in Qahirah, my pure-Python binding for Cairo graphics. Doing sequences of graphics calls on a drawing context is a very frequent operation. It is also handy for creating temporary contexts just to do some calculation, e.g. creating a “scaled font” (cached font at a predetermined size):

label_font = \


.set_font_size(12)
).scaled_font

lawrencedoliveiro
Автор

Good god, where has pyjanitor been all my life?

jamessimmons
Автор

Coming from a humble Sql beginning, I must say that this is a very eloquent, pythonic way of building queries.

I see what it would look like if Pandas was the library used to do the same as your examples and I feel that you have discovered a jewel in my opinion. Kudos

I think PyJanitor offers an on the fly approach to dynamically build code vs a static, linear way of building code.

I am thinking out loud but I would like to give this a try.

SolidBuildersInc
Автор

Most of the time, I either make back-end web apps, or libraries for robots. In latter, this would be extremely useful because so many methods just move a robot (and have to be called sequentially). Thanks a lot, James!

eccentricOrange