关于类的学习

参考  点击打开链接

 在python中类也是一个对象,创建类的几种方法

(1)可以在运行时动态创建,就像其他任何对象一样。

    首先,在函数中创建类,然后返回类,后面的其他地方可以调用这个函数来返回这个类,赋值给类名,再根据这个类名实例化对象。

(2)内建函数type的另外一种用法,他可以动态创建类,

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

Foo = type('Foo', (), {'bar':True})

FooChild = type('FooChild', (Foo,),{})  #继承了Foo类

    这里type实际就是一个元类,就是Python在背后创建所有类对象的元类,其他的类实际就是元类的实例化对象。

    str是用来创建字符串对象的类,Int是用来创建整数对象的类,type就是用来创建类对象的类。

Python中所有的东西,注意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来。

__class__指的应该是显示某个一对象的类的名称,比如:

age = 35 name = 'bob'

age.__class__ name.__class__

<type 'int'> <type 'str'>

对于任何一个__class__的__class__属性都可以看到是 age.__class__.__class__ 都是<type 'type'>

因此,元类就是创建这种type这样的东西,可以将元类叫做‘类工厂’,type就是python的内建元类。

我们所需要做的就是创建自己数据库的元类,因为后面的每一个表对应一个类,再由这个对象实例具体的表(对象),这里用来创建的类和内置的类不太一样,不能只是单纯的继承内置的type元类,应该自己设计自己的元类。

(3)创建元类

__metaclass__的使用

class Foo(object):

    __metaclass__ = something...

上面的这段代码,产生的效果是用元类来创建Foo。当写下class Foo(object):时,类对象Foo还没有在内存中创建。python会在类的定义(在哪里)中寻找metaclass属性,如果找到了,就用它创建类Foo,如果没有找到,就会用内建的type来创建这个类。

class Foo(Bar):

    pass

上面的代码python做了如下操作,查看Foo中有没有__metaclass__属性,如果有,python会在内存中通过__metaclass__创建一个名为Foo的类对象。如果python没有找到,他会在Bar(父类)中继续寻找__metaclass__属性。如果在任何一个父类中都找不到。它就会在模块层次去寻找__metaclass__,并尝试做同样操作。如果还是找不到,就会用内置的type来创建这个类对象。

所以当我们定义映射表的类时,这个类和一般创建类的方法不一样,他要通过专门的__metaclass__创建这个类对象。所以会在__metaclass__后面指示也就是元类的名称,这样现在创建的这个class就会根据元类来创建。创建类都比较简单,所以我们需要做的就是创建这个元类。也就是__metaclass__后面的这个里面放置的代码。就是type,或者任何使用type或者子类化type的东东都可以。

__metaclass__ = upper_attr  #  这会作用到这个模块中的所有类,upper_attr方法是将所有类的属性的名称都改为大写
class Foo(object):
    # 我们也可以只在这里定义__metaclass__,这样就只会作用于这个类中

    bar = 'bip'

这里就是所有的类方法都会使用__metaclass__后的upper_attr方法,这里方法就是元类,不过元类并不需要是一个正式的类,所以比如这里可以是一个方法。

__new__是在__init__之前调用的特殊方法,是用来创建类对象并返回修改之后的方法,如果希望能够控制对象的创建(比如创建的类中的属性小写改为大写,比如为要创建的类对象增加属性方法),这个创建的对象是类,我们希望自定义他,就需要改写__new__。

关于__new__中的几种不同的返回方式,返回后的就是修改之后的创建类的方式,

    1、return type(future_class_name, future_class_parents, uppercase_attr),type是父类,这样是直接调用了type,并且没有改写父类的__new__方法。没有OOP编程的思想。

    2、return type.__new__(upperattr_metaclass,future_class_name, future_class_parents, uppercase_attr)这个就是加了一个额外的参数,upper_metaclass,类方法的第一个参数总是表示当前的实例,就像在普通的类方法中的self参数一样。当然了,为了清晰起见,这里的名字我起的比较长。但是就像self一样,所有的参数都有它们的传统名称。因此,在真实的产品代码中一个元类应该是像这样的:

    3、return type.__new__(cls,name,bases,uppercase_attr)这也是通常定义一个元类需要传入的参数,

        cls:当前准备创建的类的对象;所以上面才说第一个参数表示当前的实例。

        name:类的名字;就是当前的实例的名字,这个实例是一个类。

        base:类继承的父类的集合,是作为这个实例的一个传入参数

        attr:类的方法的集合

    4、return super(UpperAttrMetaclass,cls).__new__(cls,name,bases,uppercase_attr)使用super方法的话,我们还可以使它变得更清晰一些,这会缓解继承(是的,你可以拥有元类,从元类继承,从type继承)

元类的作用:

1)   拦截类的创建

2)   修改类

3)   返回修改之后的类

元类就是在类的定义的最开始做个标记__metaclass__,表示在创建这个类的实例对象的时候去查找这个属性后面的方法、函数、类,去修改这个类,比如增加些类的方法或者修改些类的方法,修改后再返回修改之后的类。

(4)为什么用元类

“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。”  —— Python界的领袖 Tim Peters

    元类主要用处是创建API。一个典型的例子是Django ORM。见Dajongo学习—没看

(5)动态修改类

    虽然元类可以修改类的定义,但是大多数情况下,没有像需要大量使用这种元类的时候,可以通过使用以下两种技术修改类:

1) Monkey patching

2)   class decorators


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值