一、__slots__和property
1.__slots__魔术函数动态的添加方法和属性
2.直接暴露属性的局限性
3.使用get/set方法
4.利用@property简化get/set方法
5.利用@property实现只读属性
6.装饰器与property实现
# import traceback # from types import MethodType # # class MyClass(object): # # pass # #在做新的类的时候,限制动态添加的属性,这个时候需要用到__slots__魔术变量,系统内为了实现某些特定功能的 # __slots__ = ['name','set_name'] # 这个地方,能添加的属性和方法就会受到限制,只能添加name或者set_name这两个名词的属性或者方法 # def set_name(self,name): # self.name = name # cls = MyClass() #实例化类 # cls.name='Tom' #动态的添加属性 # cls.set_name=MethodType(set_name,cls) #动态的添加方法 将set_name作用于cls上面 # cls.set_name('Jerry') # print(cls.name) # try: # cls.age=30 #动态添加属性 ,这个地方要注意,age不在__slots__规定的数组中,所以会报错 # except AttributeError: # traceback.print_exc() #打印出异常信息 AttributeError: 'MyClass' object has no attribute 'age' # # class ExtMyClass(MyClass): #继承自MyClass # pass # ext_cls = ExtMyClass() # ext_cls.age=30 # print(ext_cls.age)
2.property
import traceback class Student: @property # 这个地方用装饰器进行修饰的时候,实际上是生成了一个新的对象,名字叫做score,这个相当于set函数 def score(self): return self._score @score.setter def score(self,value): if not isinstance(value,int): #进行value的类型检查,如果不是int型的值,就会报错not int raise ValueError('not int') elif (value<0) or (value>100): #如果value只不是在这个区间之间的话,就会报错值不在0~100之间,这个地方相当于get函数 raise ValueError('not between 0 ~ 100') self._score=value @property #注意,这里没有set方法,所以只能读取,不能写 def double_score(self): return self._score*2 s= Student() s.score=75 print(s.score) print(s.double_score) try: s.double_score=150 except AttributeError: traceback.print_exc() try: s.score='abc' except ValueError: traceback.print_exc() try: s.score=101 except ValueError: traceback.print_exc()
3.枚举类
from enum import Enum Month = Enum('Month',('Jan','Feb','Mar','Apr')) for name,member in Month.__members__.items(): print(name,'=>',member,',',member.value) jan = Month.Jan print(jan)
二、元类
1.运行时动态创建 vs 编译时定义
def init(self,name): #自定义构造函数, self.name=name def say_hello(self): #自定义成员函数 print('hello, %s!' %self.name) Hello = type('Hello',(object, ),dict(__init__ = init,hello=say_hello)) #(object, )是一个基类的列表 """ 这个地方的代码等价于下面的这些代码: class Hello: def __init__(.......) def hello(..........) """ h = Hello('Tom') h.hello()
2.使用type创建新类型
3.metaclass(元类)
(1)metaclass -> class -> instance
(2)继承和动态绑定可以解决问题吗?
(3)__new__函数
class ListMetaclass(type): def __new__(cls,name,bases,attrs): # print(cls) #打印出传进来的类时什么 # print(name) #打印出传进来的name是什么 # print(bases) #打印出传入进来的基类是什么 基类是list类 attrs['add'] = lambda self,value:self.append(value) return type.__new__(cls,name,bases,attrs) class MyList(list,metaclass=ListMetaclass): #从list类继承下来,就是一个数组,但是额外的增加add方法,实际等价于append pass mli = MyList() mli.add(1) mli.add(2) mli.add(3) print(mli)