面向对象高级编程


关于类的一些高级操作

class Chain(object):
    def __init__(self, path=''):
        self._path = path

    def __getattr__(self, path):

        return Chain('%s/%s' % (self._path, path))

    def users(self, name):
        return Chain('%s/users/:%s' % (self._path, name))

    def __str__(self):
        return self._path

    __repr__ = __str__
print(Chain().users('lovelyfrog').repos)
/users/:lovelyfrog/repos

使用元类

type()

str是用来创建字符串对象地类,int是用来创建整数对象的类,而type就是创建类对象的类

def fn(self, name='world'):#先定义函数
    print('hello, %s' % name)
Hello = type('Hello', (object,), dict(hello=fn)) #创建Hello class
  • 要创建一个class对象,type()函数依次传入3个参数:

1.class的名称
2.继承的父类集合,是个tuple
3.class方法名称与函数绑定,dict

通过type()函数创建的类和直接写class是完全一样的,因为python解释器遇到class定义时会自动扫描一下class定义的语法,然后调用type()函数创建class.

type()函数允许我们动态创建类,也就是说,动态语言本身支持运行期间动态创建类

动态地创建类

def choose_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return Foo
    else:
        class Bar(object):
            pass
        return Bar
MyClass = choose_class('foo')
print (MyClass)
<class '__main__.choose_class.<locals>.Foo'>
print (MyClass())
<__main__.choose_class.<locals>.Foo object at 0x0000021FF34BADD8>

metclass

除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass(元类)

如果我们想创建出类,就必须根据metaclass创建出类,所以先定义metaclass然后创建类,换句话说可以把类看成metaclass创建出来的实例

  • 我们可以在写一个类的时候为其添加metaclass属性
class Foo(object):
    __metaclass__ =  something...
[...]

如果这么做了,python就会用元类来创建Foo。

class Foo(Bar):
    pass
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

<ipython-input-28-ee44de34193a> in <module>()
----> 1 class Foo(Bar):
      2     pass


NameError: name 'Bar' is not defined

在上面的代码中python做了如下地操作:
Foo 中有metaclass这个属性吗,如果是python会在内存中通过metaclass创建一个Foo的类对象,如果没有找到,它会继续在Bar(父类)中寻找metaclass属性,并尝试做和前面同样的操作。如果最终还是找不到,则用内置的type来创建这个类对象

自定义元类

元类的主要目的就是为了当创建类的时候可以自动地改变类,比如你决定在你的模块中所有的类属性都是大写

#元类会自动将你通常传给‘type’的参数作为自己的参数传入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一个类对象,将属性都转为大写形式'''
    #选择所有不以‘__’开头的属性
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
    #将它们转为大写形式
    upper_attr = dict((name.upper(), value) for name, value in attrs)
    #通过type来做类对象的创建
    return type(future_class_name, future_class_parents, upper_attr)

class Foo(object, metaclass=upper_attr):
    bar = 'bip'
print (hasattr(Foo, 'bar'))
False
f = Foo()
print(f.BAR)
bip
# 用一个真正的class当作元类,metaclass是类的模板,所以必须要从type类派生
class UpperAttrMetaClass(type):
    #__new__是在__init__之前被调用的方法
    #__new__是用来创建对象并返回之的方法
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        upper_attr = dict((name.upper(), value) for name, value in attrs)
        return type(future_class_name, future_class_parents, upper_attr)
class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        upper_attr = dict((name.upper(), value) for name, value in attrs)
        return type.__new__(cls, name, bases, upper_attr)

python中的一切都是对象,他们要么是类的实例,要么是元类的实例,除了type,type实际上是它自己的元类

按照默认习惯,metaclass的类名总是以Metaclass结尾,以清楚地表示这是一个metaclass

class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda cls, value: cls.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list, metaclass=ListMetaclass):
    pass
L = MyList()
L.add(1)
L
[1]

而普通的list没有add()方法

L2=list()
L2.add(1)
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-73-0a75f2c80b37> in <module>()
      1 L2=list()
----> 2 L2.add(1)


AttributeError: 'list' object has no attribute 'add'

尝试编写一个ORM框架

#首先定义Field类,它负责保存数据库表的字段名和字段类型
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)
        print('Found model: %s' % name)
        mappings = dict()
        for k,v in attrs.items():
            if isinstance(v, Field):
                print('Found mapping: %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)
#定义基类Model
class Model(dict, metaclass=ModelMetaclass):
    def __init__(self, **kw):
        super(Model, self).__init__(**kw)
    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError:
            raise AttributeError(r'Model object has no attribute %s' % key)
    def __setattr__(self, key, value):
        self[key] = value

    def save(self):
        fields = []
        params = []
        args = []
        for k,v in self.__mappings__.items():
            fields.append(v.name)
            params.append('?')
            args.append(getattr(self, k, None))
        sql = 'insert into %s (%s) values (%s)' %(self.__table__, ','.join(fields), ','.join(params))
        print('SQL: %s' %sql)
        print('ARGS: %s' %str(args))
#先把调用接口写出来
class User(Model):
    id_num = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')
Found model: User
Found mapping: id_num==><IntegerField:id>
Found mapping: password==><StringField:password>
Found mapping: email==><StringField:email>
Found mapping: name==><StringField:username>
u = User(id_num=12345, name='lovelyfrog', email='lovelyfrog@qq.com', password='zbq19970216')
u.save()
SQL: insert into User (password,id,email,username) values (?,?,?,?)
ARGS: ['zbq19970216', 12345, 'lovelyfrog@qq.com', 'lovelyfrog']
sdd = ['a','b','c']
','.join(sdd)
'a,b,c'

文章作者: lovelyfrog
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lovelyfrog !
 上一篇
python编码转换与中文处理 python编码转换与中文处理
关于字符的处理 python文件的编码python 脚本文件默认都是采用ANSCII编码的,当文件中有非ANSCII编码范围内的字符时,需要“编码指示”来修正module中的定义,比如# --coding=utf-8--或者#codin
2017-08-23
下一篇 
关于python高级函数的一些操作 关于python高级函数的一些操作
返回函数和装饰器 函数作为返回值 python 调用高阶函数返回其内部一个函数时,会保存高阶函数中的参数,这种称为‘闭包’的结构具有很大的威力 def lazy_sum(*args): def sum(): ax
2017-08-13
  目录