廖雪峰python学习笔记【13】面向对象高级编程:多重继承、定制类、枚举类、元类

 

一、多重继承

1. Java是单一继承,Python是多重继承。

2. 多重继承的好处是避免了复杂庞大的继承链。

3. 多重继承时,提供基本功能的父类作为继承的第一个类,其他类名最好以MinIn结尾,体现出继承关系。

二、定制类

1.__len__方法:类中实现__len__方法后,类的实例能够通过len()函数获取实例的长度(即__len__方法的返回值)。

2. __str__方法:类中实现__str__方法后,类的实例能够通过print()函数打印出实例的内容(即__str__方法的返回值)。

3. __repr__方法:类中实现__repr__方法后,在交互式命令行输入实例名后,能打印出实例的内容(即__repr__方法的返回值)。

4. 类中实现__iter__和__next__方法后,类的实例能够作用于for var in obj循环。每次循环调用实例obj中的__next__方法。

5. __getitem__方法:实现__getitem__方法后能够使用下标访问类的实例。

6. __getattr__方法:实现__getattr__方法后,访问实例中不存在的属性时,会调用__getattr__方法。

7. __call__方法:通常访问实例方法是类似obj.method()的方式调用。实现__call__方法后,可以通过obj()直接调用__call__方法。

8. 普通函数和实现了__call__方法的类实例,作为callable()函数的参数时,函数返回True。

三、使用枚举类

1. 通过python提供的Enum类,定义常量

from enum import Enum # 从enum.py模块导入Enum类。
weekDay = Enum("WeekDay", ("Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"))
# weekDay是类的别名;
# WeekDay是类名,该类是继承自Enum类。

2. 访问枚举的方法:

weekDay.Sun #输出WeekDay.Sun
weekDay['Sun'] #输出WeekDay.Sun
weekDay.Sun.value #输出7. 枚举值默认从0开始。
weekDay.(7) #输出WeekDay.Sun

3. 为了方便控制枚举常量的值,可以自己定义枚举类:

from enum import Enum, unique
@unique #@unique装饰器 帮助检查保证没有重复值。
class WeekDay(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thur = 4
    Fri = 5
    Sat = 6

四、使用元类

1. type()

    1.1 动态语言的函数和类的定义,不是在编译时确定的,而是在运行时动态创建的。

    1.2 使用type()可以获得类型或变量的类型。类型的类型是type,比如int, list,自定义类等的类型是type。

    1.3 type()函数也可以动态创建自定义类。事实上python解释器读取python源码时,遇到class的定义,仅仅是扫描一下class定义的语法,然后通过type()函数创建出class。

Hello = type('helloClass', (object, ), dict(method=func)) # 说明如下:
    Hello : 是type()函数定义的类的别名。
    helloClass : 是type()函数定义的类名。
    (object, ) : 元祖中的object说明helloClass类继承自object。
    dict(method=func) : func为自定义的函数,表示将func函数作为helloClass的方法method。

2. metaclass

  1. 类属性和实例属性

    1. 对于User类,类属性和实例属性同名,这是必须的吗?-- 必须的。因为需要通过类属性名获取实例属性的值。(也可以不同名,但是save方法中需要进行一次转换)

    2. 类属性的值是Field类的子类,表示数据库表中字段名和字段类型。

    3. 同名的实例属性的值是数据库表中字段的值。

  2. User类继承自Model类。

  3. Model类继承自dict类,并且由metaclass重新构造。

    1. 正因为继承自dict类,所以在创建User类的实例时,才能够使用关键字参数。

  4. ModelMetaClass中的attrs为User类的类属性。

    1. 将User类的类属性集中保存在User类的新属性__mapping__中,并删除类User类中原来的属性。

  5. Model类中的save方法:

    1. 遍历__mapping__属性中的key和value。key是User类中定义的类属性,value是F ield类的子类的实例。

    2. 由value中的name属性构成sql语句中的表字段集合。

    3. 由User类属性key获取User类实例属性的值,构成sql语句的值。

      1. 由此可见:User类属性和User实例属性必须同名。但是User类属性名和类属性值中的name字段可以不同名。

代码如下:

class Field(object):
        def __init__(self, name, column_type):
                self.name = name;
                self.column_type = column_type
        def __str__(self):
                return "<%s : %s>" % (self.__class__.__name__, self.name)

class StringField(Field):
        def __init__(self, name):
                super(StringField, self).__init__(name, "varchar(100)")

class IntegerField(Field):
        def __init__(self, name):
                super(IntegerField, self).__init__(name, "bigint")

class ModelMetaClass(type):
        def __new__(cls, name, bases, attrs):
                if name == 'Model':
                        return type.__new__(cls, name, bases, attrs)
                else:
                        print("New model : %s" % name)

                        mappings = dict()

                        for k, v in attrs.items():
                                if isinstance(v, Field):
                                        print("table field : %s-%s" % (k, v))
                                        mappings[k] = v
                        for k in mappings.keys():
                                attrs.pop(k)
                        attrs["__mappings__"] = mappings
                        attrs["__table__"] = name
                        return type.__new__(cls, name, bases, attrs)
                        

class Model(dict, metaclass = ModelMetaClass):
        def __init__(self, **kwargs):
                super(Model, self).__init__(**kwargs)

        def __getattr__(self, key):
                try:
                        return self[key]
                except KeyError:
                        raise AttributeError('"Model" object has no attribute : %s' % key)
                
        def __setattr__(self, key, value):
                self[key] = value

        def save(self):
                fields = []
                values = []

                for k, v in self.__mappings__.items():
                        fields.append(v.name)
#                        values.append(getattr(self, k, None))
                        values.append(self[k])
                sql = "insert into %s(%s) values(%s);" % (self.__table__, ','.join(fields), ','.join( [str(value) for value in values] ))
                print(sql)

class User(Model):
        id = IntegerField("uid")
        name = StringField("username")
        passwd = StringField("password")
        em = StringField("e-mail")

u1 = User(id=123456, name="lfc", passwd='1q2w3e', em="123456789@qq.com")
u1.save()

输出为:

New model : User
table field : em-<StringField : e-mail>
table field : passwd-<StringField : password>
table field : name-<StringField : username>
table field : id-<IntegerField : uid>
insert into User(e-mail,password,username,uid) values(123456789@qq.com,1q2w3e,lfc,123456);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值