Python类元编程
类元编程是指在运行时创建或定制类。在Python中,类是一等对象,因此任何时候都可以使用函数创建新类,而无需用class关键字。类装饰器也是函数,不过能够审查、修改,甚至把被装饰的类替换成其他类。元类是类元编程最高级的工具:使用元类可以创建具有某种特性的全新类种,例如我们见过的抽象基类
首先,我们先尝试在运行时创建一个类,collections.namedtuple是一个类工厂函数。我们把一个类名和几个属性名传给这个函数,它会创建一个tuple的子类,其中的元素通过名称获取,还为调试提供了友好的字符串表示形式(__repr__)
假设我们有个宠物狗Dog的类,这个类有三个字段,狗的名字(那么)、重量(weight)和主人(owner),正常大家都会想这个类应该是这样实现的:
class Dog: def __init__(self, name, weight, owner):
self.name = name
self.weight = weight
self.owner = owner
如果现在猫的类或者一个水果类,而这些类中只要有一个__init__来初始化一些字段,会发现产生许多冗余的代码,现在,让我们写一个函数record_factory,这个函数可以即时创建简单的类,这里我们先看一下record_factory的效果,再分析record_factory函数
>>> Dog = record_factory("Dog", "name weight owner") # <1>
>>> rex = Dog("Rex", 30, "Bob")
>>> rex # <2>
Dog(name='Rex', weight=30, owner='Bob')
>>> name, weight, _ = rex # <3>
>>> name, weight
('Rex', 30)
>>> "{2}'s dog weighs {1}kg".format(*rex) # <4>
"Bob's dog weighs 30kg"
Dog(name='Rex', weight=32, owner='Bob')
>>> rex.weight = 32 # <5>
>>> rex
Dog(name='Rex', weight=32, owner='Bob')
>>> Dog.__mro__ # <6>
(<class 'factories.Dog'>, <class 'object'>)
- 这个工厂函数要求传入两个参数,第一个参数是类名,第二个参数是属性名,由若干空格隔开的属性名
- 字符串表示
- 实例是可迭代的对象,因此赋值时可以方便拆包
- 传给format等函数也可以拆包
- 实例是可变对象
- 新建的类继承自object,与我们的工厂函数没有关系
现在,我们来看下record_factory()函数
def record_factory(cls_name, field_names):
try:
field_names = field_names.replace(',', ' ').split() # <1>
except AttributeError: # no .replace or .split
pass # assume it's already a sequence of identifiers
field_names = tuple(field_names) # <2> def __init__(self, *args, **kwargs): # <3>
attrs = dict(zip(self.__slots__, args))
attrs.update(kwargs)
for name, value in attrs.items():
setattr(self, name, value) def __iter__(self): # <4>
for name in self.__slots__:
yield getattr(self, name) def __repr__(self): # <5>
values = ', '.join('{}={!r}'.format(*i) for i
in zip(self.__slots__, self))
return '{}({})'.format(self.__class__.__name__, values) cls_attrs = dict(__slots__=field_names, # <6>
__init__=__init__,
__iter__=__iter__,
__repr__=__repr__) return type(cls_name, (object,), cls_attrs) # <7>
- 这里尝试在逗号或空格处拆分field_names,如果失败则假定field_names是一个可迭代的对象,一个元素对应一个属性名
- 使用属性名构建元组,这将成为新建类的__slots__属性,此外,这么做还设定了拆包和字符串表示形式各字段的顺序
- 这个函数将成为新建类的__init__方法,参数有位置参数和关键字参数
- 实现__iter__函数,把类的实例变成可迭代的对象,按照__slots__设定的顺序产出字段值
- 迭代__slots__和self,生成类的字符串形式
- 组建类属性字典
- 调用type构造方法,构建新类,然后返回
通常,我们把type视为函数,利用它返回一个对象的类型,如type(obj),作用与obj.__calss__相同。然而,type是一个类,当成类使用时,传入三个参数可以组建一个新的类,如:
MyClass = type('MyClass', (MySuperClass, MyMixin), {'x': 42, 'x2': lambda self: self.x * 2})
type的三个参数分别是name,bases和dict。最后一个参数是一个映射,指定新类的属性名和值,上述代码与下面的代码有相同的作用
class MyClass(MySuperClass, MyMixin):
x = 42
def x2(self):
return self.x * 2
record_factory函数的最后一行会构建出一个类,类的名称是cls_name参数的值,唯一的直接超类是object,有__slots__、__init__、__iter__和__repr__四个类属性,其中后三个是实例方法
定义描述符的类装饰器:在Python属性描述符(一)这个章节中,LineItem类还有些问题没解决:存储属性的名称不具有描述性,即属性(如weight)的值存储名名_Quantity#{uuid},这样的名称不便于调试。由于实例化描述符时无法得到托管类属性,可是,一旦组件好整个类,而且把描述符实例绑定到类属性上之后,我们就可以审查类了。
import abc
import uuid class AutoStorage: def __init__(self):
cls = self.__class__
prefix = cls.__name__
identity = str(uuid.uuid4())[:8]
self.storage_name = '_{}#{}'.format(prefix, identity) def __get__(self, instance, owner):
if instance is None:
return self
else:
return getattr(instance, self.storage_name) def __set__(self, instance, value):
setattr(instance, self.storage_name, value) class Validated(abc.ABC, AutoStorage): def __set__(self, instance, value):
value = self.validate(instance, value)
super().__set__(instance, value) @abc.abstractmethod
def validate(self, instance, value):
"""return validated value or raise ValueError""" class Quantity(Validated):
"""a number greater than zero""" def validate(self, instance, value):
if value <= 0:
raise ValueError('value must be > 0')
return value class NonBlank(Validated):
"""a string with at least one non-space character""" def validate(self, instance, value):
value = value.strip()
if len(value) == 0:
raise ValueError('value cannot be empty or blank')
return value def entity(cls): # <2>
for key, attr in cls.__dict__.items(): # <3>
if isinstance(attr, Validated): # <4>
type_name = type(attr).__name__
attr.storage_name = '_{}#{}'.format(type_name, key) # <5>
return cls # <6> @entity # <1>
class LineItem:
description = NonBlank()
weight = Quantity()
price = Quantity() def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price def subtotal(self):
return self.weight * self.price
- 相比Python属性描述符(一)这个章节中的LineItem类,这里新增加了一个装饰器
- 装饰器的参数是一个类
- 迭代存储类属性的字典
- 判断属性是否是Validated描述符的实例
- 使用描述符类的名称和托管属性的名称重新命名storage_name
- 返回修改后的类
>>> raisins = LineItem('Golden raisins', 10, 6.95)
>>> dir(raisins)[:3]
['_NonBlank#description', '_Quantity#price', '_Quantity#weight']
>>> LineItem.description.storage_name
'_NonBlank#description'
>>> raisins.description
'Golden raisins'
>>> getattr(raisins, '_NonBlank#description')
'Golden raisins'
可以看出,类装饰器能以比较简单的方式做到以前需要使用元类做的事情,即创建类时定制类。类装饰器有一个缺点:只对依附类有效,这意味着,被装饰的类的子类可能继承也可能不继承装饰器所做的改动
导入时和运行时比较:为了正确地做元编程,必须知道Python解释器什么时候计算各个代码块。代码在导入时,解释器会从上到下一次性解析完.py模块的源码,然后生成用于执行的字节码。如果句法有错误,就在此时报告。如果本地__pycache__目录下中有最新的.pyc文件,解释器会跳过上述的步骤,因为已经有运行所需的字节码了
编译肯定是导入时的动作,不过那个时期还会做其他的事,因为Python中的语句几乎都是可执行的,也就是说语句可能会运行用户代码,修改用户程序的状态。尤其是import语句,它不只是声明,在进程中首次导入模块时,还会运行所导入模块的全部顶层代码,以后导入相同的模块则使用缓存,只做名称绑定。那些顶层代码可以做任何事,包括通常在运行时做的事,例如连接数据库。因此,“导入时”与“运行时”之间的界限是模糊的,import语句可以触发运行时行为
导入时会运行全部顶层代码,但是顶层代码会经过一些加工。导入模块时,解释器会执行顶层的def语句,解释器会编译函数的定义体(首次导入模块时),把函数对象绑定到对应的全局名称上,但是解释器显然不会执行函数的定义体。通常这意味着解释器在导入时定义顶层函数,但是仅当在运行时调用函数才会执行函数的定义体
对类来说,情况就不同了:在导入时,解释器会执行每个类的定义体,甚至会执行嵌套类的定义体,执行类定义体的结果是,定义了类属性和方法,并构建了类对象,从这个意义上理解,类的定义体属于“顶层代码”,因为它在导入时运行
先来看两个脚本:
脚本evalsupport.py
print('<[100]> evalsupport module start') def deco_alpha(cls):
print('<[200]> deco_alpha') def inner_1(self):
print('<[300]> deco_alpha:inner_1') cls.method_y = inner_1
return cls class MetaAleph(type):
print('<[400]> MetaAleph body') def __init__(cls, name, bases, dic):
print('<[500]> MetaAleph.__init__') def inner_2(self):
print('<[600]> MetaAleph.__init__:inner_2') cls.method_z = inner_2 print('<[700]> evalsupport module end')
脚本evaltime.py
from evalsupport import deco_alpha print('<[1]> evaltime module start') class ClassOne():
print('<[2]> ClassOne body') def __init__(self):
print('<[3]> ClassOne.__init__') def __del__(self):
print('<[4]> ClassOne.__del__') def method_x(self):
print('<[5]> ClassOne.method_x') class ClassTwo(object):
print('<[6]> ClassTwo body') @deco_alpha
class ClassThree():
print('<[7]> ClassThree body') def method_y(self):
print('<[8]> ClassThree.method_y') class ClassFour(ClassThree):
print('<[9]> ClassFour body') def method_y(self):
print('<[10]> ClassFour.method_y') if __name__ == '__main__':
print('<[11]> ClassOne tests', 30 * '.')
one = ClassOne()
one.method_x()
print('<[12]> ClassThree tests', 30 * '.')
three = ClassThree()
three.method_y()
print('<[13]> ClassFour tests', 30 * '.')
four = ClassFour()
four.method_y() print('<[14]> evaltime module end')
现在让我们尝试在python控制台中导入evaltime.py模块,和用python解释器运行evaltime.py文件
首先是在python控制台导入evaltime.py模块
>>> import evaltime
<[100]> evalsupport module start
<[400]> MetaAleph body
<[700]> evalsupport module end
<[1]> evaltime module start
<[2]> ClassOne body
<[6]> ClassTwo body
<[7]> ClassThree body
<[200]> deco_alpha
<[9]> ClassFour body
<[14]> evaltime module end
- [100]:evalsupport模块中所有顶层代码在导入模块时运行:解释器会比编译deco_alpha函数,但是不会执行定义体
- [400]:MetaAleph类的定义体运行了
- [2]:每个类的定义体都执行了
- [6]:包括嵌套类的定义体执行了
- [200]:先执行被装饰类ClassThree的定义体,然后运行装饰器函数
- [14]:在这个场景中,evaltime模块时导入的,因此不会运行if __name__ == "__main__":块
这里有一点要注意的:解释器先执行类的定义体,然后再调用依附在类上的装饰器函数,这是合理的行为,因为必须先构建类对象,装饰器才有类对象处理
再来看另外一个例子,用python解释器执行evaltime.py文件
python evaltime.py
<[100]> evalsupport module start
<[400]> MetaAleph body
<[700]> evalsupport module end
<[1]> evaltime module start
<[2]> ClassOne body
<[6]> ClassTwo body
<[7]> ClassThree body
<[200]> deco_alpha
<[9]> ClassFour body
<[11]> ClassOne tests ..............................
<[3]> ClassOne.__init__
<[5]> ClassOne.method_x
<[12]> ClassThree tests ..............................
<[300]> deco_alpha:inner_1
<[13]> ClassFour tests ..............................
<[10]> ClassFour.method_y
<[14]> evaltime module end
<[4]> ClassOne.__del__
- [9]:到本条为止,输出和上一个例子相同
- [3]:类的标准行为
- [300]:deco_alpha装饰器修改了ClassThree.method_y方法,因此调用three.method_y()时运行inner_1函数的定义体
- [4]:只有程序结束时,绑定在全局变量one上的Classone实例才会被垃圾回收程序收回
在第二个例子中主要想说明的是,类装饰器可能对类的子类没有影响,我们把ClassFour定义为ClassThree的子类,ClassThree类上依附着@deco_alpha装饰器把method_y方法替换掉了,这对ClassFour类根本没有影响。当然,如果ClassFour.method_y()方法使用super()调用ClassThree.method_y()方法,我们便会看到装饰器起作用了,执行inner_1函数
根据Python对象模型,类是对象,因此,类肯定是另外某个类的实例。默认情况下,Python中的类是type类的实例,也就是说,type是大多数内置的内或用户定义的类的元类:
>>> "spam".__class__
<class 'str'>
>>> str.__class__
<class 'type'>
>>> LineItem.__class__
<class 'type'>
>>> type.__class__
<class 'type'>
为了避免无限回溯,type是其自身的实例,注意,str或LineItem是type的实例,而并不是继承自type,这两个类都是object的子类,str、LineItem、type和object这几个对象的关系如下图:
两个示意图都是正确的,左边强调的是,str、type和LineItem都是object的子类,右边的示意图则表明,str、object和LineItem是type的实例,因为他们都是类。object类和type类之间的关系很独特:object是type的实例,而type是object的子类,除了type,标准库中还有一些别的元类,例如ABCMeta和Enum。collections.Iterable所属的类是abc.ABCMeta。Iterable是抽象类,而ABCMeta不是,Iterable是ABCMeta的实例:
>>> import collections
>>> collections.Iterable.__class__
<class 'abc.ABCMeta'>
>>> import abc
>>> abc.ABCMeta.__class__
<class 'type'>
>>> abc.ABCMeta.__mro__
(<class 'abc.ABCMeta'>, <class 'type'>, <class 'object'>)
向上追溯,ABCMeta最终所属的类也是type。所有的类都直接或间接地是type的实例,不过只有元类同时也是type的子类,若想理解元类一定要知道这种关系,元类(如ABCMeta)从type类继承了构建类的能力
Iterable是object的子类,是ABCMeta的实例。object和ABCMeta都是type的实例,但这里重要关系是,ABCMeta还是type的子类,因为ABCMeta是元类。所有类都是type的实例,但是元类还是type的子类,因此可以作为制造类的工厂。具体通过实现__init__方法定制实例,元类__init__方法可以做到类装饰器能做的事情,而且作用更大
evaltime_meta.py:ClassFive是MetaAleph元类的实例,evalsupport模块在上面的evalsupport.py中
from evalsupport import deco_alpha
from evalsupport import MetaAleph print('<[1]> evaltime_meta module start') @deco_alpha
class ClassThree():
print('<[2]> ClassThree body') def method_y(self):
print('<[3]> ClassThree.method_y') class ClassFour(ClassThree):
print('<[4]> ClassFour body') def method_y(self):
print('<[5]> ClassFour.method_y') class ClassFive(metaclass=MetaAleph):
print('<[6]> ClassFive body') def __init__(self):
print('<[7]> ClassFive.__init__') def method_z(self):
print('<[8]> ClassFive.method_y') class ClassSix(ClassFive):
print('<[9]> ClassSix body') def method_z(self):
print('<[10]> ClassSix.method_y') if __name__ == '__main__':
print('<[11]> ClassThree tests', 30 * '.')
three = ClassThree()
three.method_y()
print('<[12]> ClassFour tests', 30 * '.')
four = ClassFour()
four.method_y()
print('<[13]> ClassFive tests', 30 * '.')
five = ClassFive()
five.method_z()
print('<[14]> ClassSix tests', 30 * '.')
six = ClassSix()
six.method_z() print('<[15]> evaltime_meta module end')
现在,我们再用控制台和解释器执行的方式来执行evaltime_meta.py模块
在控制台导入evaltime_meta.py模块
>>> import evaltime_meta
<[100]> evalsupport module start
<[400]> MetaAleph body
<[700]> evalsupport module end
<[1]> evaltime_meta module start
<[2]> ClassThree body
<[200]> deco_alpha
<[4]> ClassFour body
<[6]> ClassFive body
<[500]> MetaAleph.__init__
<[9]> ClassSix body
<[500]> MetaAleph.__init__
<[15]> evaltime_meta module end
- [6]:创建ClassFive时,执行了ClassFive的定义体,同时调用了MetaAleph.__init__方法
- [9]:创建ClassFive的子类ClassSix时执行了ClassSix的定义体,同时调用了MetaAleph.__init__方法
Python解释器执行ClassFive类的定义体时没有调用type构建工具的类定义体,而是调用MetaAleph类,看下evalsupport.py文件中的MetaAleph.__init__方法,可以发现有四个参数:
- cls:这是要初始化的类对象
- name、bases、dic:与构建类时传给type的参数一样
evalsupport.py定义MetaAleph元类
class MetaAleph(type):
print('<[400]> MetaAleph body') def __init__(cls, name, bases, dic):
print('<[500]> MetaAleph.__init__') def inner_2(self):
print('<[600]> MetaAleph.__init__:inner_2') cls.method_z = inner_2
通常编写元类时,__init__第一个参数self会改成cls,这样就能清楚表明要构建的实例是类
在命令行中执行evaltime_meta.py脚本
python evaltime_meta.py
<[100]> evalsupport module start
<[400]> MetaAleph body
<[700]> evalsupport module end
<[1]> evaltime_meta module start
<[2]> ClassThree body
<[200]> deco_alpha
<[4]> ClassFour body
<[6]> ClassFive body
<[500]> MetaAleph.__init__
<[9]> ClassSix body
<[500]> MetaAleph.__init__
<[11]> ClassThree tests ..............................
<[300]> deco_alpha:inner_1
<[12]> ClassFour tests ..............................
<[5]> ClassFour.method_y
<[13]> ClassFive tests ..............................
<[7]> ClassFive.__init__
<[600]> MetaAleph.__init__:inner_2
<[14]> ClassSix tests ..............................
<[7]> ClassFive.__init__
<[600]> MetaAleph.__init__:inner_2
<[15]> evaltime_meta module end
- [300]:装饰器依附到ClassThree类上之后,method_y方法被替换成inner_1方法
- [5]:虽然ClassFour是ClassThree的子类,但是依附的装饰器并没有对ClassFour造成影响
- [600]:MetaAleph类的__init__函数把ClassFive和ClassSix的method_z函数替换成inner_2函数
定制描述符的元类:回到LineItem类,我们是否能提供一个类,通过继承可以代替描述符或元类?
import abc
import uuid class AutoStorage:
__counter = 0 def __init__(self):
cls = self.__class__
prefix = cls.__name__
identity = str(uuid.uuid4())[:8]
self.storage_name = '_{}#{}'.format(prefix, identity) def __get__(self, instance, owner):
if instance is None:
return self
else:
return getattr(instance, self.storage_name) def __set__(self, instance, value):
setattr(instance, self.storage_name, value) class Validated(abc.ABC, AutoStorage): def __set__(self, instance, value):
value = self.validate(instance, value)
super().__set__(instance, value) @abc.abstractmethod
def validate(self, instance, value):
"""return validated value or raise ValueError""" class Quantity(Validated):
"""a number greater than zero""" def validate(self, instance, value):
if value <= 0:
raise ValueError('value must be > 0')
return value class NonBlank(Validated):
"""a string with at least one non-space character""" def validate(self, instance, value):
value = value.strip()
if len(value) == 0:
raise ValueError('value cannot be empty or blank')
return value class EntityMeta(type):
"""Metaclass for business entities with validated fields""" def __init__(cls, name, bases, attr_dict):
super().__init__(name, bases, attr_dict) # <3>
for key, attr in attr_dict.items(): # <4>
if isinstance(attr, Validated):
type_name = type(attr).__name__
attr.storage_name = '_{}#{}'.format(type_name, key) class Entity(metaclass=EntityMeta): # <2>
"""Business entity with validated fields""" class LineItem(Entity): # <1>
description = NonBlank()
weight = Quantity()
price = Quantity() def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price def subtotal(self):
return self.weight * self.price
- LineItem是Entity的子类
- Entity类的存在只是为了便利,用户直接继承这个类,而无需关心EntityMeta元类,甚至可以不用知道他的存在
- 在超类(即type)调用__init__方法
- 获取描述符实例的类名和属性名,重定义描述符的storage_name
元类的特殊方法__prepare__
某些应用中,可能需要知道类的属性定义的顺序,type构造方法及元类的__new__和__init__方法都会收到要执行的类的定义体,形式是名称到属性的映像。在默认情况下,那个映射是字典,也就是说,元类或类装饰器获得映射时,属性在类定义中的顺序已经丢失了
这个问题的解决办法是:使用Python3引入的特殊方法__prepare__。这个方法只在元类中有用,而且必须声明为类方法(即用@classmethod装饰器定义)。解释器调用元类的__new__方法之前会先调用__prepare__方法,使用类定义体中的属性创建映射。__prepare__方法的第一个参数是元类,随后两个参数分别是要构建的类名称和基类组成的元组,返回值必须是映射。元类构建新类时,__prepare__方法返回的映射会传给__new__方法的最后一个参数,然后再传给__init__方法
class EntityMeta(type):
"""Metaclass for business entities with validated fields""" @classmethod
def __prepare__(cls, name, bases):
return collections.OrderedDict() # <1> def __init__(cls, name, bases, attr_dict):
super().__init__(name, bases, attr_dict)
cls._field_names = [] # <2>
for key, attr in attr_dict.items(): # <3>
if isinstance(attr, Validated):
type_name = type(attr).__name__
attr.storage_name = '_{}#{}'.format(type_name, key)
cls._field_names.append(key) # <4> class Entity(metaclass=EntityMeta):
"""Business entity with validated fields""" @classmethod
def field_names(cls): # <5>
for name in cls._field_names:
yield name
- 返回一个空的OrderDict实例,类属性将存储在里面
- 构建的类中创建一个_field_names属性
- attr_dict是之前那个OrderDict对象,由解释器在调用__init__方法之前调用__prepare__方法时获得。因此,这个for循环会按照添加属性的顺序迭代属性
- 找到各个Validated字段添加进_field_names列表
- _field_names类方法作用简单,按照添加字段的顺序产出字段的名称
class LineItem(Entity):
description = NonBlank()
weight = Quantity()
price = Quantity() def __init__(self, description, weight, price):
self.description = description
self.weight = weight
self.price = price def subtotal(self):
return self.weight * self.price for name in LineItem.field_names():
print(name)
运行结果:
description
weight
price
在开发框架或库时,使用元类会协助我们执行很多任务,如:
- 验证属性
- 一次把装饰器依附到多个地方
- 序列化对象或转换数据
- 对象关系映射
- 基于对象的持久存储
- 动态转换使用其他语言编写的类结构
类作为对象:__mro__、__class__和__name__已经见了很多次了,除此之外,类对象还有以下属性:
- cls.__bases__:由类的基类组成的元组
- cls.__qualname__:即从模块的全局作用域到类的点分路径,例如在A类中定义了B类,那么B类对象的__qualname__就是A.B
- cls.__subclasses__():这个方法返回一个列表,包含类的直接子类
- cls.mro():构建类时,如果需要获取存储在类属性的__mro__中的超类元组,解释器会调用这个方法。元类可以覆盖这个方法,定制要构建的类的解析顺序
Python类元编程的更多相关文章
- Python类元编程初探
在<流畅的Python>一书中提到: Classes are first-class object in Python, so a function can be used to crea ...
- Python的元编程案例
Python的元编程案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是元编程 元编程概念来自LISP和smalltalk. 我们写程序是直接写代码,是否能够用代码来生成 ...
- python之元编程
一.什么是元编程 元编程是一种编写计算机程序的技术,这些程序可以将自己看作数据,因此你可以在运行时对它进行内省.生成和/或修改. Python在语言层面对函数.类等基本类型提供了内省及实时创建和修改的 ...
- python之元编程(元类实例)
本实例是元类实例,功能是记录该的子类的类名,并以树状结构展示子类的类名. RegisterClasses继承自type,提供的功能是在__init__接口,为类创建了childrens的集合,并类名保 ...
- Python元编程
简单定义"元编程是一种编写计算机程序的技术,这些程序可以将自己看做数据,因此你可以在运行时对它进行内审.生成和/或修改",本博参考<<Python高级编程>> ...
- python类:描述器Descriptors和元类MetaClasses
http://blog.csdn.net/pipisorry/article/details/50444769 描述器(Descriptors) 描述器决定了对象属性是如何被访问的.描述器的作用是定制 ...
- python 通过元类控制类的创建
一.python中如何创建类? 1. 直接定义类 class A: a = 'a' 2. 通过type对象创建 在python中一切都是对象 在上面这张图中,A是我们平常在python中写的类,它可以 ...
- 转---一文读懂 python 的元类
译注:这是一篇在Stack overflow上很热的帖子.提问者自称已经掌握了有关Python OOP编程中的各种概念,但始终觉得元类(metaclass)难以理解.他知道这肯定和自省有关,但仍然觉得 ...
- Python之元类详解
一.引子 元类属于Python面向对象编程的深层魔法,99%的人都不得要领,一些自以为搞明白元类的人其实也是自圆其说,点到为止,从队元类的控制上来看就破绽百出,逻辑混乱: 二.什么是元类 一切源自于一 ...
随机推荐
- PHP正则表达式 - 元字符
下表包含了元字符的完整列表以及它们在正则表达式上下文中的行为: 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个 向后引用.或一个八进制转义符.例如,'n' 匹配字符 " ...
- Hi,bro
这是我第一次写部落格,也是我刚开始学python,希望我以后能把To Do List 做好,也希望大家可以好好学习,为了以后good life去努力,Do SomeThing OK?
- Oracle创建用户、表(1)
Oracle创建用户.表(1) 1. 连接 C:\Users\LEI>sqlplus / as sysdba SQL*Plus: Release 12.1.0.2.0 Production on ...
- 【extjs6学习笔记】1.6 初始:本地化
app.json中修改
- ssh连接github连不上
连接github报端口22连接不上: 输入命令展示出ssh_config内容后: vim /etc/ssh/ssh_config 或者使用open /etc/ssh/ssh_config命令在文本编辑 ...
- Beta冲刺(周五)
这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 这个作业要求在哪里 https://edu.cnblo ...
- java sql database相关收集
1 java prepareStatement http://www.importnew.com/5006.html 2 java ENGINE=InnoDB的使用 http://www.cnblog ...
- GC执行finalize的过程以及对象的一次自我拯救
参考资料:深入理解java虚拟机 /** * 此代码演示了两点: * 1.对象可以在被GC时自我拯救 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法只会被系统自动调一次 */ ...
- Google 出品的 Java 编码规范,强烈推荐,权威又科学!
原文:google.github.io/styleguide/javaguide.html 译者:Hawstein 来源:hawstein.com/2014/01/20/google-java-sty ...
- java基础—多态(动态加载)
一.面向对象最核心的机制——动态绑定,也叫多态