LongCut logo

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...

Loading video analysis...