python中的类
type这个方法有什么用?
首先纠正一个错误,type并非一个方法,而是一个类(扎心了老铁)。
>>> type(dict)
<class 'type'>
>>> type(type)
<class 'type'>
>>> type(object)
<class 'type'>
很奇怪的一个现象,似乎所有类都是type类,不是说所有类都是从object继承来的啊,为什么连object自己都是type类型呢?
这要归功于Python是一种解释型语言,并非像C++,Java一样属于编译型语言,在编译型语言中,要在静态语言运行期创建类,必须构造源代码字符串再调用编译器,或者借助一些工具生成字节码实现。而动态语言,则是在运行期间创建类,那么怎么创建类,其实就是用的type
。
定义类的两种方法
# 直接定义
class Hello(object):
'Hello'
times = 0
def hello(self,name='world'):
print('Hello,%s.' % name)
self.times += 1
# type
def fn(self,name='world'):
print('Hello,%s.' % name)
self.times += 1
Hello = type('Hello',(object,),dict(times=0,hello = fn))
这两种方法,实现的效果相同。
现在看看type的定义:
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
只截取了一小部分,type类可以实现两种功能,
- 显示对象的类型
- 创建一个新的
type
所以,当我们给type()传入相应的值(变量或名字,基类,数字字典),他就动态的创建了一个类。
元类 MetaClass
元类:用来定义类的类
一般来说,我们都是在代码里定义类,用定义的类来创建实例。而使用元类,步骤又是不同,定义元类,用元类创建类,在使用创建出来的类来创建实例。
# metaclass是类的模板,所以必须从'type'类派生:
# 习惯上 元类的类名是以Metaclass结尾
class ListMetaclass(type):
def __new__(cls,name,bases,attrs):
attrs['add'] = lambda self,value:self.append(value)
return type.__new__(cls,name,bases,attrs)
class MyList(list,metaclass=ListMetaclass):
pass
这段代码很简单,我们实现了一个MyList,它拥有add
方法,实际上就是append
,当然,如果元类仅仅能做到这么没用的事,那我宁可不做。
用元类将类中的类变量及方法改为大写
class UpperMetaclass(type):
def __new__(cls,name,bases,attrs):
print('first in metaclass')
new_attrs = dict()
for k,v in attrs.items():
if not k.startswith('__'):
new_attrs[k.upper()] = v
else:
new_attrs[k] = v
return type.__new__(cls,name,bases,new_attrs)
class Upper(object,metaclass=UpperMetaclass):
num = 0
def __init__(self,name,password):
print('then in init')
self.name = name
self.password = password
分析一下代码:
定义了一个元类,在它的__new__
方法中将所有不以__
开头的属性转换为大写,然后创建一个类。
print(dir(Upper))
==>
first in metaclass
['NUM', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
可以看出num被变成大写的了。
print(dir(Upper('lyt','lyt')))
==>
first in metaclass
then in init
['NUM', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'password']
可以看出,num变成大写了,但name,password没有,这个原因是显而易见的,由于元类是在生成类时发挥作用的,故而可以控制类变量,但不能控制生成实例时产生的实例变量。