python3 元类编程的一个例子

【引子】

  虽然我们可以通过“class”语句来定义“类”,但是要想更加细粒度的控制“类”的创建,要使用元类编程才能实现。

 

  比如说我们要实现这样的一个约束、所有项目中用到的类都应该要为它定义的方法提供文档字符字符串。有两条可行

  的路径 1):依赖工程师的自觉、自律 让他们在定义每一个方法的时候都为方法增加文档字符串, 2):通过元类来做一些

  控制,如果工程师没有为方法提供文档字符,那么就直接报错,直到工程师为方法提供字符串为止。

 

【实现1】

  依赖工程师的自觉、自律为方法增加文档字符串

class Person(object):
    name = None
    def __init__(self,name):
        self.name=name

    def say_hello(self):
        """
        print hello My name is xxx  ...
        """
        print("hello My name is {self.name}".format(self=self))

  我们如何能保证每一个方法都增加了文档字符串呢?我一方面要依靠“自觉”另一方面要依靠“纪律性”,最好要有专门的人来做代码

  审核。

 

【实现2】

  通过元类来实现这个约束

  第一步:定义一个元类来审核class

class DocMeta(type):
    """
    检查方法是否有提供文档字符串
    """
    def __init__(self,name,base,attrs):for key,value in attrs.items():
            if key.startswith('__'):
                #跳过魔术方法
                continue
            if not hasattr(value,"__call__"):
                #跳过字段
                continue
            #如果能进入到这里、那么一定是方法了、于是检查方法有没有文档字符串.
            if not getattr(value,"__doc__"):
                #没有文档字符串的情况下就报错
                raise TypeError("{0} must have a docstring".format(key))
            super().__init__(name,base,attrs)

  

  第二步:定义一个通用的基类、以后所有要实现这一约束的类都继承自它

class Documented(metaclass=DocMeta):
    pass

   注意这个项的元类是我们刚才定义的“DocMeta”类

 

  第三步:让项目中的类继承自这个基类

class Person(Documented):
    name = None
    def __init__(self,name):
        self.name=name

    def say_hello(self):
        """
        print hello My name is xxx  ...
        """
        print("hello My name is {self.name}".format(self=self))

  

  第四步:和使用普通的类一样使用Person类

if __name__=="__main__":
    p = Person("welson")
    p.say_hello() #hello My name is welson

 

 

 

【总结】

  以上代码由于在say_hello 方法中提供了文档字符串、如果没有提供的话、在创建Person类的时候就会报错了

Traceback (most recent call last):
  File "main.py", line 31, in <module>
    class Person(Documented):
  File "main.py", line 24, in __init__
    raise TypeError("{0} must have a docstring".format(key))
TypeError: say_hello must have a docstring

 

  全部代码如下:

"""
Python元类编程的一个例子
"""

__version__ = '0.1'
__author__  = '蒋乐哥哥'


class DocMeta(type):
    """
    检查方法是否有提供文档字符串
    """
    def __init__(self,name,base,attrs):
        for key,value in attrs.items():
            if key.startswith('__'):
                #路过魔术方法
                continue
            if not hasattr(value,"__call__"):
                #跳过字段
                continue
            #如果能进入到这里、那么一定是方法了、于是检查方法有没有文档字符串.
            if not getattr(value,"__doc__"):
                #没有文档字符串的情况下就报错
                raise TypeError("{0} must have a docstring".format(key))
            super().__init__(name,base,attrs)


class Documented(metaclass=DocMeta):
    pass

class Person(Documented):
    name = None
    def __init__(self,name):
        self.name=name

    def say_hello(self):
        """
        print hello My name is xxx  ...
        """
        print("hello My name is {self.name}".format(self=self))

# 在不为方法提供文档字符串的情况下会直接报错
#class Person(Documented):
#    name = None
#    def __init__(self,name):
#        self.name=name
#
#    def say_hello(self):
#        print("hello My name is {self.name}".format(self=self))

if __name__=="__main__":
    p = Person("welson")
    p.say_hello()

 

 

 

 

 

 

 

----------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值