一、类也是对象
当我们定义一个变量或者函数的时候,我们可以在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运行之前):
'''
学习中遇到问题没人解答?小编创建了一个Python学习交流群:711312441
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
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()