Python-面向对象

文章目录

定义类示例:

# 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)  # 二哈
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值