类
定义类示例:
# Python3定义类时会默认继承object类;Python2中不会默认继承object
# 未继承object的类是经典类;继承了object的类是新式类
class Animal(): # 动物类
"""
文档注释
"""
height = 0.0 # 公有静态属性
__weight = 0.0 # 私有静态属性
# __new__在__init__之前被调用,__new__的返回值会传递给__init__的第1个参数
def __new__(cls, *args, **kwargs):
# __new__必须要有返回值,返回实例化出的实例
return super().__new__(cls)
def __init__(self, name='Animal'):
# 私有:两个下划线开头,但不以两个下划线结束
# 私有仅是一种语法意义上的变形:
# 仅在类定义阶段会将私有变成:_类名__私有名,因此在类外访问时需要访问_类名__私有名
# 对象/类.__名称,不会变形为_类名__名称
self.__sex = "雄" # 私有成员变量
# 公有:即非私有
self.name = name # 公有成员变量
print("构造函数,生成对象时调用")
def __del__(self):
print("析构函数,释放对象时使用")
def __call__(self, *args, **kwargs):
"""
可以让这个类实例化出的对象像函数一样变成一个可调用的对象
"""
return "动物类"
def __str__(self):
print("类似于toString")
return self.name
# 对象方法:绑定给对象,对象调用时会将本对象自动传值给第1个参数,对象调用时不需要传递
def eat(self):
print("Animal %s eat" % self.name)
# 类方法:绑定给类,类调用时会将本类自动传值给第1个参数,类调用时不需要传递
@classmethod # 只能访问静态成员;对象和类都可调用
def attack(cls):
print("classmethod")
# 静态方法:就是一个普通函数,因此没有自动传值
@staticmethod # 只能访问静态成员;对象和类都可调用
def defense():
print("staticmethod")
@property
def sex(self):
"""
把方法装饰成属性使用:
@property、
@被@property装饰的方法名.setter、
@被@property装饰的方法名.deleter
@property默认提供一个只读属性,
如果需要修改,则需要搭配@被@property装饰的方法名.setter;
如果需要删除,则需要搭配@被@property装饰的方法名.deleter。
"""
return self.__sex
@sex.setter
def sex(self, sex):
self.__sex = sex
@sex.deleter
def sex(self):
del self.__sex
import abc
# 将类设为抽象类:使用metaclass关键字参数指定元类为abc.ABCMeta
class FlyableMixin(metaclass=abc.ABCMeta): # 飞行能力类;mix in即混入的意思
# 抽象类中被@abc.abstractmethod装饰的方法是抽象方法
@abc.abstractmethod # 若子类没有同名方法,则会抛异常
def fly(self):
pass
class Dog(Animal): # 狗类,单继承
pass
# 括号内的基类从左往右为查找方法/属性的顺序,这样可以解决菱形继承问题
# 新式类和经典类都会按照深度优先查找,但新式类会最后再找object
class Bird(Animal, FlyableMixin): # 鸟类,多继承
# 多继承时,默认使用第一个父类的同名属性和方法
def __init__(self):
super().__init__()
# 重写抽象方法
def fly(self):
pass
animal = Animal('旺财') # 创建对象
# 调用对象就是调用类中的__call__方法
print(animal())
# 给对象添加属性(仅属于这个对象)
animal.age = 18
# 给类添加静态属性(被类和所有实例共有)
Animal.food = "骨头"
# 对象._类名私有属性名,可以在类外部访问私有静态属性和私有成员变量
print(animal._Animal__weight, animal._Animal__sex)
# 类名._类名私有属性名,可以在类外部访问私有静态属性
print(Animal._Animal__weight)
Animal.__speed = 50 # 仅会在类定义阶段给私有添加前缀:_类名
print(Animal.__speed)
# 将被装饰的方法当属性使用
animal.sex = "雌"
print(animal.sex)
del animal.sex
# 通过对象调用公有对象方法
animal.eat()
# 通过类名调用公有对象方法
Animal.eat(animal)
# 以下内置函数可以访问对象的属性->反射
print(getattr(animal, 'eat')) # 获取animal对象的eat属性
print(hasattr(animal, 'name')) # 判断animal对象是否有name属性
setattr(animal, 'name', '二哈') # 给animal对象设置/修改一个age属性,值为二哈
delattr(animal, 'name') # 删除animal对象的name属性
# 对象的常用内置属性
print(animal.__doc__) # 对象所属类的文档注释
print(animal.__dict__) # 对象的数据成员信息
print(animal.__module__) # 对象所在的模块名
print(animal.__class__) # 对象所属类的类名
# 类的常用内置属性
print(Animal.__doc__) # 类的文档注释
print(Animal.__dict__) # 类的所有属性和方法
print(Animal.__module__) # 类所在的模块
print(Animal.__name__) # 类名
print(Animal.__bases__) # 所有父类
print(Animal.__mro__) # 继承的层次关系元组
print(Animal.mro()) # 继承的层次关系列表
元类
类也是一个对象,元类就是产生这种对象的类;一个类的默认元类为type,使用metaclass关键字参数可以为一个类指定元类
# class关键字创建一个类的大致过程:
# 1. 获取类名
class_name = "Animal"
# 2. 获取所有基类
class_base = (object,)
# 3. 执行类体代码,获取类的命名空间
class_dict = {} # 类的命名空间
source = """
def __init__(self, name):
self.name = name
def info(self):
print(self.name)
""" # 类体代码
"""exec参数说明:
参数1:字符串形式的Python源码
参数2:字典形式的全局作用域,默认为globals()
参数3:字典形式的局部作用域,默认为locals()
"""
exec(source, {}, class_dict)
print(class_dict)
# 4. 调用元类创建出类这个对象
# type类实例化出了Animal类这个对象
Animal = type(class_name, class_base, class_dict)
print("一个类的默认元类为", type(Animal)) # 一个类的默认元类为 <class 'type'>
# Animal对象实例化出了animal对象
animal = Animal("二哈")
animal.info() # 二哈
print(type(animal)) # <class '__main__.Animal'>
通过继承type来自定义元类可以控制类的创建过程
class Metaclass(type): # 自定义元类:继承type
def __new__(cls, *args, **kwargs):
return type.__new__(cls, *args, **kwargs)
def __init__(self, class_name, class_bases, class_dict):
super().__init__(class_name, class_bases, class_dict)
def __call__(self, *args, **kwargs):
# 调用animal = Animal("二哈")的大致过程:
# 1. 调用Animal的__new__产生一个空对象
obj = self.__new__(self) # 推荐使用self.__new__(self)产生对象
# 会按照继承关系找__new__,直到找到object
# print(self.__new__ is object.__new__)
# 2. 调用Animal的__init__初始化空对象
self.__init__(obj, *args, **kwargs)
# 初始化后就可以操作对象了,如:将对象的所有属性变成私有
obj.__dict__ = {'_%s__%s' % (self.__name__, k): v for k, v in obj.__dict__.items()}
# 3. 返回初始化好的对象
return obj
class Animal(metaclass=Metaclass): # 使用metaclass指定元类
def __init__(self, name):
self.name = name
def info(self):
print(self.name)
# animal.属性,如果object没有,则会抛异常
# Animal.属性,如果object没有,则会在元类中找
animal = Animal("二哈")
print(animal._Animal__name) # 二哈