一、实例创建
在创建实例时,调用__new__方法和__init__方法,这两个方法在没有定义时,是自动调用了object来实现的。python3默认创建的类是继承了object。
class A(object): def __init__(self, *args, **kwargs): self.name, self.age, self.gender = args[:3] def __new__(cls, *args, **kwargs): print("__new__ has called.") return super(A, cls).__new__(cls) # 可写为 super().__new__(cls) 或 object.__new__(cls) a = A("Li", 27, "male") print(a.name, a.age, a.gender) """ __new__ has called. Li 27 male """
二、类的创建
以class关键字开头的上下文在定义时就已经被解释执行。而函数(包括匿名函数)在没被调用时是不执行的。这个过程本质上做了一件事情:从元类type那里创建了一个名为A的类,开辟类内存空间,并读取class语句的上下文,将类属性和方法写进去。
print("--解释器开始执行--") def func(): print("what the hell?") print("--开始读取class关键字的上下文--") class A: name = "A" func() print("--上下文结束--") def fn1(): print("--开始读取匿名函数--") def fn2(): pass pass print("--读取结束--") print("--解释器执行结束--") """ --解释器开始执行-- --开始读取class关键字的上下文-- what the hell? --上下文结束-- --解释器执行结束-- """
" 使用class语句定义新类时,将会发生很多事情。首先,类主体将为作其自己的私有字典内的一系列语句来执行。其内容里语句的执行与正常代码中的执行过程相同,只是增加了会在私有成员(名称以__开头)上发生的名称变形。然后,类的名称、基类列表和字典将传递给元类的解构函数,以创建相应的类对象。最后,调用元类type(),这里可以自定义。在python3中,使用class Foo(metaclass=type)来显式地指定元类。如果没有找到任何__metaclass__值,Python将使用默认的元类type。" -- <<python 参考手册(第四版)>>
class_name = "Foo" # 类名 class_parents = (object, ) # 基类 # 类主体 class_body = """ name = "Foo" def __init__(self, x): self.x = x def hello(self): print("Hello") """ class_dict = {} # 在局部字典class_dict中执行类主体 exec(class_body, globals(), class_dict) # 创建类对象Foo Foo = type(class_name, class_parents, class_dict) # type可以指定 Foo("X").hello() # Hello
type类创建类时,指定了类的三个部分: class_name, class_parent, class_dict。这一步是在底层实现的。
string = """name = 'Li' age = 2712 """ # 字符串必须是换行符或分号分割 dic = {} exec(string, globals()) # globals表示执行字符串后的结果保存到全局命名空间中 print(name, age) print(dic) exec(string, globals(), dic) # locals表示执行字符串后的结果保存到局部一个映射对象中 print(dic) """ Li 2712 {} {'name': 'Li', 'age': 2712} """
我们可以用type动态地创建类。你可以用上面的方式去实现类的上下文,也可以直接定义函数并给到字典里,尽管它看起来有些"污染"全局空间:
class_name = "A" class_parent = () label = "hello world" def init(self, name, age): self.name = name self.age = age def hello(self): print("Hello, i'm %s, %s." % (self.name, self.age)) A = type(class_name, class_parent, {"__init__": init, "hello": hello, "label": label}) a = A("Li", 18) a.hello() print(a.label) """ Hello, i'm Li, 18. hello world """
三、元类的实现过程
复制代码 print("First...") class MyType(type): print("MyType begin ...") def __init__(self, *args, **kwargs): print("Mytype __init__", self, *args, **kwargs , sep="\r\n", end="\r\n\r\n") type.__init__(self, *args, **kwargs) # 调用type.__init__ def __call__(self, *args, **kwargs): print("Mytype __call__", *args, **kwargs) obj = self.__new__(self) # 第一个self是Foo,第二个self是F("Alex") print("obj ",obj, *args, **kwargs) print(self) self.__init__(obj,*args, **kwargs) return obj def __new__(cls, *args, **kwargs): print("Mytype __new__", cls, *args, **kwargs, sep="\r\n", end="\r\n\r\n") return type.__new__(cls, *args, **kwargs) print("MyType end ...") print('Second...') class Foo(metaclass=MyType): print("begin...") def __init__(self, name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__", end="\r\n\r\n") return object.__new__(cls) print("over...") def __call__(self, *args, **kwargs): print("Foo __call__", self, *args, **kwargs, end="\r\n\r\n") print("third...") f = Foo("Alex") print("f",f, end="\r\n\r\n") f() print("fname",f.name) """ First... MyType begin ... MyType end ... Second... begin... over... Mytype __new__ <class '__main__.MyType'> Foo () {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x10ad89268>, '__new__': <function Foo.__new__ at 0x10ad89488>, '__call__': <function Foo.__call__ at 0x10ad86ae8>} Mytype __init__ <class '__main__.Foo'> Foo () {'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x10ad89268>, '__new__': <function Foo.__new__ at 0x10ad89488>, '__call__': <function Foo.__call__ at 0x10ad86ae8>} third... Mytype __call__ Alex Foo __new__ obj <__main__.Foo object at 0x10ae2ac88> Alex <class '__main__.Foo'> Foo __init__ f <__main__.Foo object at 0x10ae2ac88> Foo __call__ <__main__.Foo object at 0x10ae2ac88> fname Alex """
假设MyType是type类,type有三个特殊方法__init__、__call__、__new__。
首先, First请忽略掉吧。假设底层就这样搞了一个type类,它的名字叫MyType。
其次,Second这一步。解释器发现class和Foo(),会知道要从元类MyType中"实例化"一个类对象。
它会首先扫描class Foo()的整个上下文,并分成三部分,类名、基类元组,和私有字典。
然后它会告诉解释器,马上调用MyType(就是Type)类来创建一个名为Foo的类,来开辟内存空间,把这个Foo的私有字典(包括属性和方法)给放进去。
于是解释器执行了MyType.__new__,并继续执行MyType.__init__。来创建一个名为Foo的类对象。
再次,Third这一步。
首先通过Foo()来调用MyType.__call__,来实例化一个Foo类。它相当于Foo = Type()
然后依次执行Foo.__new__和Foo.__init__,来实例化一个实例对象。
Foo()相当于: MyType()(),而MyType()就是F。于是,在a = Foo(),实际上执行了MyType()()。前面说过,实例+()会调用所属类的__call__方法,同样地,类 + ()会调用类所属元类(MyType)的__call__方法。
至此,一个实例就算创建完成了。
四、抽象基类
抽象基类有两个特点:
1.规定继承类必须具有抽象基类指定的方法
2.抽象基类无法实例化
基于上述两个特点,抽象基类主要用于接口设计
实现抽象基类可以使用内置的abc模块
import abc class Human(metaclass=abc.ABCMeta): @abc.abstractmethod # 规定子类必须有名为introduce的实例方法 def introduce(self): pass @abc.abstractproperty # 规定子类必须有名为country的装饰器方法 def country(self): pass @abc.abstractclassmethod # 规定子类必须有名为gender的类方法 def gender(cls): pass @abc.abstractstaticmethod # 规定子类必须有名为hello的静态方法 def hello(): pass class Person(Human): __country = "China" def __init__(self, name, age): self.name = name self.age = age def introduce(self): return "I'm {}, {}.".format(self.name, self.age) @property def country(self): return Person.__country @classmethod def gender(cls): return "female" @staticmethod def hello(): print("What the hell?") person = Person("Li", 24) print(person.introduce()) print(person.country) print(Person.gender()) person.hello() # I'm Li, 24. # China # female # What the hell?
collections.abc模块收集了常用的抽象基类。感兴趣的话可以打开collections.abc查看源码。
__all__ = ["Awaitable", "Coroutine", "AsyncIterable", "AsyncIterator", "AsyncGenerator", "Hashable", "Iterable", "Iterator", "Generator", "Reversible", "Sized", "Container", "Callable", "Collection", "Set", "MutableSet", "Mapping", "MutableMapping", "MappingView", "KeysView", "ItemsView", "ValuesView", "Sequence", "MutableSequence", "ByteString", ]
来源:https://www.cnblogs.com/kuaizifeng/p/9082181.html