type(obj) vs. obj.__class__ in Python, and changing an object's class.
HTML-код
- Опубликовано: 8 июн 2024
- What's the difference?
Python has two way to access the type of an object. There's type(obj) and obj.__class__. What's the difference? In this video we see how they are mostly the same (and you probably shouldn't worry about it) but there is a difference in that it's possible for a class to lie about what type it is by intercepting accesses to _class__. The builtin type on the other hand will always give you the real type of the object. Although, if a class tries to lie about it's type, maybe it has a good reason for it, which means you might prefer using __class_ for this reason. It's also possible to modify an objects _class_ at runtime after the object has been created, which will truly change the type so that type(obj) and obj.__class__ both report the new type. There are some restrictions (and use cases are questionable!) but it's good to know in case you ever feel like something funny is going on.
― mCoding with James Murphy (mcoding.io)
Source code: github.com/mCodingLLC/VideosS...
docs.python.org/3/reference/d...
SUPPORT ME ⭐
---------------------------------------------------
Sign up on Patreon to get your donor role and early access to videos!
/ mcoding
Feeling generous but don't have a Patreon? Donate via PayPal! (No sign up needed.)
www.paypal.com/donate/?hosted...
Want to donate crypto? Check out the rest of my supported donations on my website!
mcoding.io/donate
Top patrons and donors: Jameson, Laura M, Dragos C, Vahnekie, Neel R, Matt R, Johan A, Casey G, Mark M, Mutual Information, Pi
BE ACTIVE IN MY COMMUNITY 😄
---------------------------------------------------
Discord: / discord
Github: github.com/mCodingLLC/
Reddit: / mcoding
Facebook: / james.mcoding
CHAPTERS
---------------------------------------------------
0:00 Intro
0:34 How to use type(obj)
1:43 What about obj.__class__?
3:08 Lie about your _class_
3:56 Changing _class_ at runtime
6:44 Example: custom module type
7:36 Example: Reading pre-initialized object
9:34 Thanks - Наука
Wow that is seriously cursed
#type
Directly accessing dunder attributes/methods almost always looks janky
it's not janky, it's **pythonic** 🤩
Remember that somebody has to.
@@AntonioZL using stuff like type is pythonic. Using dunders directly goes against all the abstraction python is known for
@@sinom people who use the ___class___ variable in a class method (not the attribute, the variable) or the ___name___ attribute of classes:
I tend to use #class for user defined classes or more abstract classes, and #type for base types, like ints or strs.
I used to be a #class person before your video, but now I'm totally #type.
Thanks as always for deep dives and interesting facts about Python. Love your vids, keep it up!
For me it's funnily the inverse. If an object lies about its class it probably has a *really* good reason to do so.
I'm feeling like #class is more convenient while working with a class and #type is more convenient while working with plain types (e.g. int, str, float, bytes)
5:16 i nearly spat out my tea, thanks James
#class, and I actually use the runtime class change in one of my projects. Yes, it has an actual use in my case.
But where I do it, the classes basically don't have any extra initialization to be done, so... Bad code quality, but it's the only way it works.
At least it works.
EDIT:
My bad, I'm modifying instance.___bases___ rather than instance.___class___ ! Sorry for the confusion !
If you have ur project on github, would u be able to share your proj. Im mere curious about ur particular kind of task where you're required to change _bases_ at runtime
#class thanks for the demonstration, that's good to know
5:16 that was incredible, so out of left field, I love it.
#type
so when are we getting reinterpret_cast for python objects
#class I never knew you could use type(self) in place of self.__class__, so it looks funny :|
But when you add two things do you do x.__add__(y) or x + y? Calling dunder stuff is always sketchy.
“+” translates to the add method call--that’s how it’s defined to work.
Dunder methods are there because somebody, at some point, has to call them.
@@DanCojocaru2000 people who use the ___class___ variable in a class method (not the attribute, the variable) or the ___name___ attribute of classes:
Dude! You are carrying us to dark side of python, keep it on! I really love you channel. Yours and the one from ArjanCodes just have fantastic content.
Thanks so much, I appreciate the encouragement!
Thanks for the (as usual) precious insight! I wonder, is the behaviour of "isinstance" affected by this ?
Fantastic question that has a weird answer! Assuming you don't use a custom isinstance check by overriding __instancecheck__, the default behavior is to check _*_BOTH_*_ the real type's MRO and the __class__'s MRO. So if you have A < object, Liar < object, and Liar lies and says its __class__ is A, then isinstance(Liar(), A) and isinstance(Liar(), Liar) will both return True! Here's a compiler explorer link to play with this example: godbolt.org/z/fE8Ke5PWa
Thank you for asking what I need to know but didn't know to ask
8:35 this is actually cool and useful!
#3:40 you don't do that because you have great job security, but as a way of getting it! If nobody else can maintain your code, they can't get rid of you
"If you do this you must have incredible job security" lol I come here for the jokes!
#type
Just found your channel and subbed. This is the second video I see from you, the other was 25 nooby habits. Just letting you know: while this is still perfectly audible, your older video had way better audio, and I can see this 'dull' sound leading to fatigue.
Thanks for bringing this up! I don't hear any difference and i don't realize what im doing different. What about the current audio is not as good? Is it too quiet? Popping noises? Equalization? Background noise? Any feedback is greatly appreciated.
Im working on an admin panel builder for flask. Definitely been pushing all these techniques to the extreme.
Changing the class off an object must violate the geneva convention.
Jokes aside. Has anyone used this feature? I feel kinda curious
I haven't seen it in production :)
Ironically, working today I got an error from ipython that I think comes from using it
#type If a builtin function is avaiilable, as a matter of style, I always prefer it over a dunder attribute/method. Like, no one would write `list.__setitem__(index, value)` instead of `list[index] = value`, so why treat `__class__` differently?
my god, I was just thinking about this topic this morning in my bed and now I get a new video from you on this topic.. #Google_reading_minds
#type: 'type(𝕊)' is shorter than '𝕊.__class__'
Another case where you might consider modifying an object's __class__ attribute is when you have a library providing a class A with a corresponding factory function build_A. Now, if you want to create a subclass B with a similar factory function build_B, you could modify the __class__ attribute of instances created by build_A to B to avoid duplicating the code from build_A
I could see using the last example as a way of directly initializing an object from a correctly written JSON dictionary
#metaclass
I use #type for runtime type checking, i.e. type(obj1) == type(obj2). I use #class for introspection-like scenarios, especially if I'm viewing the classname. like print(self.__class__.__name___). I would never write: if obj.__class__ == int nor would I write print(type(self).__name__)
Team #type because it is more intuitive for me that way.
#type so that you can use it wherever you want.
#class
pretty sure the convention is everything starting with an underscore is private/protected and shouldn’t be used.
#type all the way
Today I've learnt yet another way to hack Python 😁
#class
#class of course
"of course"
#type- I'm of the belief we should directly reference dunders as little as possible.
#type because inheritance blows let's be honest
type(obj) ?
obj.__class__?
How about obj.__class__.__class__(obj)
But for real, #type is the proper way
This is some wonderful #cursed-code
I don't even understand what this is even doing. What even is the class of a class, some kind of class for representing types I guess. You're like constructing a type object from the given object?
@@n0ame1u1 the class of a class is "type". Yep, "type" isn't a function, it's a class.
I'm a #class user myself. No particularly strong reason, I'm just used to it.
#type, it seems odd that it would be a property
#type looks more stable, I wouldn't use class except if I needed its extra functionality.
#class
type(a) => 5 instructions;
a.__class__ => 2 instructions
class is two times faster: `timeit('type(a)', 'class A:pass
a=A()')` vs `timeit('a.__class__', 'class A:pass
a=A()')`
Premature optimization...
@@kmn1794 For the record, that's a joke, right?
It's not 2 times faster when I check. In 100 million iterations, it averages 1.7 seconds vs. 1.2 seconds, so only a 0.5 second difference. And I doubt you're doing this 100 million times. If this small of a difference matters, then you should really be using/making a C extension or writing in a different language.
And even in C/C++, it's rare to care about this small of a difference, since you're never calling this cheap of a function this many times in most cases. You're usually more focused on the bigger changes, that can cause more noticeable differences. So you really shouldn't be looking at a small difference that most people, even in fast languages, won't look at, in as slow of a language as python.
I like #class more, just looks better, ig
#class do what you mean and go straight to the source. There is no sense in asking `type` what the the class is if the class can tell you itself.
well 2:25 so #class 😂
#type because aside from the global method lookup it should be faster, maybe, probably not
Besides the fact that worrying about such a thing *in Python* is a severe mindset problem (though really, all premature optimization is bad), looking up a key in a dictionary should be faster than looking up and calling a function.
@@SkyyySi What does the function do to generate the type info and how are dictionaries in Python implemented?
@@anon_y_mousse Since that doesn't ultimately tell us that much, I did the thing to actually do when you want to know whether something is faster: measuring. The answer is that the dunder class version actually is slower. Doing 100 million iterations, the dunder version took about 13 seconds per run while the type() version took about 12. In other words, the difference is about 10 *nanoseconds* per run (assuming I didn't mess up the conversion _cough_). So if you worry about that in the slightest: stop using Python.
@@SkyyySi I actually wasn't worried, just curious. I guess I'll have to open up the source for Python to sate that curiosity, but that's okay, it's written in C. I would assume that the function call does more or less the same thing, just that it queries some kind of hidden dictionary and that dictionaries are just hash tables, but I don't know for certain, yet.
@@SkyyySi To further add to the point, even in languages like C/C++, this difference is usually insignificant.
#class cos it just looks better and since its not calling a function it faster
type is actually faster and looks better. Perhaps it looks bad among a large block of dunder attribute accesses?
@@kmn1794 well, actually, ___class___ is faster, but it's so small, you really shouldn't base your decision around this. The speed difference is basically insignificant, even in languages like C/C++. It's definitely not worth considering in python.
@@FastKnight401 You are correct. Although, I really wasn't expecting that to be the case. I was comparing the read of general class attributes rather than x.__class__ specifically.
Guess its got to do with the internals of python. Impressive that the performance negligibility of this point is comparable to C/C++.
Still, just knowing that the class way is 1.25 faster than the type way is tempting to use everywhere, however, I think the type way is more readable and its easy to use a regex to convert between both ways. Whenever I see dunder class I think of class mutation not getting the type.
type(x) is better than x.__class__ when you want the truth.
Nice updog joke
#class. _tell me your sweet little lies~_
I don't write a whole lot of Python, so I've never used either, but I would definitely rather use #type because I kind of dislike typing underscores. That's also part of why I dislike operator overloading in Python, that and the names don't always make sense, such as __truediv__ and __floordiv__. I would prefer a name like fdiv and idiv to denote which, but it's still weird to me that they use // for integer division when to me that's a comment.
holy shit this is the most retarded comment i’ve read in a while. a shit ton of personal opinions carried from another language with zero logical reasoning.
i am a dog now
are you the dude from silicon valley bro
Which one 🤔
dunder #class , I don't know it just looks more pythonic
And yet the Pythonic way is to always avoid dunder stuff unless absolutely needed. str(x) instead of x.__str__, iter(x) instead of x.__iter__, next(x) instead of x.__next__, x + y instead of x.__add__(y) and so on.
it looks ugly for a reason, dunder methods are rarely meant to be called directly and should only be called internally by python
@@Zhaxxy that's demonstrably untrue. Dunders are meant to denote a field being a part of a protocol. The underscores are meant to avoid naming collisions. In many cases there isn't even a nondunder way to do something.
Also, stop gaslighting yourself. Whenever you are doing 'def __dunder__' in python, that is just an assignment hidden by a layer of syntactic sugar.
@@__mrmino__ exactly its hidden away
@@Zhaxxy Syntactic sugar part tells you that the "hiding" is just for syntax. The rest is just a name. Many classes from stdlib define their own dunders which are meant to be accessed in specific circumstances, and this is by design. It's not about hiding these fields, it's about having a separate namespace for overridable fields that are used as language features.
I use the one copilot auto fills for me 😅
Thank you for my job security
you are a dog now 🐕
then we say YOURE A DOG NOW
Please don’t try this at home!
Too much of job security can get the whole business out of job
#type
#class
#type
#type
#type
#type
#type
#type
#type
#type
#type
#type
#type
#type
#type
#class
#class
#class
#class
#class