(2022.01.30 Sun 除夕前夜)
开发者总要铭记: DRY, i.e., Don’t Repeat Yourself。代码复用成为关键环节。
在Python中使用元编程Meta programming解决复用问题。Meta programming is the concept of building functions or classes whose primary target is to manipulate code by modifying, wrapping or generating existing codes.元编程就是用已有的代码控制和生成新的代码。
元编程的几个典型特征:
- 元类Metaclass
- 装饰器Decorator
- 类装饰器class decorator
元编程的优点是debug被隔离在特定位置,方便了debug,也方便了修改和disable。
先来看看python中的类和对象。
type
、类和对象
Python中有一句话是 Everything is an object万物皆对象。函数,类,内置类型,都是对象。而类/对象来自于何处呢?
我们来验证类和对象的类型
>>> class SomeClass:
... pass
...
>>> a = SomeClass()
>>> type(a)
>>> type(SomeClass)
>>> type(type)
用inspect
工具判断对象是否为类,或者非类
>>> import inspect
>>> inspect.isclass(SomeClass)
True
>>> inspect.isclass(a)
False
>>> inspect.isclass(type)
True
从上面的结果可以看到一个类的实例,其类型是该类。该类的类型是type
。type
的类型是其本身,并且type
本身也是一个类。
>>> isinstance(a, SomeClass)
True
>>> isinstance(a, type)
False
>>> isinstance(SomeClass, type)
True
>>> isinstance(type, type)
True
或
# 2022.03.16 Wed, also available to other types, e.g., str, float and etc
>>> age = 5
>>> age.__class__
>>> age.__class__.__class__
一个实例是实例化的类,一个类是实例化的元类metaclass,也就是type
。(2022.03.17 Thur)在面向对象的编程中,元类的实例还是类。
type
本身是一个类,是Python内置的metaclass元类。我们可以自定义metaclass,所有类和元类都从type
继承而来。元类是Python元编程的方式之一。
用type
创建类
type
是Python中类的元类,因此可用type
创建类。创建格式如下
= type( , [ ], { : method_name_1, : var_value, ...})
如,创建一个叫classBase
的类,没有内置方法和变量
>>> classBase = type('classBase', (), {})
# 第二个参数只能是tuple格式,其中数值为空表示继承自type,
# 第三个是字典格式,用于标记类方法和类变量
由classBase
类创建其他类(非实例化),即继承。注意,如果通过type
创建的类没有实例化,则定义语句外的方法声明中不需要含有self
参数。
>>> def func(argu1, argu2):
>>> return 'something'
>>> newClass = type('newClass', (classBase,), {'method1': func, 'var': 5})
# 第二个参数别忘记逗号
>>> print(newClass.var)
5
>>> print(newClass.method1(1, 2))
'something'
由list
类定义一个新类,该类不仅有list
的内置方法,还可以自定义类变量和类方法。注意,通过type
定义的类,一旦其被实例化,自定义的方法声明中需要有self
参数。
>>> def func(self, arg1):
... return str(arg1)+' is a string.'
... # 定义这个函数时需要加self参数
>>> newList = type('newList', (list, ), {'var': 99, 'display': func})
>>> a = newList() # instantiation
>>> type(a)
>>> a.append(1)
>>> print(a)
[1]
>>> a.var
99
>>> a.display('bbb')
'bbb is a string.'
(2022.03.16 Wed)
用type
创建/继承类,其优点在于可以“动态”的创建类。比如上面的newList
对象,如果按常规的类创建方式可以写成如下形式。修改方法或添加方法都需要重写类。
class newList:
var = 99
def __init__(self):
pass
def display(self, arg1):
return str(arg1)+' is a string.'
(2022.03.17 Thur)
也可以自己定义元类,自定义元类是type
类的继承。下面例子展示了如何自定义元类,该自定义元类为继承它的子类创建了hello
方法,子类无需定义即可继承该方法。
class helloMeta(type): # 这里有对type类的继承
def hello(cls):
print('helloMeta class')
def __call__(self, *args, **kwargs):
cls = type.__call__(self, *args)
setattr(cls, 'hello', self.hello)
return cls
class tryHello(object, metaclass=helloMeta): #这里的两个参数必不可少
def greet(self):
self.hello()
调用
>>> t = tryHello()
>>> t.greet()
helloMeta class
type
和object
的区别
(2022.05.18 Wed)
object
是所有类的父类,type
也是继承了object
类。在Python3.x中,所有类的创建默认情况下,即class cn:
语句,都是从object
继承类,只有标注了type
才是从type
继承类,如class cn(type):
。相比继承自type
的类,继承自object
的类内置方法更少。
通过__mro__
方法或mro
可以查看一个类的继承顺序/方法解析顺序(Method Resolution Order)。可以看到如果类继承自type
类,会最终继承object
类。
class a(object):
pass
class b:
pass
class c(type):
pass
>> a.__mro__
(__main__.a, object)
>> b.__mro__
(__main__.b, object)
>> c.__mro__
(__main__.c, type, object)
>> dir(a)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>> dir(c)
['__abstractmethods__', '__base__', '__bases__', '__basicsize__',
'__call__', '__class__', '__delattr__', '__dict__',
'__dictoffset__', '__dir__', '__doc__', '__eq__',
'__flags__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__',
'__instancecheck__', '__itemsize__', '__le__', '__lt__',
'__module__', '__mro__', '__name__', '__ne__',
'__new__', '__prepare__', '__qualname__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__',
'__text_signature__', '__weakrefoffset__', 'mro']
而object
类的类型是type
型
>> type(a)
type
元类的应用场景1: 实现单例模式
(2022.03.16 Wed)
我们用元类形式实现单例模式。另外,装饰器也可实现单例模式。
class Singleton(type): #这里一定要有type关键字表明其继承元类
def __init__(cls, name, bases, dic):
super(Singleton, cls).__init__(name, bases, dic)
cls.instance = None
def __call__(cls, *args, **kwargs):
if cls.instance is None:
print('creating a new instance')
cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
else:
print('warning: only one instance allowed')
return cls.instance
class MySingleton(metaclass=Singleton):
pass
实例化
>>> a = MySingleton()
creating a new instance
>>> b = MySingleton()
warning: only one instance allowed
>>> c = MySingleton()
warning: only one instance allowed
元类的应用场景2: 创建APIs
(2022.03.16 Wed)
>>> from django.db import models
>>> class Vehicle(models.Model):
color = models.CharField(max_length=10)
wheels = models.IntegerField()
接下来可以实例化Vehicle
这个类
>>> car = Vehicle(color="Blue", wheels=4)
>>> car.wheels
4
元类的应用,比如Django ORM,Flask,SQLAlchemy和AOP等。
类在创建时到底发生了什么
(2022.02.25 Fri)
Python程序的三个基础block分别是
- Statements
- Functions
- Classes
类的命名空间被保存成字典
class demo:
var1 = 1
def __init__(self):
self.value = 100
>>> demo.__dict__
mappingproxy({'__dict__': ,
'__doc__': None,
'__init__': ,
'__module__': '__main__',
'__weakref__': ,
'var1': 1})
>>> a = demo()
>>> a.__dict__
{'value': 100}
当一个类被创建的时候,发生了如下几步
- 类的本体被隔离 The body (statements and methods) of the class is isolated.
- 类的命名空间字典被创建,但不赋值 The namespace dictionary of the class is created, not populated though.
- 执行类的本体,类命名空间字典被赋值 The body of the class executes, then the namespace dictionary is populated with all of the attributes, methods defined, and some additional useful info about the class.
- 元类在基类中被标记出 The metaclass is identified in the base classes or the metaclass hooks (explained later) of the class to be created.
- 用类名和属性值实例化元类 The metaclass is then called with the name, bases, and attributes of the class to instantiate it.
装饰器Decorator
(2022.02.10 Thur)
参考Python装饰器
类装饰器Class decorator
(2022.02.25 Fri)
参考Python装饰器
Reference
1 https://developer点ibm点com/tutorials/ba-metaprogramming-python/
2 realpython com primer-on-python-decorators (https冒号//realpython点com/primer-on-python-decorators/)
3 编写高质量代码 改善Python编程的91个建议,张颖等著,机械工业出版社