1.元类
什么是元类呢?
元类就是用来创建类的“东⻄”。函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
Python中所有的东⻄——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。
类也是对象
在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python中这一点仍然成立。但是,Python中的类还远不止如此。类同样也是 一种对象。是的,没错,就是对象。只要你使用关键字class,Python解释器在 执行的时候就会创建一个对象。
类的本质是对象,于是可以对类做如下的操作:
- 你可以将它赋值给一个变量
- 你可以拷⻉它
- 你可以为它增加属性
- 你可以将它作为函数参数进行传递
下面通过代码看一下每个操作的具体例子吧:
class Date(object):
pass
# 1. 你可以将它赋值给一个变量
date = Date
print(date)
# 2.你可以拷⻉它
import copy
date2 = copy.deepcopy(Date)
print(id(Date))
print(id(date2))
# 3.你可以为它增加属性
Date.year = 2019
print(Date.year)
# 4.你可以将它作为函数参数进行传递
def fun(cls):
print(cls)
fun(Date)
可以看到上面的操作都可以实现,各输出如下:
动态地创建类
因为类也是对象,你可以在运行时动态的创建它们,就像其他任何对象一 样。首先,你可以在函数中创建类,使用class关键字即可。
但这还不够动态,因为你仍然需要自己编写整个类的代码。由于类也是对象,所以它们必须是通过什么东⻄来生成的才对。当你使用class关键字时,Python解释器自动创建这个对象。但就和Python中的大多数事情一样,Python仍然提供给你手动处理的方法。
下面是动态创建类的方法:
另外,type还有一种完全不同的功能,可以动态的创建类。
type可以接受一个类的描述作为参数,然后返回一个类。(要知道,根据传入参数的不同,同一个函数拥有两种完全不同的用法是一件很傻的事情,但这在Python中是为了保持向后兼容性。)
type创建类的基本格式如下:
type(类名, 由父类名称组成的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
例如下面的代码:
MathStudent = type('MathStudent', (object, ), {'country': 'China'})
print(MathStudent)
print(MathStudent.__bases__)
print(MathStudent.__dict__)
print(MathStudent.country)
输出为:
注意:type的第2个参数,元组中是父类的名字,而不是字符串;添加的属性是类属性,并不是实例属性。
使用type创建带有方法的类
你希望为你的类增加方法。只需要定义一个有着恰当签名的函数并将其作为属性然后赋值就可以了。
- 添加类方法
- 添加实例方法
- 添加静态方法
示例代码如下:
def show():
print('show.....')
Date = type('Date', (), {'Show': show})
Date.Show()
输出为:
自定义元类
__metaclass__属性自定义元类:
可以在定义一个类的时候为其添加__metaclass__属性。Python会在类的定义中寻找__metaclass__属性,如果找到了,Python就会用它来创建类Foo,如果没有找到,就会用内建的type来创建这个类。
那么,__metaclass__属性有什么功能呢?
- 拦截类的创建
- 修改类
- 返回修改之后的类
注意:在python2中用法是 __metaclass__ = something…;python3中用法是再创建类时添加metaclass方法,示例如下:
def upper_attr(cls_name, bases, attr):
"""
:param cls_name: 类名称
:param bases: 父类名称(元组)
:param attr: 属性(字典)
:return:
"""
newAttr = {}
for key, value in attr.items():
newAttr[key.upper()] = value
print(newAttr)
return type(cls_name, bases, newAttr)
# python3的写法
class Student(object, metaclass=upper_attr):
# 自定义指定元类名称
# python2:
# __metaclass__ = upper_attr
country = 'China'
score = 100
s = Student()
# print(s.country) 这样会报错,因为所有属性名已经换成了大写
print(s.COUNTRY)
输出结果为:
可以看到通过metaclass方法,所有的属性名称都已经换成了大写字母。
2.python是动态语言
动态语言的定义:
动态编程语言是高级程序设计语言的一个类别,在计算机科学领域已被广泛应用。 它是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。动态语言目前非常具有活力。例如JavaScript便是一个动态语言,除此之外如PHP、Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。
动态语言与静态语言的不同?
- 动态语言:可以在运行的过程中,修改代码
- 静态语言:编译时已经确定好代码,运行过程中不能修改
运行的过程中给对象绑定(添加)属性和方法:
给类添加方法,是使用类名.方法名=xxxx,那么给对象添加一个方法也是类似的:对象.方法名=xxxx
对象.方法名=types.MethodType(方法名,对象名)
类名.方法名=方法名
运行的过程中删除属性、方法:
删除的方法:
- del 对象.属性名
- delattr(对象, "属性名")
动态添加和删除属性的例子如下:
from prettytable import PrettyTable
# 自省功能
# 判断;类里面是否包含指定的属性?
print(hasattr(PrettyTable, '__doc__'))
print(hasattr(PrettyTable, 'a'))
# 获取指定属性对应的内容;
print(getattr(PrettyTable, "__bases__"))
# print(getattr(PrettyTable, "a"))
# 设置指定的属性, 动态添加属性信息的
setattr(PrettyTable, 'a', 1)
print(getattr(PrettyTable, 'a'))
@staticmethod
def test():
print("这是一个测试方法")
if hasattr(PrettyTable, 'test'):
print(getattr(PrettyTable, 'test'))
else:
print("正在动态添加方法:")
setattr(PrettyTable, 'test', test)
print(getattr(PrettyTable, 'test'))
test = getattr(PrettyTable, 'test') # 返回的时函数名
test()
print(hasattr(PrettyTable, 'a'))
print("正在删除属性")
delattr(PrettyTable, 'a')
print(hasattr(PrettyTable, 'a'))
输出如下:
限制实例的属性 :
1. Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性 。
2. 使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
__slots__限制实例属性的例子如下:
class MyCounter(object):
# 限制属性的添加, 只能添加count和a;
__slots__ = ('count', 'a')
print(hasattr(MyCounter, 'a'))
counter = MyCounter()
counter.a = 1
print(counter.a)
# counter.b = 2
# print(counter.b) 因为只限制了添加count和a,所以这样会报错
输出结果为: