一、类也是对象

当我们定义一个变量或者函数的时候,我们可以在globals()的返回值字典中找到响应的映射:

  1. def A():
  2. print("This is function A")
  3.  
  4. myname = "Leo"
  5.  
  6. print(globals())

我们可以得到以下结果:

  1. {
  2. '__name__': '__main__',
  3. '__doc__': None,
  4. '__package__': None,
  5. '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021F09971CC0>,
  6. '__spec__': None,
  7. '__annotations__': {},
  8. '__builtins__': <module 'builtins' (built-in)>,
  9. '__file__': 'D:/pycharm_project/leo1201/basic_class/test.py',
  10. '__cached__': None,
  11. 'A': <function A at 0x0000021F099AC1E0>,
  12. 'myname': 'Leo'
  13. }

我们可以发现我们定义的函数A和变量myname都在这个字典中,这个字典中记录的映射,实际上就是全局变量(也就是可以直接调用的对象)。

那么我们定义的类是什么呢:

  1. class B(object):
  2. pass
  3.  
  4. print(globals())

得到的结果:

  1. {
  2. '__name__': '__main__',
  3. '__doc__': None,
  4. '__package__': None,
  5. '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021F09971CC0>,
  6. '__spec__': None,
  7. '__annotations__': {},
  8. '__builtins__': <module 'builtins' (built-in)>,
  9. '__file__': 'D:/pycharm_project/leo1201/basic_class/test.py',
  10. '__cached__': None,
  11. 'B': <class '__main__.B'>
  12. }

我们可以看到,类B也在该字典中。所以,我们说类实际上也是一个全局对象,只是这个对象的功能可以生成其他的对象而已。

二、内建属性

在上面所看到的globals()返回的字典中,我们并未看到我们常用的print()等直接调用的函数,这是因为这些内建函数都在'__builtin__'中:

  1. global_dict = globals()
  2. print(global_dict['__builtins__']) # 打印 <module 'builtins' (built-in)>

我们打印一下__builtin__字典:

  1. global_dict = globals()
  2. print(global_dict['__builtins__'].__dict__)

得到一个很长的字典:

  1. {
  2. '__name__': 'builtins',
  3. '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.",
  4. '__package__': '',
  5. '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
  6. '__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>),
  7. '__build_class__': <built-in function __build_class__>,
  8. '__import__': <built-in function __import__>,
  9. 'abs': <built-in function abs>,
  10. 'all': <built-in function all>,
  11. 'any': <built-in function any>,
  12. 'ascii': <built-in function ascii>,
  13. 'bin': <built-in function bin>,
  14. 'breakpoint': <built-in function breakpoint>,
  15. 'callable': <built-in function callable>,
  16. 'chr': <built-in function chr>,
  17. 'compile': <built-in function compile>,
  18. 'delattr': <built-in function delattr>,
  19. 'dir': <built-in function dir>,
  20. 'divmod': <built-in function divmod>,
  21. 'eval': <built-in function eval>,
  22. 'exec': <built-in function exec>,
  23. 'format': <built-in function format>,
  24. 'getattr': <built-in function getattr>,
  25. 'globals': <built-in function globals>,
  26. 'hasattr': <built-in function hasattr>,
  27. 'hash': <built-in function hash>,
  28. 'hex': <built-in function hex>,
  29. 'id': <built-in function id>,
  30. 'input': <built-in function input>,
  31. 'isinstance': <built-in function isinstance>,
  32. 'issubclass': <built-in function issubclass>,
  33. 'iter': <built-in function iter>,
  34. 'len': <built-in function len>,
  35. 'locals': <built-in function locals>,
  36. 'max': <built-in function max>,
  37. 'min': <built-in function min>,
  38. 'next': <built-in function next>,
  39. 'oct': <built-in function oct>,
  40. 'ord': <built-in function ord>,
  41. 'pow': <built-in function pow>,
  42. 'print': <built-in function print>,
  43. 'repr': <built-in function repr>,
  44. 'round': <built-in function round>,
  45. 'setattr': <built-in function setattr>,
  46. 'sorted': <built-in function sorted>,
  47. 'sum': <built-in function sum>,
  48. 'vars': <built-in function vars>,
  49. 'None': None, 'Ellipsis': Ellipsis,
  50. 'NotImplemented': NotImplemented,
  51. 'False': False, 'True': True,
  52. 'bool': <class 'bool'>,
  53. 'memoryview': <class 'memoryview'>,
  54. 'bytearray': <class 'bytearray'>,
  55. 'bytes': <class 'bytes'>,
  56. 'classmethod': <class 'classmethod'>,
  57. 'complex': <class 'complex'>,
  58. 'dict': <class 'dict'>,
  59. 'enumerate': <class 'enumerate'>,
  60. 'filter': <class 'filter'>,
  61. 'float': <class 'float'>,
  62. 'frozenset': <class 'frozenset'>,
  63. 'property': <class 'property'>,
  64. 'int': <class 'int'>,
  65. 'list': <class 'list'>,
  66. 'map': <class 'map'>,
  67. 'object': <class 'object'>,
  68. 'range': <class 'range'>,
  69. 'reversed': <class 'reversed'>,
  70. 'set': <class 'set'>,
  71. 'slice': <class 'slice'>,
  72. 'staticmethod': <class 'staticmethod'>,
  73. 'str': <class 'str'>,
  74. 'super': <class 'super'>,
  75. 'tuple': <class 'tuple'>,
  76. 'type': <class 'type'>,
  77. 'zip': <class 'zip'>,
  78. '__debug__': True,
  79. 'BaseException': <class 'BaseException'>,
  80. 'Exception': <class 'Exception'>,
  81. 'TypeError': <class 'TypeError'>,
  82. 'StopAsyncIteration': <class 'StopAsyncIteration'>,
  83. 'StopIteration': <class 'StopIteration'>,
  84. 'GeneratorExit': <class 'GeneratorExit'>,
  85. 'SystemExit': <class 'SystemExit'>,
  86. 'KeyboardInterrupt': <class 'KeyboardInterrupt'>,
  87. 'ImportError': <class 'ImportError'>,
  88. 'ModuleNotFoundError': <class 'ModuleNotFoundError'>,
  89. 'OSError': <class 'OSError'>,
  90. 'EnvironmentError': <class 'OSError'>,
  91. 'IOError': <class 'OSError'>,
  92. 'WindowsError': <class 'OSError'>,
  93. 'EOFError': <class 'EOFError'>,
  94. 'RuntimeError': <class 'RuntimeError'>,
  95. 'RecursionError': <class 'RecursionError'>,
  96. 'NotImplementedError': <class 'NotImplementedError'>,
  97. 'NameError': <class 'NameError'>,
  98. 'UnboundLocalError': <class 'UnboundLocalError'>,
  99. 'AttributeError': <class 'AttributeError'>,
  100. 'SyntaxError': <class 'SyntaxError'>,
  101. 'IndentationError': <class 'IndentationError'>,
  102. 'TabError': <class 'TabError'>,
  103. 'LookupError': <class 'LookupError'>,
  104. 'IndexError': <class 'IndexError'>,
  105. 'KeyError': <class 'KeyError'>,
  106. 'ValueError': <class 'ValueError'>,
  107. 'UnicodeError': <class 'UnicodeError'>,
  108. 'UnicodeEncodeError': <class 'UnicodeEncodeError'>,
  109. 'UnicodeDecodeError': <class 'UnicodeDecodeError'>,
  110. 'UnicodeTranslateError': <class 'UnicodeTranslateError'>,
  111. 'AssertionError': <class 'AssertionError'>,
  112. 'ArithmeticError': <class 'ArithmeticError'>,
  113. 'FloatingPointError': <class 'FloatingPointError'>,
  114. 'OverflowError': <class 'OverflowError'>,
  115. 'ZeroDivisionError': <class 'ZeroDivisionError'>,
  116. 'SystemError': <class 'SystemError'>,
  117. 'ReferenceError': <class 'ReferenceError'>,
  118. 'MemoryError': <class 'MemoryError'>,
  119. 'BufferError': <class 'BufferError'>,
  120. 'Warning': <class 'Warning'>,
  121. 'UserWarning': <class 'UserWarning'>,
  122. 'DeprecationWarning': <class 'DeprecationWarning'>,
  123. 'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>,
  124. 'SyntaxWarning': <class 'SyntaxWarning'>,
  125. 'RuntimeWarning': <class 'RuntimeWarning'>,
  126. 'FutureWarning': <class 'FutureWarning'>,
  127. 'ImportWarning': <class 'ImportWarning'>,
  128. 'UnicodeWarning': <class 'UnicodeWarning'>,
  129. 'BytesWarning': <class 'BytesWarning'>,
  130. 'ResourceWarning': <class 'ResourceWarning'>,
  131. 'ConnectionError': <class 'ConnectionError'>,
  132. 'BlockingIOError': <class 'BlockingIOError'>,
  133. 'BrokenPipeError': <class 'BrokenPipeError'>,
  134. 'ChildProcessError': <class 'ChildProcessError'>,
  135. 'ConnectionAbortedError': <class 'ConnectionAbortedError'>,
  136. 'ConnectionRefusedError': <class 'ConnectionRefusedError'>,
  137. 'ConnectionResetError': <class 'ConnectionResetError'>,
  138. 'FileExistsError': <class 'FileExistsError'>,
  139. 'FileNotFoundError': <class 'FileNotFoundError'>,
  140. 'IsADirectoryError': <class 'IsADirectoryError'>,
  141. 'NotADirectoryError': <class 'NotADirectoryError'>,
  142. 'InterruptedError': <class 'InterruptedError'>,
  143. 'PermissionError': <class 'PermissionError'>,
  144. 'ProcessLookupError': <class 'ProcessLookupError'>,
  145. 'TimeoutError': <class 'TimeoutError'>,
  146. 'open': <built-in function open>,
  147. 'quit': Use quit() or Ctrl-Z plus Return to exit,
  148. 'exit': Use exit() or Ctrl-Z plus Return to exit,
  149. 'copyright': Copyright (c) 2001-2018 Python Software Foundation.
  150. All Rights Reserved.
  151. }

这个字典中包含着python的所有内建功能。我们可以从中找到print()、open()、exit()、False、Bool、dir()等我们常用的内建函数,以及很多异常类。

我们通过使用该字典,可以直接队其中的内建函数进行调用:

  1. global_dict = globals()
  2. builtin_dict = global_dict['__builtins__'].__dict__
  3. builtin_dict['print']("Hello Builtin functions") # 打印 Hello Builtin functions

所以,我们平时在使用内建函数的时候,Python实际上就是在这个字典中查找我们调用的函数名是否存在,存在则调用,不存在则报错。

三、元类

我们知道,类可以创建实例对象。从前面我们可以看出,类实际上也是一种对象,那么类是谁的对象呢??答案是元类。

当我们平时在创建类时:

  1. class Test1():
  2. num1 = 100
  3. num2 = 200
  4.  
  5. help(Test1)

通过help我们可以看到:

  1. class Test1(builtins.object)
  2. | Data descriptors defined here:
  3. |
  4. | __dict__
  5. | dictionary for instance variables (if defined)
  6. |
  7. | __weakref__
  8. | list of weak references to the object (if defined)
  9. |
  10. | ----------------------------------------------------------------------
  11. | Data and other attributes defined here:
  12. |
  13. | num1 = 100
  14. |
  15. | num2 = 200

在Python中,元类就是type类,我们使用type来创建一个普通类:

  1. Test2 = type('Test2', (), {'num1': 100, 'num2': 200})
  2. help(Test2)

通过help可以看到:

  1. class Test2(builtins.object)
  2. | Data descriptors defined here:
  3. |
  4. | __dict__
  5. | dictionary for instance variables (if defined)
  6. |
  7. | __weakref__
  8. | list of weak references to the object (if defined)
  9. |
  10. | ----------------------------------------------------------------------
  11. | Data and other attributes defined here:
  12. |
  13. | num1 = 100
  14. |
  15. | num2 = 200

我们可以看到Test1和Test2基本是一样的。我们在程序中通过class关键字创建类,实际上和type()创建一个类,效果一样。

在 Test2 = type('Test2', (), {'num1': 100, 'num2': 200}) 中,第一个参数是类名,第二个参数是父类,第三个参数是属性和方法(用字典列出)。

这里注意:我们给一个类取名叫"Test2",那么type的返回值我们也应该用"Test2"来接收(当然也可以用其他的名字),如果不一致的话:

  1. Test222 = type('Test2', (), {'num1': 100, 'num2': 200})
  2. help(Test222)
  3. t = Test222()
  4. # t = Test2() # 报错

但在help中:

  1. class Test2(builtins.object)
  2. | Data descriptors defined here:
  3. |
  4. | __dict__
  5. | dictionary for instance variables (if defined)
  6. |
  7. | __weakref__
  8. | list of weak references to the object (if defined)
  9. |
  10. | ----------------------------------------------------------------------
  11. | Data and other attributes defined here:
  12. |
  13. | num1 = 100
  14. |
  15. | num2 = 200

所以,我们尽量采用一致的名字, 避免出错。

如果一个类继承于Test2:

  1. Test3 = type("Test3", (Test2,), {})

类中的各种成员方法:

  1. def func1(self):
  2. print("This is method func1")
  3.  
  4. @classmethod
  5. def func2(cls):
  6. print("This is class method func2")
  7.  
  8. @staticmethod
  9. def func3():
  10. print("This is static method func3")
  11.  
  12. Test2 = type('Test2', (), {"func1": func1, "func2": func2, "func3": func3})
  13. t = Test2()
  14. t.func1()
  15. Test2.func2()
  16. t.func3()

四、元类什么时候用

元类一般很少使用

我们可以自定义元类,并用于创建普通类:

第一种,用函数来修改属性名(在type运行之前):

  1. def upper_attr(class_name, class_parents, class_attr):
  2. new_attr = {}
  3. for name, value in class_attr.items():
  4. if not name.startswith("__"):
  5. new_attr[name.upper()] = value
  6.  
  7. return type(class_name, class_parents, new_attr)
  8.  
  9. class Foo(object, metaclass=upper_attr):
  10. bar = 'pig'
  11.  
  12. print(hasattr(Foo, "bar")) # 打印 Flase
  13. print(hasattr(Foo, "BAR")) # 打印 True
  14.  
  15. f = Foo()
  16. print(f.BAR) # 打印 pig

upper_attr会修改属性的名称为大写,然后再使用type生成一个Foo类。

第二种,定义一个继承于type的元类来创建Foo类:

  1. class UpperAttrMetaClass(type):
  2. def __new__(cls, class_name, class_parents, class_attr):
  3. print("Here is new")
  4. new_attr = {}
  5. for name, value in class_attr.items():
  6. if not name.startswith("__"):
  7. new_attr[name.upper()] = value
  8.  
  9. return type(class_name, class_parents, new_attr)
  10.  
  11. class Foo(object, metaclass=UpperAttrMetaClass):
  12. def __init__(self, abv):
  13. self.abv = abv
  14. print("Here is init")
  15.  
  16. bar = 'pig'
  17.  
  18. print(hasattr(Foo, "bar")) # 打印 Flase
  19. print(hasattr(Foo, "BAR")) # 打印 True
  20.  
  21. f = Foo()
  22. print(f.BAR) # 打印 pig

UpperAttrMetaClass继承于type,则他就变成了一个元类,由于元类在创建Foo类时会调用__new__函数,所以,我们在__new__函数中做了一些额外的操作。

五、使用__new__实现单例模式(引申)

既然我们可以在类创建对象之前在__new__中做事情,那么我们可以在__new__中判断这个类是否已经存在实例对象,如果存在则直接返回已存在的对象,如果不存在才创建新的对象,这就实现了单例模式。

  1. # -*- coding: utf-8 -*-
  2. import threading
  3.  
  4. class Singleton(object):
  5. _lock = threading.Lock()
  6.  
  7. def __new__(cls, *args, **kwargs):
  8. if not hasattr(Singleton, "_instance"):
  9. with Singleton._lock: # 加锁防止多线程环境中两个线程同时判断到上一行代码为True,同时创建该类的实例
  10. if not hasattr(Singleton, "_instance"):
  11. # 调用object类的__new__方法
  12. Singleton._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
  13. return Singleton._instance
  14.  
  15. def test(number):
  16. s = Singleton()
  17. print str(number) + ": " + str(id(s))
  18.  
  19. for i in range(10):
  20. t = threading.Thread(target=test, args=(i, ))
  21. t.start()

[Python之路] 元类(引申 单例模式)的更多相关文章

  1. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  2. 深刻理解Python中的元类(metaclass)以及元类实现单例模式

    在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...

  3. Python元类(metaclass)以及元类实现单例模式

    这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...

  4. python基础——使用元类

    python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...

  5. Python基础:元类

    一.概述 二.经典阐述 三.核心总结 1.类的创建过程 2.元类的使用惯例 四.简单案例 1.默认行为 2.使用元类 五.实践为王 一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯 ...

  6. Python中的元类(metaclass)

    推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...

  7. 什么是python中的元类

    所属网站分类: python高级 > 面向对象 作者:goodbody 原文链接: http://www.pythonheidong.com/blog/article/11/ 来源:python ...

  8. Python之面向对象元类

    Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...

  9. Python 中的元类到底是什么?这篇恐怕是最清楚的了

    类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...

随机推荐

  1. Jenkins+SVN持续环境搭建

    需要三台不同环境的服务器,SVN.Jenkins.Tomcat 1.SVN搭建 1.Subversion服务器(SVN服务器) 2.项目对应的版本库 3.版本库中钩子程序(用于触发构建命令) 在我以前 ...

  2. vim 常用基本

    vim 基本操作 0. 基本操作 :w // 保存当前文件 :q // 退出vim :wq // 保存退出 :w! // 强制保存当前文件 :q! // 强制退出(可以忽略修改) :!cmd // 执 ...

  3. php用逗号格式化数字

    今日工作需要格式化数字显示当前商品价格,比如2335.32,需要格式化为2,335.32这样显示.我写了一个函数.总感觉这么简单的功能,但是却需要30多行代码来完成. <?php/**** * ...

  4. thinkPHP连接数据库报错:PDOException in Connection.php line 295

    跑去网上找了N多方法来尝试,重装apache.mysql.安装集成软件都试过了.错误一样. 后来细细分析,PDOException in Connection指的不就是PDO异常吗? 然后去了解了一些 ...

  5. ASP.NET练习③——AspNetChosmePager

    aspx代码: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="_Chosm ...

  6. dev chart使用

    public class LineChartHelp { #region 折线图 /// <summary> /// 创建折线图 /// </summary> public v ...

  7. Http请求头缓存设置方法

    1.直接在.aspx页面中设置最直接的,在.aspx页面中添加一行如下代码: <%@ OutputCache Duration="3600" VaryByParam=&quo ...

  8. js判断一个 object 对象是否为空

    方法一:使用for...in for...in... 遍历属性,为真则为“非空数组”:否则为“空数组” for (var i in obj) { return true  // 如果不为空,则会执行到 ...

  9. Oracle数据库中的变量

    Oracle数据库中的变量 来源:https://blog.csdn.net/wahaa591/article/details/46772769 1.define(即host变量) define va ...

  10. 如何为 esp32 编译和配置及烧写 MicroPython 固件。

    MicroPython 在 esp-idf (esp32) 上编译固件 esp32 编译 micropython 的固件相关的资料应该很多吧,我也会出一篇,但会额外讲一些 linux 的东西的. 资料 ...