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
  • НаукаНаука

Комментарии • 123

  • @Serpent10i
    @Serpent10i Год назад +86

    Wow that is seriously cursed

  • @danwellington3571
    @danwellington3571 Год назад +100

    #type
    Directly accessing dunder attributes/methods almost always looks janky

    • @AntonioZL
      @AntonioZL Год назад +8

      it's not janky, it's **pythonic** 🤩

    • @lawrencedoliveiro9104
      @lawrencedoliveiro9104 Год назад +2

      Remember that somebody has to.

    • @sinom
      @sinom Год назад +9

      ​@@AntonioZL using stuff like type is pythonic. Using dunders directly goes against all the abstraction python is known for

    • @FastKnight401
      @FastKnight401 Год назад

      @@sinom people who use the ___class___ variable in a class method (not the attribute, the variable) or the ___name___ attribute of classes:

  • @AntonioZL
    @AntonioZL Год назад +26

    I tend to use #class for user defined classes or more abstract classes, and #type for base types, like ints or strs.

  • @Phaust94
    @Phaust94 Год назад +18

    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!

    • @Kenionatus
      @Kenionatus Год назад +10

      For me it's funnily the inverse. If an object lies about its class it probably has a *really* good reason to do so.

  • @SyberiaK
    @SyberiaK Год назад +5

    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)

  • @MilChamp1
    @MilChamp1 Год назад +3

    5:16 i nearly spat out my tea, thanks James

  • @mathieuflouret7177
    @mathieuflouret7177 Год назад +10

    #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 !

    • @umion9529
      @umion9529 10 месяцев назад

      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

  • @Scymet
    @Scymet Год назад +2

    #class thanks for the demonstration, that's good to know

  • @adamdapatsfan
    @adamdapatsfan Год назад +1

    5:16 that was incredible, so out of left field, I love it.
    #type

  • @jemand771
    @jemand771 Год назад +8

    so when are we getting reinterpret_cast for python objects

  • @RichardFeynman2282
    @RichardFeynman2282 Год назад +9

    #class I never knew you could use type(self) in place of self.__class__, so it looks funny :|

    • @DanCojocaru2000
      @DanCojocaru2000 Год назад +1

      But when you add two things do you do x.__add__(y) or x + y? Calling dunder stuff is always sketchy.

    • @lawrencedoliveiro9104
      @lawrencedoliveiro9104 Год назад

      “+” 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.

    • @FastKnight401
      @FastKnight401 Год назад

      @@DanCojocaru2000 people who use the ___class___ variable in a class method (not the attribute, the variable) or the ___name___ attribute of classes:

  • @julianbazanaguirre8439
    @julianbazanaguirre8439 11 месяцев назад +2

    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.

    • @mCoding
      @mCoding  11 месяцев назад +1

      Thanks so much, I appreciate the encouragement!

  • @paper_cut9457
    @paper_cut9457 Год назад +14

    Thanks for the (as usual) precious insight! I wonder, is the behaviour of "isinstance" affected by this ?

    • @mCoding
      @mCoding  Год назад +16

      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

    • @felixfourcolor
      @felixfourcolor 11 месяцев назад

      Thank you for asking what I need to know but didn't know to ask

  • @Cyber_Chriis
    @Cyber_Chriis Год назад +1

    8:35 this is actually cool and useful!

  • @QuantumHistorian
    @QuantumHistorian Год назад +10

    #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

  • @fartzy
    @fartzy 11 месяцев назад

    "If you do this you must have incredible job security" lol I come here for the jokes!

  • @schrummy14
    @schrummy14 Год назад +2

    #type

  • @tobylegion6913
    @tobylegion6913 Год назад +1

    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.

    • @mCoding
      @mCoding  Год назад

      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.

  • @thagreatone402
    @thagreatone402 Год назад

    Im working on an admin panel builder for flask. Definitely been pushing all these techniques to the extreme.

  • @gustavomendez2891
    @gustavomendez2891 Год назад +4

    Changing the class off an object must violate the geneva convention.
    Jokes aside. Has anyone used this feature? I feel kinda curious

    • @mCoding
      @mCoding  Год назад +3

      I haven't seen it in production :)

    • @gustavomendez2891
      @gustavomendez2891 Год назад +1

      Ironically, working today I got an error from ipython that I think comes from using it

  • @felixfourcolor
    @felixfourcolor 11 месяцев назад +2

    #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?

  • @elrandira
    @elrandira Год назад

    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

  • @GanerRL
    @GanerRL Год назад +3

    #type: 'type(𝕊)' is shorter than '𝕊.__class__'

  • @panosemp
    @panosemp Год назад

    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

  • @brandonhicks7549
    @brandonhicks7549 Год назад +1

    I could see using the last example as a way of directly initializing an object from a correctly written JSON dictionary

  • @AsgerJon
    @AsgerJon Год назад +3

    #metaclass

  • @marckiezeender
    @marckiezeender 8 месяцев назад

    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__)

  • @MarioFanGamer659
    @MarioFanGamer659 Год назад +1

    Team #type because it is more intuitive for me that way.

  • @MmKayUltra1
    @MmKayUltra1 Год назад +1

    #type so that you can use it wherever you want.

  • @RupeshBhandari-977
    @RupeshBhandari-977 Год назад

    #class

  • @itsmaxim01
    @itsmaxim01 4 месяца назад

    pretty sure the convention is everything starting with an underscore is private/protected and shouldn’t be used.

  • @paridhaxholli
    @paridhaxholli 11 месяцев назад

    #type all the way

  • @yaroslavdon
    @yaroslavdon Год назад +1

    Today I've learnt yet another way to hack Python 😁
    #class

  • @unperrier5998
    @unperrier5998 Год назад

    #class of course

  • @treyheaney9483
    @treyheaney9483 11 месяцев назад

    #type- I'm of the belief we should directly reference dunders as little as possible.

  • @evandrofilipe1526
    @evandrofilipe1526 Год назад +2

    #type because inheritance blows let's be honest

  • @Tomyb15
    @Tomyb15 Год назад +8

    type(obj) ?
    obj.__class__?
    How about obj.__class__.__class__(obj)
    But for real, #type is the proper way

    • @mCoding
      @mCoding  Год назад +1

      This is some wonderful #cursed-code

    • @n0ame1u1
      @n0ame1u1 Год назад +1

      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?

    • @FastKnight401
      @FastKnight401 Год назад

      @@n0ame1u1 the class of a class is "type". Yep, "type" isn't a function, it's a class.

  • @Diapolo10
    @Diapolo10 Год назад

    I'm a #class user myself. No particularly strong reason, I'm just used to it.

  • @daniihh
    @daniihh Год назад +1

    #type, it seems odd that it would be a property

  • @Yazan_Majdalawi
    @Yazan_Majdalawi Год назад

    #type looks more stable, I wouldn't use class except if I needed its extra functionality.

  • @senyai
    @senyai Год назад +1

    #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()')`

    • @SkyyySi
      @SkyyySi Год назад +7

      Premature optimization...

    • @SkyyySi
      @SkyyySi Год назад

      @@kmn1794 For the record, that's a joke, right?

    • @FastKnight401
      @FastKnight401 Год назад +1

      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.

  • @guddi8
    @guddi8 Год назад

    I like #class more, just looks better, ig

  • @haxwithaxe
    @haxwithaxe 9 месяцев назад

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

  • @mubrik_
    @mubrik_ 10 месяцев назад

    well 2:25 so #class 😂

  • @lior_haddad
    @lior_haddad Год назад +1

    #type because aside from the global method lookup it should be faster, maybe, probably not

    • @SkyyySi
      @SkyyySi Год назад

      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.

    • @anon_y_mousse
      @anon_y_mousse Год назад

      ​@@SkyyySi What does the function do to generate the type info and how are dictionaries in Python implemented?

    • @SkyyySi
      @SkyyySi Год назад

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

    • @anon_y_mousse
      @anon_y_mousse Год назад

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

    • @FastKnight401
      @FastKnight401 Год назад

      @@SkyyySi To further add to the point, even in languages like C/C++, this difference is usually insignificant.

  • @diamonddemon7612
    @diamonddemon7612 Год назад

    #class cos it just looks better and since its not calling a function it faster

    • @kmn1794
      @kmn1794 Год назад

      type is actually faster and looks better. Perhaps it looks bad among a large block of dunder attribute accesses?

    • @FastKnight401
      @FastKnight401 Год назад

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

    • @kmn1794
      @kmn1794 Год назад +1

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

    • @kmn1794
      @kmn1794 Месяц назад

      type(x) is better than x.__class__ when you want the truth.

  • @andreasnulein782
    @andreasnulein782 Год назад

    Nice updog joke

  • @bee_irl
    @bee_irl Год назад

    #class. _tell me your sweet little lies~_

  • @anon_y_mousse
    @anon_y_mousse Год назад

    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.

    • @stxnw
      @stxnw 10 месяцев назад

      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.

  • @TheHackysack
    @TheHackysack 10 месяцев назад

    i am a dog now

  • @agrahajigyasu1715
    @agrahajigyasu1715 Год назад

    are you the dude from silicon valley bro

  • @archibald-yc5le
    @archibald-yc5le Год назад

    dunder #class , I don't know it just looks more pythonic

    • @DanCojocaru2000
      @DanCojocaru2000 Год назад +3

      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.

    • @Zhaxxy
      @Zhaxxy Год назад +2

      it looks ugly for a reason, dunder methods are rarely meant to be called directly and should only be called internally by python

    • @__mrmino__
      @__mrmino__ Год назад

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

    • @Zhaxxy
      @Zhaxxy Год назад +1

      @@__mrmino__ exactly its hidden away

    • @__mrmino__
      @__mrmino__ Год назад

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

  • @gardnmi
    @gardnmi Год назад +5

    I use the one copilot auto fills for me 😅

    • @arnontzori
      @arnontzori Год назад +1

      Thank you for my job security

  • @rx97_mc
    @rx97_mc Год назад +4

    you are a dog now 🐕

  • @Nominal_GDP
    @Nominal_GDP Год назад +1

    then we say YOURE A DOG NOW

  • @everytimeifall
    @everytimeifall 11 месяцев назад

    Please don’t try this at home!
    Too much of job security can get the whole business out of job

  • @fiNitEarth
    @fiNitEarth Год назад +3

    #type

  • @knut-olaihelgesen3608
    @knut-olaihelgesen3608 Год назад

    #class

  • @DanCojocaru2000
    @DanCojocaru2000 Год назад +2

    #type

  • @Zhaxxy
    @Zhaxxy Год назад +3

    #type

  • @murphygreen8484
    @murphygreen8484 Год назад +2

    #type

  • @YeloFelo
    @YeloFelo Год назад +2

    #type

  • @anselmschueler
    @anselmschueler Год назад +2

    #type

  • @greasedweasel8087
    @greasedweasel8087 Год назад +2

    #type

  • @ablobofgarbage
    @ablobofgarbage Год назад +1

    #type

  • @spaghettiking653
    @spaghettiking653 Год назад +1

    #type

  • @AssemblyWizard
    @AssemblyWizard Год назад +1

    #type

  • @DanHartwigMusic
    @DanHartwigMusic Год назад +1

    #type

  • @carlossegura403
    @carlossegura403 Год назад +1

    #type

  • @cefarix
    @cefarix Год назад +2

    #type

  • @Keithfert490
    @Keithfert490 11 месяцев назад

    #type

  • @ilyarik8888
    @ilyarik8888 Год назад

    #class

  • @30IYouTube
    @30IYouTube Год назад

    #class

  • @genkidaemon
    @genkidaemon Год назад

    #class

  • @tooru
    @tooru Год назад

    #class

  • @loicgrossetete9570
    @loicgrossetete9570 Год назад

    #class