python里的class都有什么类型_如何理解python中的类_如何理解Python中的元类metaclass...

1、Python中的类

在理解元类之前,你需要掌握Python中的类。Python中借用了SmallTalk语言特性对类进行实现。

在大部分的语言中,类一般是一段生成对象的代码,这在Python中也一样。

>>> class ObjectCreator(object):

... pass

...

>>> my_object = ObjectCreator()

>>> print(my_object)

在Python中,类也是一种对象。当执行如下代码时,Python会申请一块内存保存名为ObjectCreator的对象。

>>> class ObjectCreator(object):

... pass

...

生成的对象(类)拥有创造对象(实例)的能力,因此称为类。

作为对象,因此它能够像对象一样操作:

可以给变量赋值

可以复制

可以增加属性

可以作为函数参数传递

>>> print(ObjectCreator) # you can print a class because it's an object

>>> def echo(o):

... print(o)

...

>>> echo(ObjectCreator) # you can pass a class as a parameter

>>> print(hasattr(ObjectCreator, 'new_attribute'))

False

>>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class

>>> print(hasattr(ObjectCreator, 'new_attribute'))

True

>>> print(ObjectCreator.new_attribute)

foo

>>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable

>>> print(ObjectCreatorMirror.new_attribute)

foo

>>> print(ObjectCreatorMirror())

(推荐一个q裙,小伙伴们在学习的过程中遇到了什么问题都可以一起交流解决,点击裙号就可跳转啦610 380 249)

2.动态生成类

类可以像对象一样动态生成。

首先使用class关键字对类进行定义

>>> def choose_class(name):

... if name == 'foo':

... class Foo(object):

... pass

... return Foo # return the class, not an instance

... else:

... class Bar(object):

... pass

... return Bar

...

>>> MyClass = choose_class('foo')

>>> print(MyClass) # the function returns a class, not an instance

>>> print(MyClass()) # you can create an object from this class

以上方式并不是那么动态,因为你需要自己定义整个类。而类本身作为一个对象是可以通过其他来生成的,Python中允许手动定义类----通过使用type关键字完成类的定义

>>> print(type(1))

>>> print(type("1"))

>>> print(type(ObjectCreator))

>>> print(type(ObjectCreator()))

以上是通过type关键字进行类型查看,但是type还有另一种完全不同的能力--创建类。输入类的描述参数来生成对应的类(为什么type会根据输入参数的不同而表现出两种完全不同的功能,主要是需要满足Python向后兼容)

以下为type使用方式,需要类的名称,可能继承的父类元祖,包含属性键值对的字典三个输入参数

type(name of the class,

tuple of the parent class (for inheritance, can be empty),

dictionary containing attributes names and values)

>>> class MyShinyClass(object):

... pass

%可以换成另一种方式:

>>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object

>>> print(MyShinyClass)

>>> print(MyShinyClass()) # create an instance with the class

在手动创建类时,使用了MyShinyClass作为类的名字,同时也用同样的名字对该类进行引用。这两个名字可以不一样,如a=type('MyShinyClass',....),但没必要搞复杂。

type接受一个字典来定义类中的属性

>>> class Foo(object):

... bar = True

%可以转换成:

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

%可以作为正常的类来使用:

>>> print(Foo)

>>> print(Foo.bar)

True

>>> f = Foo()

>>> print(f)

>>> print(f.bar)

True

这样的类也能继承:

>>> class FooChild(Foo):

... pass

%可以写为:

>>> FooChild = type('FooChild', (Foo,), {})

>>> print(FooChild)

>>> print(FooChild.bar) # bar is inherited from Foo

True

当你需要给你的类添加方法(属性)的时候,通过函数段定义,并将其传递给type输入属性参数即可。

>>> def echo_bar(self):

... print(self.bar)

...

>>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})

>>> hasattr(Foo, 'echo_bar')

False

>>> hasattr(FooChild, 'echo_bar')

True

>>> my_foo = FooChild()

>>> my_foo.echo_bar()

True

这样你就可以为创建的类动态的添加你需要的属性。

3、那么什么是元类呢?

元类(Metaclass)是创建类的元素。之前已经了解了可以通过类来创建实例对象,那么元类可以用来创建类对象,是类的类。

MyClass = MetaClass()

my_object = MyClass()

结合上文通过type来创建MyClass,我们可以了解type实际上就是元类,Python中使用type作为所有类的元类。可以通过__class__属性来查看类别。在Python中一切都是对象,不管是整数、字符串、函数还是类。但追根溯源,type是python中所有对象的元类,以下代码解释了这个机制。

>>> age = 35

>>> age.__class__

>>> name = 'bob'

>>> name.__class__

>>> def foo(): pass

>>> foo.__class__

>>> class Bar(object): pass

>>> b = Bar()

>>> b.__class__

>>> age.__class__.__class__

>>> name.__class__.__class__

>>> foo.__class__.__class__

>>> b.__class__.__class__

type是內建元类(built-in),但是可以创建自己的元类。

__metaclass__属性

在Python2中,你可以在创建类时给类添加一个__metaclass__属性,Python会使用这个元类属性来创建类对象Foo

class Foo(object):

__metaclass__ = something...

当执行class Foo(object)时,Python首先在__metaclass__中寻找类的定义,如果有,就用来创建类对象Foo,如果没有找到,Python会调用type方法创建类对象Foo。

当执行以下代码时,Python的编译过程如下:

class Foo(Bar):

pass

判断Foo中是否有__metaclass__属性?如果有,分配内存并使用__metaclass__属性创建以Foo为名的类对象;如果没有找到,Python会在当前模块里寻找该属性;如果还没有找到,那就会用父类Bar的元类(可能是默认的type)来创建类对象。这里需要注意,Foo从Bar处继承,但不会继承Bar的__metaclass__属性。如果Bar的使用type()来作为__metaclass__机制创建子类的话,那么子类不会继承这种创建机制。

而在Python3.x中,元类语法与2.x中不同。

class Foo(object, metaclass=something):

...

__metaclass__属性换成了关键字参数,传递给类对象,但元类的其他行为大体是相同的。3.x中新增的是可以按照关键字参数将属性传递给元类,如下:

class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):

...

4、自定义元类

元类的主要作用是,在创建类时自动改变类的一些属性。当进行类似于调用APIs操作时需要创建对应匹配的类。

举一个例子,如果你想把模块中的所有类的属性名都使用大写,那其中一个可以实现的方式就是使用元类定义,设置__metaclass__。只需要告诉元类需要把属性转换成大写,这样在创建类对象是就可以自动满足。

如下一个简单例子:

# the metaclass will automatically get passed the same argument

# that you usually pass to `type`

def upper_attr(future_class_name, future_class_parents, future_class_attr):

"""

Return a class object, with the list of its attribute turned

into uppercase.

"""

# pick up any attribute that doesn't start with '__' and uppercase it

uppercase_attr = {}

for name, val in future_class_attr.items():

if not name.startswith('__'):

uppercase_attr[name.upper()] = val

else:

uppercase_attr[name] = val

# let `type` do the class creation

return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr # this will affect all classes in the module注意这一行代码,会影响当前模块中的所有类

class Foo(): # global __metaclass__ won't work with "object" though

# but we can define __metaclass__ here instead to affect only this class

# and this will work with "object" children

bar = 'bip'

print(hasattr(Foo, 'bar'))

# Out: False

print(hasattr(Foo, 'BAR'))

# Out: True

f = Foo()

print(f.BAR)

# Out: 'bip'

现在我们换成另一个方式,定义一个元类:

# remember that `type` is actually a class like `str` and `int`

# so you can inherit from it

class UpperAttrMetaclass(type):

# __new__ is the method called before __init__

# it's the method that creates the object and returns it

# while __init__ just initializes the object passed as parameter

# you rarely use __new__, except when you want to control how the object

# is created.

# here the created object is the class, and we want to customize it

# so we override __new__

# you can do some stuff in __init__ too if you wish

# some advanced use involves overriding __call__ as well, but we won't

# see this

def __new__(upperattr_metaclass, future_class_name,

future_class_parents, future_class_attr):

uppercase_attr = {}

for name, val in future_class_attr.items():

if not name.startswith('__'):

uppercase_attr[name.upper()] = val

else:

uppercase_attr[name] = val

return type(future_class_name, future_class_parents, uppercase_attr)

这个方式不太符合面向对象编程的准则,这里我们直接调用了type方法而没有重写或使用父类的__new__方法。我们改变一下:

class UpperAttrMetaclass(type):

def __new__(upperattr_metaclass, future_class_name,

future_class_parents, future_class_attr):

uppercase_attr = {}

for name, val in future_class_attr.items():

if not name.startswith('__'):

uppercase_attr[name.upper()] = val

else:

uppercase_attr[name] = val

# reuse the type.__new__ method

# this is basic OOP, nothing magic in there

return type.__new__(upperattr_metaclass, future_class_name,

future_class_parents, uppercase_attr)

这里你会发现多出一个upperattr_metaclass参数,这个是由于__new__方法总是把它定义的类作为第一个参数接受,类似于普通类定义中的self,为简洁可用cls来代替。通常可以使用较短的参数名,如下:

class UpperAttrMetaclass(type):

def __new__(cls, clsname, bases, dct):

uppercase_attr = {}

for name, val in dct.items():

if not name.startswith('__'):

uppercase_attr[name.upper()] = val

else:

uppercase_attr[name] = val

return type.__new__(cls, clsname, bases, uppercase_attr)

当然我们还可以使用super来使得类的继承更加简洁。

class UpperAttrMetaclass(type):

def __new__(cls, clsname, bases, dct):

uppercase_attr = {}

for name, val in dct.items():

if not name.startswith('__'):

uppercase_attr[name.upper()] = val

else:

uppercase_attr[name] = val

return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

回到Python3.x中对元类的使用:

class Foo(object, metaclass=Thing, kwarg1=value1):

...

%可以转换成如下:

class Thing(type):

def __new__(class, clsname, bases, dct, kwargs1=default):

...

元类的介绍差不多就这些。

元类在实际中最主要的应用是生成API,典型应用是Django的ORM

(转载:csdn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值