Why is it wrong to inherit Python built-in types?!

itread01 2020-11-15 16:15:14
wrong inherit python built-in built


> This article from the “Python Why? ” series , Please check [ All articles ](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUyOTk2MTcwNg==&action=getalbum&album_id=1338406397180084225&subscene=0&scenenote=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzUyOTk2MTcwNg%3D%3D%26mid%3D2247485945%26idx%3D1%26sn%3D02f1ac9a690f57accefeed7a1ea1247b%26chksm%3Dfa584e7ccd2fc76af5d45ebbc43c1e4d379a0fcfeee8ce70111a8a293c4b7efc8ac7a82dfd6a%26xtrack%3D1%26scene%3D0%26subscene%3D91%26sessionid%3D1596284425%26clicktime%3D1596284604%26enterid%3D1596284604%26ascene%3D7%26devicetype%3Dandroid-28%26version%3D2700103f%26nettype%3DWIFI%26abtest_cookie%3DAAACAA%253D%253D%26lang%3Dzh_CN%26exportkey%3DAa1rI96xIRQ8cDJChmQS9BU%253D%26pass_ticket%3DP%252BUyocSqsqUN5JuCQOyjZNpQH%252Fwm0bsN6NchdKKM9CFDDEu0ZPKsRpo8Utu4BBRc%26wx_header%3D1#wechat_redirect) not long ago ,`Python Cat ` I recommend a book to you 《 Flowing Python》([ Click to jump to read ](https://mp.weixin.qq.com/s/A4_DD2fvceNk1apn9MQcXA)), That article has a lot of “ Words of praise ”, It seems to be rather vague …… however ,《 Flowing Python》 A book is worth reading over and over again , You can learn from the old . Recently, I found a strange knowledge point in the book , So I'm going to talk about this topic ——** Subclassing built-in types can cause problems ?!** ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gk0qx3a7iuj20uq0hnq8g.jpg) ## 1、 What are the built-in types ? Before the official start , First of all, we need to popularize science :** Which are Python The built-in type of ?** According to the classification of official documents , Built in type (Built-in Types) It mainly includes the following contents : ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gk1f8ng1ozj20m90d3my7.jpg) Detailed documents :https://docs.python.org/3/library/stdtypes.html among , There is a well-known [ Number type ](https://mp.weixin.qq.com/s/0XpPaH53II5yO9Lfh80ZOw)、 Sequence type 、 Text type 、 And so on , And, of course, we've introduced [ Brin type ](https://mp.weixin.qq.com/s/JVhXjQKcd8uds8yTUumZJw)、[... thing ](https://mp.weixin.qq.com/s/SOSN_p74eDHv3tJnSJIZfg) wait . In so much content , This article focuses only on what is done ` Callable objects `(callable) The built-in type of , That is, with built-in functions (built-in function) On the surface, similar ones :**int、str、list、tuple、range、set、dict……** These types (type) It can be simply understood as a class in other languages (class), however Python There is no customary nomenclature for the hump , So it's easy to get misunderstood . stay Python 2.2 After that , These built-in types can be subclassed (subclassing), That is, it can be inherited (inherit). ## 2、 Subclassing of built-in types As we all know , For a common object x,Python To find its length, we need to use the common built-in function len(x), It is not like Java Object oriented languages like this , The latter objects usually have their own x.length() Method .(PS: The analysis of these two design styles , Recommended reading [ This article ](https://mp.weixin.qq.com/s/pKQT5wvyaSNFvnJexiCC8w)) Now , Suppose we want to define a list class , Hope it has its own length() Method , At the same time, keep all the features of a normal list . The experimental code is as follows ( Just for demonstration ): ```python # Define a list Subclasses of class MyList(list): def length(self): return len(self) ``` We make MyList This custom class inherits list, At the same time, a new definition of length() Method . In this way ,MyList Just have append()、pop() Method, etc. , At the same time, I have length() Method . ```python # Add two elements ss = MyList() ss.append("Python") ss.append(" Cat ") print(ss.length()) # Output :2 ``` The other built-in types mentioned earlier , It can also be subclassed in this way , It shouldn't be hard to understand . By the way ,** What are the benefits of subclassing built-in types / What about the usage scenarios ?** There's an intuitive example , When we are in a custom class , When you need to use a list object frequently ( Add... To it / Delete the element 、 Pass on as a whole ……), In this case, if our class inherits from list, You can write directly self.append()、self.pop(), Or will self Pass on as an object , So you don't have to define an extra list object , It will be concise in writing . There are other benefits / Use scenarios ? Welcome to leave a message to discuss ~~ ## 3、 Built in subclasses of “ The problem is ” Finally, it will enter the formal theme of this article :) generally , In our textbook cognition ,** Methods in subclasses override methods with the same name in the parent class , That is to say , The query priority of subclass method is higher than that of parent method .** Here's an example , The parent class Cat, Subclass PythonCat, All have one say() Method , The function is to say the current object inner_voice: ```python # Python A cat is a cat class Cat(): def say(self): return self.inner_voice() def inner_voice(self): return " meow " class PythonCat(Cat): def inner_voice(self): return " Meow meow " ``` When we create subclasses PythonCat The object of , its say() Methods will take precedence over the ones defined by themselves inner_voice() Method , instead of Cat Parent inner_voice() Method : ```python my_cat = PythonCat() # The following results are in line with expectations print(my_cat.inner_voice()) # Output : Meow meow print(my_cat.say()) # Output : Meow meow ``` This is the Convention of programming language , It's a basic principle , Students who have studied the fundamentals of object-oriented programming should know . However , When Python When implementing inheritance ,** It seems incomplete ** Will operate according to the above rules . It's divided into two situations : - In accordance with common sense : For use Python Implemented classes , They will follow “ The subclass precedes the parent ” The principle of - Against common sense : To be practical, it is to use C Implemented classes ( namely str、list、dict Wait, these built-in types ), When explicitly calling subclass methods , Will follow “ The subclass precedes the parent ” The principle of ; however ,** When there is an implicit call ,** They seem to follow “ The parent class precedes the child class ” The principle of , That is, the usual inheritance rules will fail here Contrast PythonCat Example , Equivalent to saying , Direct call my_cat.inner_voice() When , Will get the right “ Meow meow ” It turns out , But it's calling my_cat.say() When , You get more than you expect “ meow ” It turns out . Here is 《 Flowing Python》 The example given in (12.1 Chapter ): ```python class DoppelDict(dict): def __setitem__(self, key, value): super().__setitem__(key, [value] * 2) dd = DoppelDict(one=1) # {'one': 1} dd['two'] = 2 # {'one': 1, 'two': [2, 2]} dd.update(three=3) # {'three': 3, 'one': 1, 'two': [2, 2]} ``` ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gknw0m0nzuj20q90ag758.jpg) In this case ,dd['two'] Will call subclasses directly \_\_setitem\_\_() Method , So the results are in line with expectations . If other tests are as expected , The end result will be {'three': [3, 3], 'one': [1, 1], 'two': [2, 2]}. However , Initialization and update() Inherited directly from the parent class \_\_init\_\_() and \_\_update\_\_(), And then they ** Implicitly ** call _\_setitem\_\_() Method , There is no method to call subclasses at this time , Instead, it calls the method of the parent class , The result is beyond expectation ! official Python This double rule approach , It's a little against common sense , If you don't pay attention to , It's easy to step on the pit if it's not done well . So , Why is this exception ? ## 4、 The true face of the built-in method We learned that built-in types don't implicitly call subclass overlay methods , Then , Namely `Python Cat ` To get to the bottom of it : Why doesn't it call ? 《[ Flowing Python](https://mp.weixin.qq.com/s/A4_DD2fvceNk1apn9MQcXA)》 There is no further questioning in the book , But , I tried to make a wild guess ( It should be verified from the source code ):** All the methods of built-in type are using C Language realizes , In fact, they don't call each other , So there is no query priority problem when calling .** That is to say , Ahead “\_\_init\_\_() and \_\_update\_\_() Will implicitly call _\_setitem\_\_() Method ” This statement is not accurate ! These magic methods are actually independent of each other !\_\_init\_\_() Have their own setitem Realize , It doesn't call the parent class \_\_setitem\_\_(), With Subclasses of course \_\_setitem\_\_() It doesn't matter much . To understand logically , Dictionary \_\_init\_\_() Method contains \_\_setitem\_\_() The function of , So we thought the former would call the latter ,** This is the embodiment of habitual thinking ,** However, the actual call relationship may be like this : ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gkok0fm3ucj20u10c574u.jpg) The method on the left opens the door to the language interface and enters the world on the right , To fulfill all its missions there , It does not return to the original interface to query the next instruction ( There is no red line path in the graph ). The reason for not turning back is simple , namely C Code calls between languages are more efficient , The implementation path is shorter , The implementation process is simpler . Empathy ,dict Type get() Method and \_\_getitem\_\_() There's no call relationship , If the subclass only covers \_\_getitem\_\_() And then , When a subclass calls get() When the method is used , It will actually use the parent class get() Method .(PS: On this point ,《 Flowing Python》 And PyPy The description of the document is not accurate , They mistook get() Method will call \_\_getitem\_\_()) That is to say ,Python The built-in method itself does not have a call relationship , Even though they're at the bottom C Language implementation , There may be common logic or methods that can be reused . I think of it. “[Python Why? ](https://github.com/chinesehuazhou/python-whydo)” The series has been analyzed 《[Python Why can support arbitrary truth value judgment ?](https://mp.weixin.qq.com/s/g6jZX0IdH9xpM7BMV3-ToQ)》. Before we write `if xxx` When , It seems to implicitly call \_\_bool\_\_() and \_\_len\_\_() Magic method , But in fact, the program is based on POP_JUMP_IF_FALSE Instructions , It goes straight into pure C Logic of code , There's no call to these magic methods ! therefore , Realizing C After the special methods implemented are independent of each other , Let's go back to subclassing built-in types , There will be new discoveries : ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gkokkxoyapj20z60jcdgy.jpg) Parent \_\_init\_\_() Magic method will break the language interface to achieve its own mission , However, it is similar to subclasses of \_\_setitem\_\_() There is no pathway , That is, the red line path in the figure is not reachable . Special methods go their own way , thus , We'll come to a different conclusion from the previous one :** Actually Python Strictly followed “ Subclass methods precede parent methods ” The principle of succession , It doesn't destroy common sense !** Finally, it is worth mentioning that ,\_\_missing\_\_() It's a special case .《 Flowing Python》 Just a simple and vague sentence , Not too much unfolding . After preliminary experiments , I found that when subclasses define this method ,get() Read nonexistent key When , Normal return None; however \_\_getitem\_\_() and dd['xxx'] Read nonexistent key When , Will be defined by subclass \_\_missing\_\_() Processing . ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gkosoha3krj20f70a63ys.jpg) I haven't had time to analyze , Please leave me a message if you know the answer . ## 5、 Best practices for subclassing built-in types To sum up , There is no problem with subclassing built-in types , It's just that we don't recognize the special method (C The method of language implementation ) The true face of , Will lead to the deviation of the result . So , This calls up a new question :** If you have to inherit the built-in type , What is the best way to practice ?** First , If after inheriting the built-in type , It doesn't rewrite (overwrite) Its special method , There's no problem with subclassing . secondly , If you want to override a particular method after inheritance , Remember to rewrite all the methods you want to change , for example , If you want to change get() Method , It's going to be rewritten get() Method , If you want to change \_\_getitem\_\_() Method , It's going to be rewritten …… however , If we just want to rewrite some logic ( namely C The language part ), If all the special methods used to use the logic have changed , For example, rewrite \_\_setitem\_\_() The logic of , At the same time, initialize and update() Wait for the operation to change , So what to do ? We know that there is no reuse between special methods , That is to say, simply define new \_\_setitem\_\_() It's not enough , So , How can it affect multiple methods at the same time ? PyPy This unofficial Python The version found this problem , Its approach is to make a call to a particular method of a built-in type , Establish a path of connection between them . official Python Of course, I'm aware of this problem , But it doesn't change the nature of the built-in type , It's about offering new solutions :UserString、UserList、UserDict…… ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gkotx6gj14j20rz04taap.jpg) Except for the name , They are basically equivalent to built-in types . The basic logic of these classes is to use Python Realized , It is equivalent to putting the preceding paragraph C Some of the logic of the language interface has moved to Python Interface , Set up a call chain on the left side , In this way , It solves the reuse problem of some special methods . In contrast to the previous example , After adopting a new way of inheritance , The result is as expected : ```python from collections import UserDict class DoppelDict(UserDict): def __setitem__(self, key, value): super().__setitem__(key, [value] * 2) dd = DoppelDict(one=1) # {'one': [1, 1]} dd['two'] = 2 # {'one': [1, 1], 'two': [2, 2]} dd.update(three=3) # {'one': [1, 1], 'two': [2, 2], 'three': [3, 3]} ``` Obviously ,** If you want to inherit str/list/dict And then , The best practice is to inherit `collections` The classes provided by the library .** ## 6、 Summary Write so much , It's time to do ending 了 ~~ In the previous article in this series ,Python Cat from the query order and execution speed of two aspects , Analysis of the “[ Why is the built-in function / Built in types are not everything ](https://mp.weixin.qq.com/s/YtfPlE9JAIS3tpLBGFo5ag)”, This article follows it in the same vein , It also reveals some mysterious and seemingly defective behavior of built-in types . Although this article is from 《 Flowing Python》 The inspiration from the book , But beyond the surface of language , We asked one more question “ Why? ”, Thus further analysis of the phenomenon behind the principle . In short ,** Special methods for building in types are created by C Language independent implementation of , They are Python There is no call relationship in the language interface , So when subclassing an intrinsic type , A particular method that is overridden only affects the method itself , It doesn't affect the effect of other special methods .** If we have a misconception about the relationship between particular methods , You might think that Python Destroyed “ Subclass methods precede parent methods ” The basic principle of inheritance is .( I'm sorry 《 Flowing Python》 and PyPy They all have this wrong perception ) In order to meet the general expectations of built-in types ,Python In the standard library UserString、UserList、UserDict These extension suite classes , It is convenient for programmers to inherit these basic data types . At the end : This article belongs to “[Python Why? ](https://github.com/chinesehuazhou/python-whydo)” series (Python Cat products ), The series focuses on Python The grammar of 、 Design and development , One by one “ Why? ” This is the starting point , Try to show Python The charm of . If you have other topics of interest , Welcome to fill in 《[Python Why are 100000 of them ?](https://mp.weixin.qq.com/s/jobdpO7BWWON0ruLNpn31Q) 》 In the questionnaire in . ![](http://ww1.sinaimg.cn/large/68b02e3bgy1gfffh3g28lj2076076q3e.jpg) Public number 【**Python Cat **】, This is a series of excellent articles , Yes Python Why series 、 Meow philosophy Cat Series 、Python Advanced Series 、 Good book recommendation series 、 Technical writing 、 High quality English recommendation and translation, etc , Welcome off
版权声明
本文为[itread01]所创,转载请带上原文链接,感谢

  1. 利用Python爬虫获取招聘网站职位信息
  2. Using Python crawler to obtain job information of recruitment website
  3. Several highly rated Python libraries arrow, jsonpath, psutil and tenacity are recommended
  4. Python装饰器
  5. Python实现LDAP认证
  6. Python decorator
  7. Implementing LDAP authentication with Python
  8. Vscode configures Python development environment!
  9. In Python, how dare you say you can't log module? ️
  10. 我收藏的有关Python的电子书和资料
  11. python 中 lambda的一些tips
  12. python中字典的一些tips
  13. python 用生成器生成斐波那契数列
  14. python脚本转pyc踩了个坑。。。
  15. My collection of e-books and materials about Python
  16. Some tips of lambda in Python
  17. Some tips of dictionary in Python
  18. Using Python generator to generate Fibonacci sequence
  19. The conversion of Python script to PyC stepped on a pit...
  20. Python游戏开发,pygame模块,Python实现扫雷小游戏
  21. Python game development, pyGame module, python implementation of minesweeping games
  22. Python实用工具,email模块,Python实现邮件远程控制自己电脑
  23. Python utility, email module, python realizes mail remote control of its own computer
  24. 毫无头绪的自学Python,你可能连门槛都摸不到!【最佳学习路线】
  25. Python读取二进制文件代码方法解析
  26. Python字典的实现原理
  27. Without a clue, you may not even touch the threshold【 Best learning route]
  28. Parsing method of Python reading binary file code
  29. Implementation principle of Python dictionary
  30. You must know the function of pandas to parse JSON data - JSON_ normalize()
  31. Python实用案例,私人定制,Python自动化生成爱豆专属2021日历
  32. Python practical case, private customization, python automatic generation of Adu exclusive 2021 calendar
  33. 《Python实例》震惊了,用Python这么简单实现了聊天系统的脏话,广告检测
  34. "Python instance" was shocked and realized the dirty words and advertisement detection of the chat system in Python
  35. Convolutional neural network processing sequence for Python deep learning
  36. Python data structure and algorithm (1) -- enum type enum
  37. 超全大厂算法岗百问百答(推荐系统/机器学习/深度学习/C++/Spark/python)
  38. 【Python进阶】你真的明白NumPy中的ndarray吗?
  39. All questions and answers for algorithm posts of super large factories (recommended system / machine learning / deep learning / C + + / spark / Python)
  40. [advanced Python] do you really understand ndarray in numpy?
  41. 【Python进阶】Python进阶专栏栏主自述:不忘初心,砥砺前行
  42. [advanced Python] Python advanced column main readme: never forget the original intention and forge ahead
  43. python垃圾回收和缓存管理
  44. java调用Python程序
  45. java调用Python程序
  46. Python常用函数有哪些?Python基础入门课程
  47. Python garbage collection and cache management
  48. Java calling Python program
  49. Java calling Python program
  50. What functions are commonly used in Python? Introduction to Python Basics
  51. Python basic knowledge
  52. Anaconda5.2 安装 Python 库(MySQLdb)的方法
  53. Python实现对脑电数据情绪分析
  54. Anaconda 5.2 method of installing Python Library (mysqldb)
  55. Python implements emotion analysis of EEG data
  56. Master some advanced usage of Python in 30 seconds, which makes others envy it
  57. python爬取百度图片并对图片做一系列处理
  58. Python crawls Baidu pictures and does a series of processing on them
  59. python链接mysql数据库
  60. Python link MySQL database