Are you fluent in Python, or do you speak the language with an accent?
Python's ease of learning can also lead to non-Pythonic patterns for even experienced developers.
Luciano Romalo is here to give us a deeper understanding of this language we love.
It's episode number 24, recorded Thursday, August 6, 2015.
I'm a developer in many senses of the word, because I make these applications, but I also use these verbs to make this music.
I construct it line by line, just like when I'm coding another software design.
In both cases, it's about design patterns. Anyone can get the job done, it's the execution that matters.
I have many interests, sometimes conflict.
Welcome to Talk Python to Me, a weekly podcast on Python.
The language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy. Follow me on Twitter where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
This episode is brought to you by Hired and CodeChip.
Thank them for supporting the show on Twitter via at Hired underscore HQ and at CodeChip.
Before we get to the conversation with Luciano, he generously agreed to give away an electronic copy of his book, Fluent Python.
All you have to do to be eligible to win is to be a friend of the show.
Visit talkpython.fm, choose friend of the show in the nav bar, and sign up.
Now, let me introduce Luciano.
Luciano Romalo is the author of Fluent Python.
Romalo was a web developer before the Netscape IPO in 1995 and switched from Perl to Java and finally to Python in 1998.
Since then, he's worked on some of the largest news portals in Brazil using Python.
He's taught Python web development in the Brazilian media, banking, and government sectors.
He's spoken multiple times at OSCON, PyCon, Python Brazil, FISL, and Rupy.
Romalo is a fellow at the Python Software Foundation and a co-founder at the Garoa Hacker Club, the first hackerspace in Brazil.
Finally, he's the managing partner at python.pro.br at Python Training Company.
Luciano, welcome to the show.
Thanks, Mike.
Thanks for having me.
Yeah, I'm really excited to talk to you about your new book, Fluent Python.
Yeah, I'm excited about it too.
I bet.
You've been working on it for a while.
Before we get into talking about your book, which is really an amazing book, I'll have more to say on that in a minute.
Thanks.
You're welcome.
Let's talk about how you got started in the programming and Python at all.
You know so much.
I can tell from your book.
But at some point, you had to start at the beginning, like we all do, right?
Where did you get started?
Okay.
Now, I'm 51 years old.
So when I was a teenager in Brazil, there were no microcomputers.
But I got a hand on a programmable calculator, a TA-58.
And I learned to program by programming it.
And actually, my first interesting program was a port of a game from the HP-25 calculator to the TI-59.
It was the lunar landing game that was famous.
Oh, that was a great game.
Yeah.
So that was my first significant program.
And then I was an exchange student in 81 in the US.
I lived in Little Harrisburg, Illinois, population 10,000.
And there I got – there were – in the library, in the school, there were a few Apple II computers that had just arrived when I arrived.
And nobody knew how to use them.
The teachers who were supposed to teach about them hadn't yet taken the course to do it.
So they were basically free for anyone to do whatever they wanted.
And I learned – I taught myself basic programming in them.
Anyway, so that's a long time.
And then I went through lots of languages after basic, Pascal.
And Pascal was one of the most important ones for me.
And then Delphi.
And then Visual Basic.
And I studied a little bit of small talk.
And then when the web started here in Brazil, again, we had a kind of a different situation because there was – all telecom companies in Brazil were state-owned at that time.
Later they were privatized, but they were state-owned in 94.
And so I was hired by a large publishing company here to start developing their strategy for online.
And I learned – I taught myself pro programming because everybody did everything on the web that was automated using Perl at the time.
Right?
Right.
And I loved Perl.
I thought it was awesome.
But I also found it – well, I'm saying I just said I love it.
But I loved it, but I also hated it at the same time because it was very powerful and quick.
But it was also full of traps.
And it was difficult to read afterwards and so on.
Then I tried Java and I probably was one of the first people in Brazil to do server-side Java because when Java was first released, Sun was trying to market it as a tool for client-side programming, right, with the applets and so on.
It took a while for them to realize that server-side was where Java was going to thrive.
But I didn't enjoy the verbosity of Java.
I liked the fact that it was really object-oriented, which Perl was not at the time.
But it was too verbose.
And then after a while, I went back to Perl again.
And Perl had acquired object-oriented features in around Perl 5.
And then something happened.
As the Perl community was discussing how to do things in a dynamic language, but also in an object-oriented way,
they kept repeating the sentence.
Here's how they do it in Python.
In Python, this is like that.
And that's how I first heard of Python.
It was discussions on the Perl mailing list about how to do things in an object-oriented way,
but in a language that was a scripting language, in a dynamic language.
So after reading mentions of Python a few times, I decided to go study it.
And then I read the tutorial, which was shorter at the time than it is now.
And I just fell in love immediately because for me, it had the best features of Python, of Java and Perl.
It was really object-oriented with an object-oriented standard library like Java and had exceptions and other things that I liked about Java,
but was not verbose.
So it was, you know, very concise and to the point and agile like Perl.
And so it was for me the combination of the best features of both languages.
And then I basically never looked back.
That's a great story.
I think we've all had those sorts of feelings about some of our first programming languages.
We love them because we really got into programming, but, you know, they're not necessarily the best.
So you have those words as well, right?
Exactly.
But Python's where you've sort of settled into.
I can tell you've been doing it for a long time from your book.
Yeah.
So I started doing it in 98.
That was when I found the tutorial that I mentioned.
And then I immediately pitched a Python solution to a client at the time for an online news site.
And then I discovered Zope, which was just then released as open source.
And I started using it like a couple weeks after it was released as open source.
And then a couple months later, we actually launched in Brazil a new site that was based on Zope.
And it was one of the first big Zope cases around the world.
Oh, that's excellent.
Yeah.
And so I owe a lot to Zope.
I don't use Zope anymore these days, but I owe a lot to it because it was because of Zope that I was able to deliver the kinds of products that the clients were looking for me to deliver, like content management systems.
And so I was able to get paid for writing Python pretty early, at least in the context of Brazil, since 98.
That's a great feeling, right?
Yeah.
You find this thing you love and, wow, people pay me to do it.
Exactly.
It's a good time to be a programmer indeed.
So let's talk a little bit about your book.
The title is Fluent Python.
And it's coming out under, being published by O'Reilly.
And it's coming out, I think, September 4th is what Amazon.com tells me anyway.
Is that right?
Yeah.
To be honest, I don't know exactly when the print book is going to come out because different pages that I look at give different dates.
I've seen August.
I've seen September.
And I've seen October all in the last two weeks.
So, yeah.
But soon, right?
Pretty soon.
Just about the same time that this podcast comes out, I think, should be the time that the book is released.
Wow.
That's excellent.
But let me say, the e-book is now complete in the final form.
So people who buy the e-book or who have bought it previously can now download the final version of, you know, first edition, first revision.
And it's also available from Amazon.com for the Kindle in the final form.
So we are only waiting for the print book at this time.
Right.
Okay.
Excellent.
Yeah.
I think having the electronic book works really well.
I was reading it on my Kindle and it, on my Kindle, paper white, and it was really nice.
You know, the code samples came through really well.
Like sometimes that doesn't work so well.
Wow.
That's cool.
Nice to know.
Yeah.
It came out really, really well.
And, you know, so I've only had the book for a few days.
So I've only been able to read maybe the first five chapters.
But my impression of the first five chapters, if it keeps going like this, I'm sure it does, is this book is a masterpiece.
It is really, really good.
Well, thank you very much.
I think it's going to go down as a classic book in the Python community.
Really.
Thank you very much.
Yeah.
I'm not just saying that because you're on the show.
But I was reading it and it's a little hard for me to put in words, I think, for people to really understand.
But it seemed like everything that you covered, and we'll talk a bit more about that.
But it seemed like everything you covered, I'm kind of like, I mostly know this.
Oh, wait.
There's this really cool piece of information or motivation that I was never really aware of.
And just underneath the surface of the knowledge that I do have.
Right.
And that was like all the time happening to me while I was reading your book.
And so I think it's a great contribution.
Thank you.
Yeah.
So let me read a quick quote right from the beginning to give people a sense of, I think, what you're going for with this book.
So in the introduction or one of the first chapters, you say, Python is an easy-to-learn, powerful programming language.
Those are the first words of the official Python tutorial.
That's true, but there's a catch.
Because the language is so easy to learn and put to use, many practicing Python programmers leverage only a fraction of its powerful features.
Does that kind of sum up the problem you're trying to solve with this book?
Exactly.
And that's why I called it Fluent Python.
You know, as somebody who is fluent in two languages, in Portuguese and English, and that knows how difficult it is to become fluent in a language,
because it's easy to become fluent in the language in your native language, right?
You grow with it, and that's basically people don't even notice.
But getting fluent in another language is hard.
And so I've been teaching Python to lots of people.
When I had a company, whenever we hired people, we never could hire people that knew Python because nobody knew Python at the time.
So we hired people who knew Java and then taught them Python.
But I also worked as a Python instructor, and that's what I do now these days.
So I realized that this thing that I say over there, that the language is easy to use, it's practical.
So people start solving real problems real fast.
But that means that sometimes they are already using it for several years and don't know why some things are the way they are.
And another thing that I say right after that in the second paragraph is that when you're learning a new language,
you look for things that are familiar to you.
Like, for instance, maybe this language, probably this language has a way to use a regular expression.
Let's see how that works.
But if there is something in the language that is not matched by something that you know from another language,
like, for instance, the concept of generators that many languages don't have,
then you're unlikely to go look for it, right?
Because you don't even know the thing exists.
Another simpler example than generators is like tuple unpacking.
It's just a nice synthetic sugar.
But if you've never seen that in a language, you won't look for it.
And maybe you're going to spend years working with Python without ever using it.
But it's a really nice thing to use because it makes code more readable, even safer in some ways.
Python tuple unpacking has this characteristic because it actually forces the interpreter to count the number of items.
So if there's one more or one less, an error will be raised.
So it's a very nice feature, but it's something that people who come from other languages may never use because they won't think about it.
Right.
If you came from something like C#, for example, that doesn't have this concept of tuple unpacking,
and so you just wouldn't even, you might not ever find it.
And that kind of gets at the broader issue or concept of Pythonic versus non-Pythonic code, right?
Yes.
It's pretty easy to come over to Python and learn it really quickly so that you can do the same thing that you do.
But it's not always the best, is it?
Some of your mental models don't really carry over so well.
Exactly.
Yeah.
It's very, it's, of course, it's a very elusive thing to define what is Pythonic.
I actually mentioned it several times in the book and tried to address it afterwards.
But basically, I just send people links to other people that I respect a lot in the Python community who have attempted to define it directly.
Right.
But it's like, it's about a good definition which doesn't really explain what is Pythonic is to say it's idiomatic Python, right?
Right.
But okay, so what is idiomatic Python?
Right?
It's hard to define.
Yeah.
I think your best bet is to show a bunch of people a bunch of examples, say, all of these things are Pythonic.
All of these things are not Pythonic because they carry over concepts that work well in other languages but are not the proper way to do them here.
And once you get enough experience of going, bad example, good example, then you kind of get this sense, like almost a smell for like, yeah, it seems like this is right.
It seems like that's not right.
But it's very hard to be very concrete.
Exactly.
Yeah.
I tried to do that in the book.
And actually, a decision that I made early on was to be as Pythonic as I could in the program examples, even when being Pythonic might not have provided the clearest source code from something that's not familiar with the language.
You know?
Like, for instance, right in the first example in the book, I use named tuple, right?
Yep.
And then I give it just a couple sentences to explain.
It's probably not enough if the person has never seen it, but it's actually something useful that I start using all over the book.
And if that picks up the person's curiosity, then the person can go and look for it.
So this is what I decided.
Like, for instance, before I actually have a chapter that formally discusses generated expressions, I use them in the book whenever it was natural to do so.
Even before I actually cover it.
Because of what I just said.
You know, I wanted to write idiomatic Python whenever I could, even if that made the...
Because the thing is, when you're speaking to a native speaker of English, for example, the person won't dumb down his or her speech for you, right?
That's right.
And that's cool.
Sometimes maybe you don't understand everything, but you're catching, you know, there's something new about the way this person is expressing herself.
And then you're going to try and find out what that means.
That's, you know, if you always talk to people that spoke English, easy English, you would only learn easy English and not real English, fluent English.
You wouldn't get that chance to grow into a fluent speaker, kind of like you said.
So your example with the name tuple kind of hits on the point that I was talking about.
Like, I've used name tuples.
I'm familiar with them.
I think they're great.
But, you know, you go a little bit deeper and you're like, hey, it's really cool to use a name tuple because the actual dictionary that stores the attributes is stored in the class object, which is a singleton in the runtime.
Not in the individual instances.
So storage is actually cheaper than regular custom classes.
Yes.
So if all you want to have is just a bunch of pieces of data that have names in an object, but not functionality, maybe you should use these name tuples.
This episode is brought to you by Hired.
Hired is a two-sided, curated marketplace that connects the world's knowledge workers to the best opportunities.
Each offer you receive has salary and equity presented right up front, and you can view the offers to accept or reject them before you even talk to the company.
Typically, candidates receive five or more offers in just the first week, and there are no obligations.
Ever.
Sounds pretty awesome, doesn't it?
Well, did I mention there's a signing bonus?
Everyone who accepts a job from Hired gets a $2,000 signing bonus, and as Talk Python listeners, it gets way sweeter.
Use the link Hired.com slash Talk Python to me, and Hired will double the signing bonus to $4,000.
Opportunities knocking.
Visit Hired.com slash Talk Python to me and answer the call.
Exactly.
Yeah.
And another thing.
They are, because they are inexpensive, you can use it.
And they are inexpensive and they are completely compatible with tuples, right?
You can unpack them, you can iterate over the items and so on.
So, for instance, whenever you need to return more than one value from a function, I recommend you return a name tuple.
Because it will make, for instance, understanding what the function does easier, because there's going to be the definition of this name tuple.
If the person is looking at the result of the function in the console or in the debugger, the person is going to actually see the names of the parts of the tuple that the function is returning.
So, this is a recommendation.
Like, for instance, if you're going to return more than one value from a function, usually people do it with a tuple, and that's fine.
But with the name tuple is even better.
And it's cheap, like you said, because of the way it's implemented.
It doesn't require more memory.
Yeah.
You don't have to store all the keys, copies of the keys for every instance, right?
Like you would with regular classes or objects.
Yeah.
And, of course, when those come back, if you're unsure what's coming back from that method, you could print it out and you get a nice listing of actually not just what's in there, but the meaning of them by the name.
Exactly.
Or if you're in a debugger like PyCharm, you could probably hover over it and actually see it pop up in the watch window.
Yeah, it's excellent.
Yeah.
So, one thing that you said you used in your book is something called Doctest to check the code in the console listings.
Can you talk about that a little bit?
Yeah.
So, that's something that I think was created by the people in the ZOOP community.
And it's not...
So, in the ZOOP community, this was always very big.
So, the main idea of Doctest is to make sure that whatever code snippets appear in documentation, particularly listings of console sessions demonstrating stuff, that those actually match the behavior of the program at that time.
So, this was the starting point for Doctest.
In the ZOOP community, which is still active, there's a lot of development going on still in ZOOP.
There's a lot of also files that are testing files that are not strictly documentation that are written in the Doctest format.
Because it's really easy to...
I find it excellent to...
When I have to design a new API.
Because I...
It's sort of a BDD thing, you know?
You start typing those fake console sessions where you're thinking how it would feel to interact with this API.
And then the result would look like that and so on.
And then you...
It's really good to do TDD.
Because you write a couple of stanzas of Doctest and then you implement the code that makes it pass and so on and on and on.
You know, the whole idea of trying to envision what your API looks like from the outside and then implement it generates much cleaner APIs in the end.
And this is, you know, one flavor of that, right?
That's cool.
Yeah.
One thing, though, I have to say about Doctest is that after a while you'll realize there are some limitations to it.
And even recently, like last week, I was...
I had to come up with a difficult solution to an algorithmic problem.
And I started implementing some tests using Doctests.
But then, for instance, Doctest doesn't let you easily run just one part of the test.
It runs everything from top to down.
And sometimes when you're debugging, it's useful to be able to run just a specific part.
Anyway, the unit testing frameworks, not only unit tests, but py tests, which is my favorite, are much more powerful than Doctests.
And they can actually also run Doctests.
So there is a way to integrate them.
So you can have...
I think the best idea these days is to really use Doctests just for the documentation.
And just the straightforward cases, not corner cases, not weird outcomes, not testing whether an exception is raised or not.
Because although all of that can be done in Doctests, in the end, it becomes difficult to maintain the tests.
Right.
Maybe it's better done in pytest, something like that.
Exactly.
Yeah.
I use Py.Test.
I prefer it much better than unit tests because I think unit tests has a very strong Java flavor of forcing you to do everything inside classes.
Mm-hmm.
And I much prefer the syntax that pytest introduced and the nodes also supports.
But I prefer Py.Test of having tests as functions.
And you can create classes if you want, but you can also have module level things.
I prefer the syntax.
Yeah, cool.
So one of the very first things that you talk about in your book is the Python data model.
And you talk about it's sort of the foundation for making your own classes fit this Pythonic programming model.
And you have a quote in there.
It's something like the – you know, talking about this data model or just learning about it is the tip of the iceberg.
So the iceberg is called the Python data model, and it describes the API that you can use to make your own objects play well with the most idiomatic language features.
Yes.
Mm-hmm.
Do you think people are – people who are sort of come to Python from other languages, you know, ones that add functionality to their classes very much by overriding virtual methods and those kinds of things sort of miss out on some of the Python data model, like under-under init or, you know, the iter or str methods, things like that?
Yeah, for instance, this is something that happened to me many years ago when I developed the French deck, the card deck example that I use in that chapter.
So many years ago when I had the idea of implementing that, so I was – the idea was to show how easy it was to create a new class that behaved like a sequence, right?
So you implement dunder lan and you implement dunder get item and basically you are done.
But then something really interesting happened because I was implementing – the idea was to implement a card deck, right?
So what is an obvious thing you want to do with a card deck is to shuffle it, right?
Right.
So the first time that I created this example, I actually had a method called shuffle, which was not a special method.
It was not dunder shuffle.
It was just shuffle, right?
So the idea was – so you have this card deck and you can look at the cards and you can call the shuffle method and see the cards shuffle.
Okay.
But then a few weeks after that, I realized that when I looked back at the example given a class, I said, wait, wait a minute.
There is already a shuffle function in the random module that shuffles any mutable sequence that you give it.
So it actually doesn't make sense to implement the shuffle.
If the whole point of my exercise was to show how easy it was to create a sequence, even if the sequence represented a card deck, a very specific domain, specific thing, it didn't make sense for me to implement my own shuffle method.
Because there was already a shuffle method and it is designed to work with mutable sequences.
Right.
And it's already tested, probably optimized, all that kind of stuff, right?
Exactly.
So then that was an insight for me of an advantage of being Pythonic.
It's the fact that when you are Pythonic, your objects suddenly become more compatible with things that are already out there in the standard library and in other packages that you can download from PyPI.
Yeah, I think this is a lesson that people need to learn.
Because, for instance, I don't know about C#.
I studied Java a lot for a while.
And even today, sometimes I spend some time every year I try to sit down and read something about Java.
Because I get a lot of clients in my course that studied Java before and it's useful to make analogies.
But, for instance, a big advantage of Python over Java is the fact that we have these operators that are more generic.
Like, for instance, the square bracket operator, which is the operator to get an item or to set an item, right?
And they don't have that in Java.
That operator in Java is a magical thing that only works with the primitive arrays.
Anything else, you have to use some other, you know, you have to use method syntax.
Also, these days I'm studying Go, the Go language, and I really like it very much.
But one of the things that I most dislike about it is the fact that it follows this Java philosophy of having some built-in data structures that are magical.
And you cannot create your own data structures that emulate them precisely.
Like, for instance, in Go, there's a way to...
You can iterate over some primitive types, like maps and arrays and slices.
But you cannot create your own type that is iterable using the for-range construct of the language.
Right.
That's too bad.
Unlike the for-in-loop in Python, which is totally accessible.
Yeah, so I think Java, I think Python is actually better than most languages in this regard, of enabling you to create structures that behave exactly like the most fundamental data structures in the language.
And the way to accomplish that is through the data model.
So, I think it's very nice to have that documented and exposed, and I wanted to give it more visibility.
So, that's why I started the first chapter with that.
Even if in the following chapters, my strategy then is to say, okay, but let's look at what is already implemented in Python.
Because I didn't want people to go out and reimplementing new sequence types when maybe they don't even leverage everything that the built-in sequence types can offer.
Right?
Right.
I think that's a good point.
People coming from other languages, they don't necessarily know what's available.
So, they'll find themselves reimplementing stuff.
A really simple example would be I would like to randomly get an item out of a list.
So, I might import the random module, get a random index based on the length, and then go index it out.
Or you could just do random.choice.
Oh, I didn't know random.choice exists.
Exactly.
Yeah.
So, one thing that you talk about around the Python data model is the len method.
Mm-hmm.
Yeah.
And, you know, being such an object-oriented language, I always felt that it should be, you know, collection.len or length or something like that, maybe even as a property.
And this sort of special function on the outside of the classes seemed a little bit odd.
But you had a good conversation around that in there.
You want to elaborate on that?
Yeah.
Sure.
So, that is also something that bothered me for a while.
Of course, you get used to it because it's really easy to get used to it and it's really easy to type.
It's actually one of the arguments that Guido uses to defend that decision is that it's easier to type than having a dot.
You know, if it was a method call, you would have to write, like, you know, x.len open close paren.
Right?
So, there's one dot extra there.
And it's also something.
And here's another thing that's funny.
Because I think it's of the human nature.
When people come to learn a new language, sometimes they are not pleased.
Sometimes their boss told them to learn it.
Right?
And then, some people try to resist by pointing out, you know, things that they don't like or things that they think are inconsistent.
And bugs, although bugs are extremely difficult for a beginner to find in Python.
I've never seen a beginner find a bug in Python.
Every time a beginner thinks…
I've seen them write bugs.
Yeah, yeah.
Sure.
Yeah.
But most of the time, in my life, every time I've seen a beginner complain about a Python bug in a mailing list, it was invariably because the person didn't understand what exactly was going on.
That's right.
It was not a real bug.
But anyway, here's about inconsistencies.
So, they say, ah, this is inconsistent because it should be spelled as a method.
Okay.
Now, let's think about how this problem is solved in Java.
In Java, there's actually an inconsistency because there is the… in the array type, there is like a… a property, as it were.
It's actually a field, like a public field that you read.
So, you don't… you just write myarray.length without parentheses, and that's how you get the length of the array.
Because Java is just basically giving you the value that's… it's internally stored in a structure that represents the array.
So, that's very cheap, and that's how they do it.
And it's important to be cheap because it's a very common operation.
Then, for other types that don't have this structure, there's a method called length.
But also, in the Java API, there are other classes that could perfectly have methods named length, but have methods named size.
Size or count or something, yeah.
Yeah.
So, there's at least three different ways that are common in Java code to do the same thing.
And in Python, we have only one way.
It's the length of the thing, called as a function.
And so, first of all, it's more consistent.
The second thing is, it's pragmatic.
Because the way it works is, if you say length of X, and X is a built-in type, this built-in type, if the built-in type has many elements,
there's actually a struct, I forgot the name, but it's spelled out in the book,
there's actually a C struct that represents the type, and it has a field that has the count of the numbers, of the number of items.
So, that's the same thing that Java does, except that it doesn't expose a special field, but uses the length function.
So, the length function, the implementation of the length function in the Python interpreter does that.
It just goes to look at, if there is a built-in type, and it's a multi-valued built-in type,
then return the value of this field in the struct.
So, that's very cheap, and it's actually faster than doing the resolution of an attribute, right?
So, because if you had to write X dot length, this dot requires some advanced machinery in Python,
because of the dynamic nature of Python.
The price we pay for all this dynamic behavior is that the dot operator is kind of expensive.
Right.
Basically, a dictionary lookup, and then the function calls themselves are also kind of expensive.
Exactly.
Yeah, and it's more expensive than a dictionary lookup, because there's all that machinery that I explain later in the book.
Basically, in the last part of the book, the metaprogramming part, is where I explain actually how descriptors work.
And descriptors, the infrastructure below properties, but also below another thing that's really fundamental that everybody uses in Python,
which are methods.
Because what makes a method behave as a method, as an instance method, as a bound method, or as an unbound method,
has to do with the way the descriptor mechanism resolves the dot operator.
So, it's an expensive thing.
So, by making it be written as len paren X, close paren, the interpreter can resolve this much faster.
And then, if the structure is not a built-in structure, then the interpreter falls back to looking up,
and then there's the cost of the attribute lookup, but it will look up the under len method.
So, I think this is actually very elegant, because in the end, the user interface is always the same.
It's always len of X.
But it allows, but it gives us, creators of APIs, a way to provide a consistent interface.
An interface that's consistent with the built-in method, with the built-in types,
while at the same time ensuring that the built-in types have the fastest possible performance for doing this operation,
which is crucial, right?
It's often something done in loops, right?
And you want to optimize everything that's done in a loop.
So, getting the lane of something is important to be fast.
This episode is brought to you by Codeship.
Codeship has launched organizations, create teams, set permissions for specific team members,
and improve collaboration in your continuous delivery workflow.
Maintain centralized control over your organization's projects and teams with Codeship's new organizations plan.
And, as Talk Python listeners, you can save 20% off any premium plan for the next three months.
Just use the code TALKPYTHON, all caps, no spaces.
Check them out at CodeChip.com and tell them thanks for supporting the show on Twitter where they're at, CodeChip.
Yeah, that's excellent.
And you talked a lot about the internals, which I think can be kind of tricky to discover in Python.
The previous show that I recorded but is not yet released is with Philip Guao, all about this university class he did and then put online on the internals of Cpython.
I think he did a 10-hour series on like walking through Cpython.
And I just –
I want to watch that.
Yeah, I just want to recommend to listeners like if that kind of stuff that we were just talking about sounds a little like, I'm not really sure where this is going.
Like watch Philip's videos, right?
Maybe I'll put them in the links here because it'll all of a sudden click together and be like, oh, I see, exactly.
And you talk a little bit about the same kinds of things that he does by importing the disassembly module, the dis module, and disassembling functions and actually looking at what it is you're talking about to see what's really happening.
Yeah.
The thing is I'm not – to be honest, I'm not an authority on the internals of Python.
But sometimes I was curious about some things and I went to look for it.
But I also want to tell your listeners that the book is not about that kind of thing.
It has some moments that has these kinds of look into, you know, under the covers.
But most of the time it's not like that.
It's something that I enjoy, but I also found it challenging to read the source code for Cpython.
So I would love to see Python developing – here's a wish that I have.
I would love to see some time in the future, perhaps, a Python interpreter written in Go.
Because Go is much more readable than C.
It's simpler also.
The syntax is simpler.
But it has the problem of concurrency resolved in a very good way.
And it would be awesome to see a Python interpreter written in Go.
It would make it also much easier to understand what's going on.
Yeah.
How about something – a future Python that the runtime parts are easier to read because it's Go.
And it doesn't have the global interpreter lock.
Exactly.
Maybe because you can somehow resolve that with simpler threading models in Go.
Yeah.
It's important to – since you mentioned the global interpreter lock, you know, the JITON and the Iron Python implementations of Python don't have it.
Because they already can count on an underlying implementation of objects and threads that is thread safe.
So it's something that happens with CPython and also with PyPI.
But Iron Python and JITON don't have the global interpreter lock.
Oh, that's interesting.
Yeah.
So basically there's two cases of this is a possible thing.
It's just we're not there yet, right?
Yeah.
No.
Not at all.
Yeah.
Let's move on maybe to like the array section and the sequences.
You did some really interesting things there, a lot of which was kind of familiar to me like list comprehensions and generator expressions.
Those are –
Yeah.
You know, if you've been doing Python for a while, it'll make a lot of sense.
But then you also have like little gems in there.
Like one of them that really stuck with me is said basically if you implement the iter method, you can automatically do iteration.
But if the collection you have doesn't have a dunder contains, then any sort of is check will actually be a sequential scan.
An in check, not is.
Yeah.
Oh, sorry.
Yes, of course.
Yes, an in check.
So if you say object in sequence and it does – it implements iteration but not the contains, all of a sudden – it can still answer the question, but it's a huge performance problem potentially.
Yeah.
And that's because if you look on – right at the second page of chapter two, there's a diagram of the – of the mutable sequence and sequence ABCs and then container iterable and sized.
And so those ABCs pretty much define the standard API for mutable sequences.
And in the sequence ABC, contains is a concrete method.
So even though that's an abstract class, the only abstract method in it is dunder get item.
But dunder contains is already implemented.
And the way it's implemented is by just using iteration.
Yeah.
This is one thing that I – that – one thing that makes me really like Python is the fact that as a teacher, I found it easier to explain over the years.
Although it has also grown more features that take a lot of time to explain.
But for a certain specific set of features, for instance, if you're talking about sequences, these days it's easier to talk about sequences, I think, than it was before.
Because although there's more content, you have to talk about comprehensions and so on.
The basic concept of a sequence was not very well defined earlier in the language because there were no ABCs.
In the documentation, you read about, oh, so this expects a sequence and that's – but there was no strict definition of what a sequence was.
After a while –
It's like a vague concept of, well, a sequence is kind of these – yeah, what does that actually mean precisely?
Exactly.
Yeah, exactly.
So people who were comfortable with the language intuitively knew what a sequence was.
People who knew about the implementation of the language in C knew exactly what a sequence was, but in a way that was very complicated to convey.
And now with the introduction with the ABCs, it's easier because you can say, no, so here is what a sequence is.
A sequence has to have a way of – it's a container, an iterable-sized container.
So it has to be a way to – there's got to be a way to get the lane, to iterate over it and to determine whether something is or is not in it.
And then it has to have a – so there's a definition that people can look up in the documentation.
And in the book, I drew some UML diagrams, which I also think it's – they make it easier to see the relationship between those ABCs because in the documentation, there is no diagram.
So it's all –
Yeah, those pictures are really nice.
I like them.
Yeah.
So one thing I thought was really helpful, and I think probably I learned a decent amount from it, was when you're talking about this whole thing on data structures, you have this part that's called – that you entitled, you know, when a list is not the answer.
Uh-huh.
Yeah.
So, like, you can almost always use a list for everything, and it does have a, you know, effectively a pop method and, you know, push is just append and things like that, right?
So – but it's maybe not the best choice for that.
So you talk about things like arrays.
Yeah, exactly.
And the DQ class or sequence for double-ended queues, and I thought that was really interesting.
So maybe – do you want to just talk quickly about your message there?
Yeah, so that was the idea, because it's something that I've always – not always, but I've already caught myself doing in the past, was to use a list when I should be using an array.
An array is easy – it was really easy to use, and it's much more efficient in terms of memory, and also in terms of execution, because it's a packed data structure where one number is right after the other.
Yeah, it might be worth just, like, expanding on that just a little bit, you know, because in normal Python, even a number, if I say x equals 7, that allocates under, you know, down in the runtime, like a full-on object, which has all sorts of additional information, and it's a pointer out to that thing.
Exactly.
Whereas array allocates, you know, literally four bytes for ints or whatever in a huge long array, right?
Exactly.
That's because – yeah, exactly.
That's why when you create a – I think the first stumbling block to create an array is that you have to look up in the documentation, because when you create an array, you have to write this type code that tells the array what are the size of the numbers that are going to – the size and the type of the numbers that are going to be there, because it can also have an array of floats, right?
So you have to look up in the documentation to remember what are the letters that you use to specify the numeric type that goes into the array.
But then, when you do that, you have to look up in the array.
But then, when you do that, you're all set.
One thing that I try to do, like, for instance, in the discussion about arrays, there is that, and there's other places, is to compare – I wrote those tables with, like, all the methods and operations of a list and array.
And so you can just briefly look and realize what the difference is.
Oh, here's something that I can do with an array that I cannot do with a list or vice versa, right?
So that's why I decided to add those tables, because there's a lot of functionality, and I wanted to pretty much graphically show people that they're almost the same.
But there are some differences, and when you look at the tables, it's easy to tell really quickly what the differences are.
Yeah, it was really helpful for me, so I appreciate that you added that.
That's cool.
Mm-hmm.
So we're kind of coming up towards the end of the show.
Maybe you want to touch on just a couple more points that you think are important parts of the book that maybe I haven't gotten to.
Yeah.
So, basically, the book is divided in six parts, right?
We talked about the part one, which is just one chapter where I present the data model in a very introductory way.
But the idea of the data model and demonstrate how useful it is with the card deck example, and then there's a vector class with operators.
Anyway, and then the second part is data structures, the part that we were talking about.
That part has a chapter.
I think the longest chapters in the book are there.
The one about all the sequence types, the one about dictionaries and sets, and the one about texts versus bytes.
About the text versus bytes chapter, I was very happy because one of my favorite programming book authors, Bruce Echel, who wrote the famous Thinking in Java book.
These days, he's doing some Scala writing, but also he loves Python, and he was reading my book, and he said that my chapter about text versus bytes, which covers Unicode, what Unicode means, and all the different ways of converting Unicode from and to bytes.
He thought they were very useful for him.
Anyway, so this is the data structures part of the book.
Then part three is about functions as objects.
I decided to introduce that before classes, also because I think it's a Pythonic way of thinking.
We start by coding stuff in functions, and we usually only create classes when realized that just plain functions won't do.
Right.
Maybe some data needs to come along with those functions or something, right?
Exactly, exactly.
If you are trained in Java, you are trained to do everything in classes because that's the only way to do it.
So that's why I decided in the book to give a total explanation of functions and design patterns using functions,
how you can simplify some design patterns by getting rid of classes and just using functions.
And then I wrap up with decorators and closures.
And then part four is about object-oriented programming.
It starts with an explanation of how references work and how the whole thing about mutability works.
And then I give some examples of implementing what I call PyTonic objects,
which are first a vector class, a 2D vector class, and then a two-dimensional vector class,
and then a multi-dimensional vector class.
And those examples are excuses to show the use of many special methods in practice.
I thought your comment on how you don't like to call the Dunder methods magic methods,
but special methods was interesting.
You're like, there's nothing magic about these.
This is how you do it.
Exactly, exactly, exactly.
And the thing is, when you call something magical, you're saying,
okay, so this is not for mere mortals.
But that's exactly the opposite.
Like I was saying before about the criticism that I was criticizing Java and Go
because of the fact that it has some data structures that are magical
in the sense that you cannot really emulate them in your own code.
And so, exactly.
Anyway, so this is the part of the book where I explain how to do that.
And also, there's some discussions about the use of interfaces.
And something that's a first, and I'm very proud that Alex Martelli,
who was one of the reviewers of the book, one of the tech reviewers of the book,
wrote an essay introducing, after he introduced duck typing,
at least the Wikipedia credits him with the creation of,
or at least with the first use of the expression duck typing
in the context of discussing programming languages.
Alex Martelli now invented the concept of goose typing.
Goose typing.
Okay.
What is goose typing?
So, goose typing is a variation of duck typing where you have some type hints,
this new feature of Python 3.5.
But it doesn't require, actually, the new feature, the type hints.
The idea is to use ABCs as a way to specify types.
But here's the thing.
Python uses ABCs in a way that's very influenced by its origins
as a dynamic-typed language with duck typing.
And the main reason for that is that it allows you to actually create a class
that does not inherit from an ABC,
but then you register it as a virtual subclass of that ABC.
So, you're actually promising.
I do implement that thing.
Although I do not inherit from it, I do implement that.
And you can actually do that after the fact, for instance.
Maybe because it's a third-party library that implements something that you look at it
and say, hey, this actually looks like a sequence,
and it would be useful in my code to be able to ask if that's a sequence
and to have the answer yes.
So, in your own code, you can affirm that this other data structure
that somebody else did is, in fact, a virtual subclass of a sequence.
So, this is a facility that Python has with the way the ABCs were implemented.
And there's this register method of ABCs
that allow you to register some other type as a virtual subtype of this type.
That's cool.
Yeah.
So, that's the idea of goose typing.
It's a different kind of waterfall,
but it's related to ducks in some way.
Yes.
Yeah.
Nice.
And then there is a chapter about inheritance
where I discuss the multiple inheritance,
which, again, is something that a lot of people don't have contact with
because many OO languages don't implement that.
And then there's the chapter about control flow.
This was the hardest chapter for me to do.
And there was a lot because, basically, because the AsyncIO was very new,
still very new.
Yeah.
You have a lot of stuff on, basically, parallelism or async here.
You've got concurrency with AsyncIO, concurrency with futures.
What's the story with the futures part?
Yeah.
So, the thing is, there is a module called concurrent futures, right?
And this module actually works with threads and processes under the covers.
But it was the first module in the first package in the Python standard library
that implemented this idea of futures,
which is something that is gaining a lot of currency in other languages as well.
So, futures are basically objects that represent a pending computation.
So, the idea is that when you submit to some concurrent API a task to be done,
usually you submit, please run this function, right?
So, the API immediately and in a non-blocking way returns to you a future
that represents that pending computation.
And then you can query this future to know whether the thing that you asked to be done
is actually done or not.
And when it's done, you can actually get the results from the future as well.
And another thing that the future does is,
that is extremely useful whenever you are doing async work or threaded work,
that it encapsulates some exception that was raised when the system was running that function that you asked it to run.
And this is really important because what happens is,
when you're running code asynchronously and there's an exception happens,
it's happening in another context, right?
So, how do you catch it?
And it's really interesting.
The way it works is, the future object catches it and stores it for you.
And then later, when you actually go look at the future object,
and for instance, if you request the result from the future,
if instead of a result, an exception was raised,
the exception is raised at this point in your program.
So, it teleports, in a way, the exception that happened in this other context that you have,
where you have no control,
to a context where you actually either, you know,
you want to look at the result of the computation,
but actually there was an exception,
and this is where the exception is raised,
and you get to handle it.
Yeah, that's excellent.
Because normally you think of the exception as going up the call stack.
Yeah, exactly.
Until somebody catches it.
But on the other thread that you didn't start or manage, right,
that's not what you need.
Exactly.
Cool.
Yeah.
Awesome.
And then the last section you have is on metaprogramming, right?
Exactly.
Yeah.
So, the metaprogramming part is about how attributes actually work in Python.
So, I start with some simple examples using the dundergetutter special method,
for example, that allows you to emulate like a virtual attribute.
And I use it, I have a real data stream from OSCON last year that had all the talks.
So, it had a few thousand records in JSON format.
And I use, I implement a few classes to make it easy to navigate through this OSCON data.
And then, what else?
Then I talk about properties.
And then I go to, the next chapter is about descriptors, which is the infrastructure for properties.
And then I developed an example that actually evolved from a talk that I gave at PyCon in 2013 in Santa Clara.
It was called encapsulation with descriptors, the talk.
But in the chapter, I can spend much more than 45 minutes with that.
Of course.
Or 30 minutes, actually, it was.
Anyway.
And the last chapter is about class metaprogramming.
And I didn't call it metaclasses, because there's an area.
Although metaclasses is the most famous way of doing metaprogramming with classes in Python and other languages that allow it.
We also, we now have an easier way of doing metaprogramming with classes, which is using class decorators.
So, then I show some examples with that and a real metaclass.
And that wraps up the book.
Yeah, that's really cool.
There's a bunch of stuff that I'm looking forward to digging into if I have a few more days.
You know, especially the concurrency looks really interesting.
So, yeah, congratulations on your book.
It's very well done, and people are going to get a lot out of it.
Thanks a lot.
Let me just mention one thing that I'm proud of in the concurrency part of the book, and actually the control flow part.
In the cool routines chapter, I wanted to show people cool routines used in an interesting way, which was not linked to asynchronous programming, which is the main use case for them these days.
And so, I decided to implement this discrete event simulation of taxi cabs.
And so, this is something that, an example that I'm proud of, that I came up with this example that shows and gives you, when you run the simulation, if you actually run the script, it gives you an intuition of how actually you can use cool routines to manage many things happening at the same time.
In the example, there are cab trips, different cabs that are on the street catching passengers and dropping off passengers.
And so, but it doesn't involve an event loop, but it's a simulation.
And so, there's a very simple scheduler implemented in about 10 lines of Python and makes all those cabs run.
And actually, the cabs are implemented as co-routines.
That sounds really cool.
Definitely want to check that out.
So, before I let you go, there's two questions I always ask my guests on the way out the door.
First one is, what's your favorite code editor?
I use Sublime Text.
Sublime.
That's a good one.
Yeah.
Although, I have a partner in my training company that uses PyCharm.
And sometimes I get, I think I'm moving to PyCharm.
You get sucked in there.
Yeah.
Yeah, exactly.
I'm not an IDE person.
Maybe someday I will be, but now I prefer simpler things and I'm very happy with Sublime Text.
Yeah, excellent.
And the other question is, what's your favorite PyPI package?
You know, there's all these different things out there, 60,000 plus, whatever.
Yeah.
There's just so much to raise people's awareness of.
So, what's your top list?
Well, requests is probably a common answer.
That's one of my favorites.
Other people have maybe given you this answer.
But I think it's really cool.
And I actually use it in the book.
It's one of the few external libraries that I use, even though there is a library that does pretty much the same in the standard library.
And I use it because it's much simpler, but also because it runs the same on Python 2 and Python 3.
But our HTTP client functionality in the standard library has always been not very good.
And because it's not been very good, it's been changed a lot in Python 3 without getting much better, but enough to become incompatible.
So, I think requests, if you want to write an HTTP client, is something that you really have to go for because then your code will be easier, nicer, and it will run in Python 2 and Python 3 at the same time.
Yeah.
The only thing that I wish requests had, and it doesn't, is support for asynchronous requests.
One of the things that you learn in my book is that you can actually do very effective network code in Python, despite the GIL, with threads.
Because of the fact that every single function in the standard library of Python that does blocking I.O. releases the GIL.
So, if you test it, if you run it, you will see it.
Actually, you know, except in very extreme cases, the performance of threaded applications and asynchronous applications in Python is pretty much the same.
So, you can use requests with threads for doing very fast HTTP clients.
Yeah, that's great.
Because most of you are blocked waiting on the network anyway, right?
Exactly.
Cool.
Yeah, we had Kenneth Wright on the show, the sixth episode, and we talked a lot about requests.
That was very cool.
Yeah.
I'm very, I was very glad.
I think Kenneth, I don't know, Kenneth gave some manifestation that was positive about my book on Twitter.
That maybe he favored somebody else's tweet that was positive about my book.
But I was very proud of that because he's really an example of a guy who can do things in a very Pythonic way.
If you want to learn what Pythonic is, study Kenneth's code.
Yeah, he's very good at creating APIs.
Yeah.
Mm-hmm.
All right.
Any final shout-outs or call to actions before we go?
People should go read your book.
They should go check out your book, right?
Yeah, sure.
Yeah, it was a huge investment for me.
I don't know if most of your readers know, but it's pretty impossible to make a living writing books, right?
It's sort of like how to make a living playing guitar.
Yes.
There's about very few people in the world that do it, that manage that.
Anyway, so I have to recover the investment in time that was huge.
I spent 18 months writing this book.
And the second half of that time was full-time doing it because my editor started complaining that it was, you know, I get, I was not feeling my...
You weren't on the deadline.
I was not in the schedule, yes.
So there was a couple of postponements, but then she noticed that I was really writing a lot.
The book grew.
It started as a project for a 300 to 400 pages book.
But I'm really happy with the result.
I'm really proud.
And I'm really happy with the chance that I had to work with Megan Blanchett, my editor, O'Reilly.
She was awesome.
And the support that I had from the technical editors, Alex Martelli, Anna Ravenscroft, Leonardo Rochael, and Leonard Regebru, and Victor Steiner, who was a special guest tech editor for the AsyncIO chapter.
They were awesome.
And it's really been a great experience.
And I'm really happy to see how people are enjoying the book.
Yeah.
It's quite an investment, but hopefully it pays off for you because it's definitely good work.
Yes.
Thanks a lot.
Yeah, you're welcome.
Luciano, thanks for being on the show.
Really appreciate it.
Yeah.
Thank you very much, Mike.
You bet.
Bye.
This has been another episode of Talk Python to Me.
Today's guest was Luciano Romalo, and this episode has been sponsored by Hired and Cochip.
Thank you guys for supporting the show.
Hired wants to help you find your next big thing.
Visit Hired.com slash Talk Python to Me to get five or more offers with salary and equity presented right up front and a special listener signing bonus of $4,000.
Cochip wants you to always keep shipping.
Check them out at Cochip.com and thank them on Twitter via at Cochip.
Don't forget the discount code for listeners.
It's easy.
Talk Python.
All caps.
No spaces.
You can find the links from today's show at talkpython.fm/episodes slash show slash 24.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes and direct RSS feeds in the footer of the website.
Our theme music is Developers, Developers, Developers by Corey Smith, who goes by Smix.
You can hear the entire song at talkpython.fm/home slash music.
This is your host, Michael Kennedy.
Thanks for listening.
It's Mix.
Take us out of here.
He's dating with my voice.
There's no norm that I can feel within.
Haven't been sleeping.
I've been using lots of rest.
I'll pass the mic back to who rocked it best.
Thank you.