3 Unique Python Features You NEED To Know
By Tech With Tim
Summary
## Key takeaways - **Python's Match Statement: Beyond Simple Switches**: Python's match statement, available since version 3.10, offers structural pattern matching that goes beyond simple value comparisons, allowing for complex data structure and type matching, simplifying code that would otherwise require extensive nested if-else statements. [00:30], [02:04] - **Dataclasses: Reduce Boilerplate for Data Objects**: Dataclasses significantly reduce the amount of boilerplate code needed for data-holding objects by automatically generating methods like __init__, __repr__, and __eq__, making code cleaner and more maintainable. [04:38], [05:44] - **Immutable Dataclasses for Safer Data**: By enabling the 'frozen' option when using the @dataclass decorator, you can create immutable data objects in Python, preventing accidental modification of their values after creation and enhancing data integrity. [06:42], [07:56] - **Positional-Only Args: Robust API Design**: Using a forward slash '/' in function definitions enforces positional-only arguments, preventing callers from using keyword arguments. This is crucial for API design, allowing parameter names to be refactored without breaking existing code. [10:10], [11:30] - **Keyword-Only Args: Clarity and Future-Proofing**: Arguments placed after an asterisk '*' in a function definition must be passed as keyword arguments. This improves code readability by making parameter usage explicit and allows for future renaming of parameters without breaking compatibility. [13:19], [11:53]
Topics Covered
- Python's 'match' statement: Beyond basic switches
- Python's 'match' statement: Unlocking complex pattern matching
- Data classes: Eliminating boilerplate for Python objects
- Slash and asterisk: Controlling Python function argument passing
- Keyword-only arguments: Enhancing API robustness and future-proofing
Full Transcript
Python is definitely an interesting
language that has many unique features.
However, many of these features are
never actually used out in the wild
because people simply don't know they
exist. So, in this video, I'm going to
go over some more modern and relatively
new Python features that I rarely see
used that I think are interesting and
that you should definitely know about.
They're not all in the most recent
version of Python, but they're things
that are in modern Python that I think
are worth knowing. With that said, let's
dive in. Now, the first feature I have
on my list here is called the match
statement. Now, it's also referred to as
structural pattern matching. Has a few
different names, and it was released in
Python version 3.10. Now, you've likely
seen this before, but I doubt that
you've actually used it in your code.
And when I review Python code, many
people don't actually seem to use this.
Okay, so what is the match statement?
Well, the match statement when used
simply works exactly like a switch
statement in various other programming
languages. For example, let's just move
this down here. You can have a look at
this code right here. You see, we have
some inner function. This function has a
match statement inside of it. And all
we're doing is we're trying to match the
status to one of these various cases
that we have. So we have a case for
success. That simply means if status is
equal to success, go ahead and do this.
We have a case for error means same
thing. If it's error, you know, go ahead
and do this. Pending do this. And then
we have a default case. A default case
is kind of like an else statement or
default if you're familiar with a switch
statement where if the status doesn't
match any of these, then we'll go ahead
into this default case. The default case
isn't required. We don't have to have
it. Uh but in this case, we do where we
just put the default case to handle
anything else. Okay. So if we were to
run this function here, you can see that
we can kind of go through this match
statement and we can process all of
these different values that we have in
our list and then we will get the
output. You know, operation completed,
an error occurred, still in progress,
etc. So that alone is pretty useful. It
can allow us to prevent writing, you
know, a ton of nested if statements and
we can just write it like this match
statement where we're trying to match a
particular value. However, where this
gets more interesting is when we get
into a more complex pattern matching
scenario. So this match statement
doesn't just work to match strings or
numbers or you know particular value.
You can actually match patterns. So have
a look at this second example down here.
What we're able to do is we have a case
for simply the value zero. Right? So
just like before we can match if data is
equal to zero. We also can use this pipe
operator and we can check for multiple
values. So we can check if it's one or
if it's two or if it's three and all of
that will be handled by this case. Then
we can also check for the structure
which is why a lot of times people refer
to this as structural pattern matching
of the object which is data. So in this
case we can say case first and second.
Now what this is saying is we're looking
for any kind of data where we have an
array or sorry a list I should say in
Python of two values. So for example if
you look down here we have apple and
banana that would match with this
pattern right here. And then we would be
able to extract the values. So apple and
banana were the first and second item by
using the variables first and second. I
know it looks a little bit weird. It
looks kind of like magic, but that's how
this works. Now, same thing with a
dictionary or an object in Python,
whatever you want to refer to it as,
right? What we're able to do is we have
name. So the key name, some value name,
the key age, some value age. In this
case, we're matching with anything that
is a dictionary that contains exactly
these two keys. And then we can strip
out what the values are and print them.
and we're process them however we want.
Now, we also can just check if something
is a string. This is kind of
interesting, right? We can just use the
string function. And now we're saying,
okay, I want to match anything that is a
string. Then, if we go down here, this
is the default case. So, I'm going to
run the code for you so you can quickly
see that this does indeed work. And
notice that we get all of the match
statements here up above, right? And
then same thing, we have all of the
match statements here. Now, it's
important to note when you use the match
statement that it's going to attempt to
match in the order in which you write
these cases. So for example, if we
change this to zero, right? And then we
had some string zero, it would actually
match with this first statement here,
not with this statement down here. Okay?
Because it's going to go into the first
case that it sees, especially because we
have the return. Now, there's a lot of
other information. Sorry about the match
statement. You could do some really
interesting complex stuff here. And I
definitely would suggest checking it
out. I'll leave a link to the
documentation in the description down
below. This is a feature that I rarely
see used which can be extremely powerful
especially when you have a variety of
different type of data and you want to
process that in some kind of format
right so we can look for the exact type
of pattern really simplifies and cleans
up our code and then we can handle all
of these different cases as we see fit
now the next feature on my list is
actually relatively old compared to the
other ones on this list however it is
still something that's definitely worth
knowing about and that I see few Python
developers especially beginners or
intermediates using that's called data
classes. And in order for us to see the
value of this, we need to actually look
at how you would typically write a class
before data classes existed. So in
Python, if you want to have a class that
represents data. So represents like a
user or a book or some kind of entity,
you would typically write it something
like this where you have this init
method. Maybe you take in an ID, some
name, maybe some roles for this
particular user. And then you're almost
always going to be defining a few
methods on these objects to make them
more usable in your code. For example,
you use this magic method repper which
gives you a string representation of the
object. So you can actually see what it
looks like if you're debugging the code
for example and you write something like
this where you have user name and then
the rules. Then you have something like
equals for example where you're going to
check the equivalence of two objects.
You might have the string method. You
might have a few other ones as well,
right? But a lot of times when you're
just trying to represent data, you're
almost always just writing the same kind
of boilerplate code. You're always
writing the same equal method. You're
always writing the same wrapper method.
And there isn't really a good reason to
do that other than the fact that there's
no better way. So, what I'm going to
show you now is what's called the data
class, which avoids you having to do all
of this. So, I'm going to open up this
example here. And notice that we have
this class right here, which is a data
class. And this is exactly the same as
the class that you just saw. It's
equivalently pretty much the exact same.
There's a few very, very minor
differences. And it's written in
significantly less code. There was no
init method. There's no equal method.
There's no wrapper method. Right? We
didn't have to do any of that. But this
actually functions the exact same way on
this data class. I can use the double
equal sign right between two user
objects. It will test for equivalence in
the exact same way as our other class. I
can try to print it out. And when I
print it out, I'm going to get that
wrapper where it's going to show me
exactly what this looks like in that
debugging format. And by default, if I
don't pass a role, it's automatically
going to be an empty list because of
this field that I brought in here from
the data classes. Now, I have a whole
video on data classes which I will link
on screen which you can watch if you
want the really in-depth explanation.
But the point is these are very very
useful. Now one thing to note here is
that I did enable frozen on this because
I decorated it with the data class
decorator and when I do that it means
that you cannot change the values inside
of this user object. Uh you can freeze
it right you can make it immutable which
is also an interesting component of data
classes. So in order to make something a
data class you use the data class
decorator. You define the different
fields that you want. You can use
standard Python types or you can use
from the typing module. For example, if
you want something like a list and then
if you want some kind of default value,
you can do that with this field. So
default factory means create a new list.
It's important you do it like this and
not define a list uh due to how Python
kind of interprets that list object. And
then if we come down here another
example, we have a product for example,
right? Well, we have a price, we have in
stock, id name, in this case it's
mutable. And if we look down here, these
are the operations you can perform on
these data classes that are
automatically implemented that you don't
need to write yourself. So I can create
an instance of user and I didn't need to
write init. I can have the ID, I can
have the name, I can have the rules. I
don't need to pass the rules. Same thing
with the product, you know, I can pass
the values. I didn't need to write the
init method. Then I can print these out.
When I do that, it's automatically going
to use a wrapper method for me, which
I'm going to show you in one second. And
then you can check for the equivalence
of these values, right? Right? And an
equal method is automatically
implemented for you. Same thing with the
immutability which will be enforced
which I'll show you. And then this works
really nicely with the match statement.
So what I can actually do is I can now
use these objects with the match
statement and I can check if a product
has the price of zero, right? I can
check if the product has a price that's
greater than 1,000 or something, right?
Or I can check if it's a regular
product. So it's kind of a cool thing
you can do with match. If I run this
code here, scroll down and notice that
we get the user, right? So this is
automatically implemented for us. We get
product automatically implemented. We
get the equal method automatically
implemented. Same thing here. You know,
user cannot modify the field name
because it's immutable. And then it
defines that one of our products was
expensive because we made it $1,200.
Okay. So the data class is super super
useful. Again, I'll put that video on
screen. And just consider right this
versus this. Which one would you rather
write? Of course, you would rather use
the data class. Now, the next feature
that I have for you is something called
the positional or keyword only
parameters. Now, parameters in Python
are notoriously a little bit confusing
because of all of the different
combinations of ways that you can call
them. So, I want to quickly go into a
bit of a primer about parameters and
then show you this relatively new
feature. All right, so let's have a look
at this function here. Right, we have
some function. We have some values now a
b c d. Right, these are our parameters.
Now, when I call the function, I can
call it using what's known as positional
parameters. So I can say you know my
function and I can pass 1 2 3 4 or
something right and when I do that I'm
now assigning the value A to 1 B to 2 C
to 3 D to 4. So I can do that. That's
totally fine. But I also could do
something like B= 2, A= 1. Okay. And
then I can say C= 3, D= whatever. And I
can pass these in like kind of a random
order, whatever order that I want. And I
can kind of pick and choose if I want to
pass them positionally or if I want to
pass them using a keyword argument,
which is what I'm doing right here. And
there's all kinds of other combinations
of ways that I could call this function.
And it can be a little bit confusing.
Now, it's fine, right? That's just by
default how functions are written. But
in Python, there's actually a way to
enforce the way in which your functions
are called. And that is by using this
fancy operator right here, which is the
slash. Now, this slash forces arguments
to be passed positionally only. I know
it seems a little bit weird. Why would
you do this? We'll talk about that a
little bit later. But by me implementing
this slash now inside of these function
parameters, which is something you may
see in larger libraries, it now doesn't
allow me to pass name using a keyword
argument. And again, we'll talk about
why that's important in a second. So,
you can look here and you can see I can
call it in this way, right? I can call
it with Alice. I can call with Bob and
hi. I can call it with you know Charlie
and the greeting is equal to hey because
name is passed positionally where I'm
not manually defining you know name is
equal like this to Alice. However if I
go down here and I try to call this
where I say you know greet name is equal
to David you'll see that we actually get
a type error and it will tell us that
this is a positional only argument or
parameter and that I cannot call it by
specifying the name. So let me just call
this function and show you what that
looks like. Okay. And you can see all
three of these function calls uh worked
properly. And then when I did try to
call it here, you can see result four.
It said this was a positional only
argument, right? So got some positional
only arguments passed as a keyword
argument name. So you are able to do
this enforcement. Okay. Now let me
quickly talk about why that's actually
important. The reason why this is
interesting actually applies more to
APIs and if you're creating libraries
that other people are going to be using.
And that's because this allows you to
make significantly more robust functions
and just APIs in general so that you can
control the way in which they're used
and make sure they stay backwards
compatible. So for example, if callers
can't use a name, right? If I'm not able
to use, you know, name is equal to
whatever and pass the parameter or you
know value is equal to whatever or max
is equal to two. if I can't use that
right as a uh keyword argument, then it
means that I can rename this parameter
later on and I'm not going to break any
user's code. So, this is especially
important when you're writing something
that you know is going to change in the
future. If you make sure that something
is only passed positionally, then the
name of the positional argument doesn't
actually matter and you can change it to
anything you want in the future or
implement it a new, for example, keyword
argument that has the same name. So this
just allows flexibility to you as
someone who's writing these functions.
Now again, imagine the code you're
writing is used by someone else and
maybe millions of people are using it
and then all of a sudden you change the
name of one of your parameters. If it
could have been called by a keyword and
you now change it, you're going to break
a bunch of people's code, right? So
that's kind of one of the main reasons.
Now another one is semantics, right? So
some of the parameters don't have
meaningful names. For example, x y a b
you know 1 2 whatever, right? So when
you force the use of positional
arguments, you signal to the user that
this is more used internally in the
function and to pass it positionally
rather than trying to name the keywords.
Now same thing as I said before, room
for future keyword updates, right? So
you can keep the names available to use
them later on. And it's also more
consistent with built-in functions where
a lot of the built-in functions uh work
like this already where you can only
pass values positionally, right? You
can't pass them with keyword arguments.
So hopefully that makes a little bit of
sense. Now to kind of continue this you
also can force arguments to be only
keyword so not be passed positionally
and be passed keyword only and that's by
using this asterisk. So the way this
works is anything that I want to be
positional only I put before this
forward slash. If I do that anything
before this so you know pause only two
right all of these can only be passed by
position. Then anything after this can
be passed freely as normally. So it can
be passed by position or by keyword.
Okay, so regular I can pass this with a
keyword argument or I can pass it
normally. Then if I put an asterisk,
anything to the right of this can only
be passed by a keyword. So now I cannot
pass this value positionally. I can only
pass it by a keyword. And similar
reasons for doing that apply to us why
you would only pass it positionally. I
know this is kind of advanced, you know,
niche Python code, but that's the point
of this video is to show you guys some
new stuff that you probably never seen
before. And I know I didn't see this
until I started looking deeper into it.
Let's actually run the code here. And
you can see now that this works, right?
And it says, you know, mix parameters,
positional only one, regular two,
keyword only three. I just quickly
changed this example back so it would
work with the way that it was being
called. Anyways, that is pretty much
going to wrap this up. Now, if you've
made it to this point in the video, then
I can tell that you definitely valued
learning. You like more of those
advanced topics, and I mean, you're
spending your time watching a video like
this. And if that's the case, then I
think you would definitely benefit from
the sponsor of today's video, which is
Brilliant. Brilliant is where you learn
by doing with thousands of interactive
lessons in math, data analysis,
programming, and AI. They adopt a first
principles approach, ensuring you
understand the why behind each concept.
Every lesson is interactive, engaging
you in hands-on problem solving, which
is proven to be six times more effective
than simply watching lectures. The
content is developed by top-notch
educators researchers and
professionals from renowned institutions
like MIT, Caltech, and Google. Brilliant
emphasizes enhancing your critical
thinking abilities through active
problem solving rather than
memorization. As you learn specific
subjects, you're simultaneously training
your mind to think more effectively.
Consistent daily learning is crucial,
and Brilliant makes it effortless with
their bite-sized lessons, allowing you
to acquire meaningful knowledge in just
a few minutes each day, which is perfect
for replacing idle screen time.
Additionally, Brilliant offers a
comprehensive range of computer science
and Python courses as well as extensive
AI workshops guiding you from a complete
beginner to an expert through practical
hands-on lessons. To learn for free on
Brilliant, go to
brilliant.org/techwithtim.
Scan the QR code on screen or click the
link in the description. Brilliant has
also given our viewers 20% off an annual
premium subscription, which gives you
unlimited daily access to everything on
Brilliant. Thanks to Brilliant for
sponsoring this video, and I look
forward to seeing you in the next one.
[Music]
Loading video analysis...