[Python之路] 元类(引申 单例模式)
一、类也是对象
当我们定义一个变量或者函数的时候,我们可以在globals()的返回值字典中找到响应的映射:
def A():
print("This is function A") myname = "Leo" print(globals())
我们可以得到以下结果:
{
'__name__': '__main__',
'__doc__': None,
'__package__': None,
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021F09971CC0>,
'__spec__': None,
'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__file__': 'D:/pycharm_project/leo1201/basic_class/test.py',
'__cached__': None,
'A': <function A at 0x0000021F099AC1E0>,
'myname': 'Leo'
}
我们可以发现我们定义的函数A和变量myname都在这个字典中,这个字典中记录的映射,实际上就是全局变量(也就是可以直接调用的对象)。
那么我们定义的类是什么呢:
class B(object):
pass print(globals())
得到的结果:
{
'__name__': '__main__',
'__doc__': None,
'__package__': None,
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021F09971CC0>,
'__spec__': None,
'__annotations__': {},
'__builtins__': <module 'builtins' (built-in)>,
'__file__': 'D:/pycharm_project/leo1201/basic_class/test.py',
'__cached__': None,
'B': <class '__main__.B'>
}
我们可以看到,类B也在该字典中。所以,我们说类实际上也是一个全局对象,只是这个对象的功能可以生成其他的对象而已。
二、内建属性
在上面所看到的globals()返回的字典中,我们并未看到我们常用的print()等直接调用的函数,这是因为这些内建函数都在'__builtin__'中:
global_dict = globals()
print(global_dict['__builtins__']) # 打印 <module 'builtins' (built-in)>
我们打印一下__builtin__字典:
global_dict = globals()
print(global_dict['__builtins__'].__dict__)
得到一个很长的字典:
{
'__name__': 'builtins',
'__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.",
'__package__': '',
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': ModuleSpec(name='builtins', loader=<class '_frozen_importlib.BuiltinImporter'>),
'__build_class__': <built-in function __build_class__>,
'__import__': <built-in function __import__>,
'abs': <built-in function abs>,
'all': <built-in function all>,
'any': <built-in function any>,
'ascii': <built-in function ascii>,
'bin': <built-in function bin>,
'breakpoint': <built-in function breakpoint>,
'callable': <built-in function callable>,
'chr': <built-in function chr>,
'compile': <built-in function compile>,
'delattr': <built-in function delattr>,
'dir': <built-in function dir>,
'divmod': <built-in function divmod>,
'eval': <built-in function eval>,
'exec': <built-in function exec>,
'format': <built-in function format>,
'getattr': <built-in function getattr>,
'globals': <built-in function globals>,
'hasattr': <built-in function hasattr>,
'hash': <built-in function hash>,
'hex': <built-in function hex>,
'id': <built-in function id>,
'input': <built-in function input>,
'isinstance': <built-in function isinstance>,
'issubclass': <built-in function issubclass>,
'iter': <built-in function iter>,
'len': <built-in function len>,
'locals': <built-in function locals>,
'max': <built-in function max>,
'min': <built-in function min>,
'next': <built-in function next>,
'oct': <built-in function oct>,
'ord': <built-in function ord>,
'pow': <built-in function pow>,
'print': <built-in function print>,
'repr': <built-in function repr>,
'round': <built-in function round>,
'setattr': <built-in function setattr>,
'sorted': <built-in function sorted>,
'sum': <built-in function sum>,
'vars': <built-in function vars>,
'None': None, 'Ellipsis': Ellipsis,
'NotImplemented': NotImplemented,
'False': False, 'True': True,
'bool': <class 'bool'>,
'memoryview': <class 'memoryview'>,
'bytearray': <class 'bytearray'>,
'bytes': <class 'bytes'>,
'classmethod': <class 'classmethod'>,
'complex': <class 'complex'>,
'dict': <class 'dict'>,
'enumerate': <class 'enumerate'>,
'filter': <class 'filter'>,
'float': <class 'float'>,
'frozenset': <class 'frozenset'>,
'property': <class 'property'>,
'int': <class 'int'>,
'list': <class 'list'>,
'map': <class 'map'>,
'object': <class 'object'>,
'range': <class 'range'>,
'reversed': <class 'reversed'>,
'set': <class 'set'>,
'slice': <class 'slice'>,
'staticmethod': <class 'staticmethod'>,
'str': <class 'str'>,
'super': <class 'super'>,
'tuple': <class 'tuple'>,
'type': <class 'type'>,
'zip': <class 'zip'>,
'__debug__': True,
'BaseException': <class 'BaseException'>,
'Exception': <class 'Exception'>,
'TypeError': <class 'TypeError'>,
'StopAsyncIteration': <class 'StopAsyncIteration'>,
'StopIteration': <class 'StopIteration'>,
'GeneratorExit': <class 'GeneratorExit'>,
'SystemExit': <class 'SystemExit'>,
'KeyboardInterrupt': <class 'KeyboardInterrupt'>,
'ImportError': <class 'ImportError'>,
'ModuleNotFoundError': <class 'ModuleNotFoundError'>,
'OSError': <class 'OSError'>,
'EnvironmentError': <class 'OSError'>,
'IOError': <class 'OSError'>,
'WindowsError': <class 'OSError'>,
'EOFError': <class 'EOFError'>,
'RuntimeError': <class 'RuntimeError'>,
'RecursionError': <class 'RecursionError'>,
'NotImplementedError': <class 'NotImplementedError'>,
'NameError': <class 'NameError'>,
'UnboundLocalError': <class 'UnboundLocalError'>,
'AttributeError': <class 'AttributeError'>,
'SyntaxError': <class 'SyntaxError'>,
'IndentationError': <class 'IndentationError'>,
'TabError': <class 'TabError'>,
'LookupError': <class 'LookupError'>,
'IndexError': <class 'IndexError'>,
'KeyError': <class 'KeyError'>,
'ValueError': <class 'ValueError'>,
'UnicodeError': <class 'UnicodeError'>,
'UnicodeEncodeError': <class 'UnicodeEncodeError'>,
'UnicodeDecodeError': <class 'UnicodeDecodeError'>,
'UnicodeTranslateError': <class 'UnicodeTranslateError'>,
'AssertionError': <class 'AssertionError'>,
'ArithmeticError': <class 'ArithmeticError'>,
'FloatingPointError': <class 'FloatingPointError'>,
'OverflowError': <class 'OverflowError'>,
'ZeroDivisionError': <class 'ZeroDivisionError'>,
'SystemError': <class 'SystemError'>,
'ReferenceError': <class 'ReferenceError'>,
'MemoryError': <class 'MemoryError'>,
'BufferError': <class 'BufferError'>,
'Warning': <class 'Warning'>,
'UserWarning': <class 'UserWarning'>,
'DeprecationWarning': <class 'DeprecationWarning'>,
'PendingDeprecationWarning': <class 'PendingDeprecationWarning'>,
'SyntaxWarning': <class 'SyntaxWarning'>,
'RuntimeWarning': <class 'RuntimeWarning'>,
'FutureWarning': <class 'FutureWarning'>,
'ImportWarning': <class 'ImportWarning'>,
'UnicodeWarning': <class 'UnicodeWarning'>,
'BytesWarning': <class 'BytesWarning'>,
'ResourceWarning': <class 'ResourceWarning'>,
'ConnectionError': <class 'ConnectionError'>,
'BlockingIOError': <class 'BlockingIOError'>,
'BrokenPipeError': <class 'BrokenPipeError'>,
'ChildProcessError': <class 'ChildProcessError'>,
'ConnectionAbortedError': <class 'ConnectionAbortedError'>,
'ConnectionRefusedError': <class 'ConnectionRefusedError'>,
'ConnectionResetError': <class 'ConnectionResetError'>,
'FileExistsError': <class 'FileExistsError'>,
'FileNotFoundError': <class 'FileNotFoundError'>,
'IsADirectoryError': <class 'IsADirectoryError'>,
'NotADirectoryError': <class 'NotADirectoryError'>,
'InterruptedError': <class 'InterruptedError'>,
'PermissionError': <class 'PermissionError'>,
'ProcessLookupError': <class 'ProcessLookupError'>,
'TimeoutError': <class 'TimeoutError'>,
'open': <built-in function open>,
'quit': Use quit() or Ctrl-Z plus Return to exit,
'exit': Use exit() or Ctrl-Z plus Return to exit,
'copyright': Copyright (c) 2001-2018 Python Software Foundation.
All Rights Reserved.
}
这个字典中包含着python的所有内建功能。我们可以从中找到print()、open()、exit()、False、Bool、dir()等我们常用的内建函数,以及很多异常类。
我们通过使用该字典,可以直接队其中的内建函数进行调用:
global_dict = globals()
builtin_dict = global_dict['__builtins__'].__dict__
builtin_dict['print']("Hello Builtin functions") # 打印 Hello Builtin functions
所以,我们平时在使用内建函数的时候,Python实际上就是在这个字典中查找我们调用的函数名是否存在,存在则调用,不存在则报错。
三、元类
我们知道,类可以创建实例对象。从前面我们可以看出,类实际上也是一种对象,那么类是谁的对象呢??答案是元类。
当我们平时在创建类时:
class Test1():
num1 = 100
num2 = 200 help(Test1)
通过help我们可以看到:
class Test1(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| num1 = 100
|
| num2 = 200
在Python中,元类就是type类,我们使用type来创建一个普通类:
Test2 = type('Test2', (), {'num1': 100, 'num2': 200})
help(Test2)
通过help可以看到:
class Test2(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| num1 = 100
|
| num2 = 200
我们可以看到Test1和Test2基本是一样的。我们在程序中通过class关键字创建类,实际上和type()创建一个类,效果一样。
在 Test2 = type('Test2', (), {'num1': 100, 'num2': 200}) 中,第一个参数是类名,第二个参数是父类,第三个参数是属性和方法(用字典列出)。
这里注意:我们给一个类取名叫"Test2",那么type的返回值我们也应该用"Test2"来接收(当然也可以用其他的名字),如果不一致的话:
Test222 = type('Test2', (), {'num1': 100, 'num2': 200})
help(Test222)
t = Test222()
# t = Test2() # 报错
但在help中:
class Test2(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| ----------------------------------------------------------------------
| Data and other attributes defined here:
|
| num1 = 100
|
| num2 = 200
所以,我们尽量采用一致的名字, 避免出错。
如果一个类继承于Test2:
Test3 = type("Test3", (Test2,), {})
类中的各种成员方法:
def func1(self):
print("This is method func1") @classmethod
def func2(cls):
print("This is class method func2") @staticmethod
def func3():
print("This is static method func3") Test2 = type('Test2', (), {"func1": func1, "func2": func2, "func3": func3})
t = Test2()
t.func1()
Test2.func2()
t.func3()
四、元类什么时候用
元类一般很少使用
我们可以自定义元类,并用于创建普通类:
第一种,用函数来修改属性名(在type运行之前):
def upper_attr(class_name, class_parents, class_attr):
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value return type(class_name, class_parents, new_attr) class Foo(object, metaclass=upper_attr):
bar = 'pig' print(hasattr(Foo, "bar")) # 打印 Flase
print(hasattr(Foo, "BAR")) # 打印 True f = Foo()
print(f.BAR) # 打印 pig
upper_attr会修改属性的名称为大写,然后再使用type生成一个Foo类。
第二种,定义一个继承于type的元类来创建Foo类:
class UpperAttrMetaClass(type):
def __new__(cls, class_name, class_parents, class_attr):
print("Here is new")
new_attr = {}
for name, value in class_attr.items():
if not name.startswith("__"):
new_attr[name.upper()] = value return type(class_name, class_parents, new_attr) class Foo(object, metaclass=UpperAttrMetaClass):
def __init__(self, abv):
self.abv = abv
print("Here is init") bar = 'pig' print(hasattr(Foo, "bar")) # 打印 Flase
print(hasattr(Foo, "BAR")) # 打印 True f = Foo()
print(f.BAR) # 打印 pig
UpperAttrMetaClass继承于type,则他就变成了一个元类,由于元类在创建Foo类时会调用__new__函数,所以,我们在__new__函数中做了一些额外的操作。
五、使用__new__实现单例模式(引申)
既然我们可以在类创建对象之前在__new__中做事情,那么我们可以在__new__中判断这个类是否已经存在实例对象,如果存在则直接返回已存在的对象,如果不存在才创建新的对象,这就实现了单例模式。
# -*- coding: utf-8 -*-
import threading class Singleton(object):
_lock = threading.Lock() def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._lock: # 加锁防止多线程环境中两个线程同时判断到上一行代码为True,同时创建该类的实例
if not hasattr(Singleton, "_instance"):
# 调用object类的__new__方法
Singleton._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return Singleton._instance def test(number):
s = Singleton()
print str(number) + ": " + str(id(s)) for i in range(10):
t = threading.Thread(target=test, args=(i, ))
t.start()
[Python之路] 元类(引申 单例模式)的更多相关文章
- [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式
使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...
- 深刻理解Python中的元类(metaclass)以及元类实现单例模式
在理解元类之前,你需要先掌握Python中的类.Python中类的概念借鉴于Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.在Python中这一点仍 ...
- Python元类(metaclass)以及元类实现单例模式
这里将一篇写的非常好的文章基本照搬过来吧,这是一篇在Stack overflow上很热的帖子,我看http://blog.jobbole.com/21351/这篇博客对其进行了翻译. 一.理解类也是对 ...
- python基础——使用元类
python基础——使用元类 type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello. ...
- Python基础:元类
一.概述 二.经典阐述 三.核心总结 1.类的创建过程 2.元类的使用惯例 四.简单案例 1.默认行为 2.使用元类 五.实践为王 一.概述 Python虽然是多范式的编程语言,但它的数据模型却是 纯 ...
- Python中的元类(metaclass)
推荐+收藏:深刻理解Python中的元类(metaclass) 做一些笔记学习学习: 在大多数编程语言中,类就是用来描述如何生成一个对象的代码段,在Python中类也是一个对象,这个(类)对象自身拥有 ...
- 什么是python中的元类
所属网站分类: python高级 > 面向对象 作者:goodbody 原文链接: http://www.pythonheidong.com/blog/article/11/ 来源:python ...
- Python之面向对象元类
Python之面向对象元类 call方法: class People: def __init__(self,name): self.name=name # def __call__(self, *ar ...
- Python 中的元类到底是什么?这篇恐怕是最清楚的了
类作为对象 在理解元类之前,您需要掌握 Python 的类.Python 从 Smalltalk 语言中借用了一个非常特殊的类概念. 在大多数语言中,类只是描述如何产生对象的代码段.在 Python ...
随机推荐
- # [洛谷1337] 吊打XXX/平衡点 (模拟退火)
[洛谷1337] 吊打XXX/平衡点 (模拟退火) 题意 n个重物(x,y,w),求平衡时x的位置(x,y) 分析 模拟退火基础题,基于随机数的优化算法,时间复杂度玄学,参数玄学,能不能AC看脸,当然 ...
- spark内核篇-task数与并行度
每一个 spark job 根据 shuffle 划分 stage,每个 stage 形成一个或者多个 taskSet,了解了每个 stage 需要运行多少个 task,有助于我们优化 spark 运 ...
- node 环境安装
记录一下, 方便自己需要时用, 免得到处找 1. 官网下载安装node(选择LTS长期支持版本), 一路点击next即可(傻瓜式安装) 2. 验证是否正确安装, 打开命令窗口, 执行 node -v ...
- 数据库数据导入/导出报错:无法在只读列“Id”中插入数据。
本文仅供小白参考,大佬请随意...... 本例是:从vs 2017自带的localDB数据库的数据---导出到---->Sql Server 2008中的相应数据库中 1. 导出数据库: 2. ...
- Navicat连接CentOS7中的MariaDB
Step 1:首先登录数据库设置开启远程连接 mysql -u root -p Step 2:使用改表法实现远程连接 use mysql; update user set host = '%' whe ...
- ES6新增内容总结
ES6新增内容有:1,模块化思想.2,关于变量let和const.3,解构赋值.4,字符串的扩展.5,函数的扩展.6,箭头函数.7,继承apply的用法 以下就是详解: 1:模块化思想 非模块化有命名 ...
- sql server 2012使用新特性offset和fetch next完成分页操作
1 select * from HumanResources.Department order by DepartmentID offset rows fetch next rows only; of ...
- SokcetClient c++
#include "pch.h" #include "SokcetClient.h" #include <iostream> #include &l ...
- php的协程
有关迭代生成器的内容在这篇博客中 协程 协程的支持是在迭代生成器的基础上, 增加了可以回送数据给生成器的功能(调用者发送数据给被调用的生成器函数). 这就把生成器到调用者的单向通信转变为两者之间的双向 ...
- 如何解决comctl32.dll文件丢失的问题?
有些Win7系统用户在电脑开机时,系统会出现提示找不到comctl32.dll文件的情况,遇到这个问题我们该怎么去解决呢?好系统重装助手下面就来告诉你方法. Win7系统开机提示找不到comctl32 ...