basicPython-3

类和对象

公有属性

"""类和对象(公有)"""


# 创造一个正义派的神仙类
class God:
    # 共有属性
    occupation = "神"
    character = "善良"

    # __init__方法(对象初始化)
    def __init__(self, name, grade):
        self.name = name
        self.grade = grade

    def infomation(self):
        print("神级强者 [%s] 的修炼等级为 [%s]" % (self.name, self.grade))


# 实例化对象
obj_1 = God("唐三", 150)
obj_2 = God("马红俊", 110)

# 调用对象的方法
obj_1.infomation()

私有属性

"""类和对象(私有)"""


# 创建一个电影类
class Movie:
    # 私有属性
    __stuff = '电影'
    __the_style = '抗日神剧'

    # __init__方法(初始化对象)
    def __init__(self, name, public_time):
        self.__name = name
        self.__time = public_time

    # 私有方法
    def __infomation(self):
        print(f"""
        物品:{Movie.__stuff}
        类型:{Movie.__the_style}
        名称:{self.__name}
        发布时间:{self.__time}
        """)

    # 私有方法
    def __change(self):
        dict_info = {
            '0': '取消修改',
            '1': '名称',
            '2': '发布时间'
        }
        while True:
            for i in dict_info:
                print(f"{i}:{dict_info[i]}")
            func_num = input('请输入功能号>>>')
            if func_num == '0':
                return
            elif func_num == '1':
                self.__name = input('修改名称为:').strip()
                return
            elif func_num == '2':
                self.__time = input('修改时间为:').strip()
                return
            else:
                print('请输入正确的功能号!')

    # 共有方法(为上面的私有属性和私有方法提供一个对外使用的接口)
    # 即:上面的所有私有属性和私有方法都无法直接调用,
    # 而是通过下面的get方法进行统一安全管理,间接性达到---调用或修改---的目的
    def get(self):
        print('可执行的功能')
        dict_info = {
            '0': '退出',
            '1': '修改信息',
            '2': '查看信息'
        }
        while True:
            for i in dict_info:
                print(f"{i}:{dict_info[i]}")
            func_num = input('请输入功能号>>>')
            if func_num == '0':
                return
            elif func_num == '1':
                self.__change()
                return
            elif func_num == '2':
                self.__infomation()
                return
            else:
                print('请输入正确的功能号!')


# 创建对象(实例化对象):
movie_1 = Movie('黑狐', 2016)
movie_2 = Movie('铁血使命', 2013)

"""下面是使用对象的部分"""
# 1.检测能否调用私有属性和私有方法
# print(movie_1.stuff)
# movie_2.infomation()

# 2.通过get入口,正常的调用私有属性和私有方法
movie_1.get()

@property

"""类和对象(将一个属性转化为一个方法时候,可以在方法上面加一个@property装饰器)"""

"""
例如,定义一个矩形类,
并定义用 @property 修饰的方法操作类中的 area 私有属性,
代码如下:
"""


# 高级玩法
class Rect:
    def __init__(self, area):
        self.__area = area

    @property
    def area(self):
        return self.__area


# 实例化对象
obj_1 = Rect(10)

# 间接调用私有属性"__area"
print(obj_1.area)

"""
小结:
以"."点的形式调用,不知道的人还以为它是"属性",但其实它是"方法"
而又因为"方法"的"封装"特性,所以数据被"神不知鬼不觉的保护起来了"
例如,某个"菜鸡黑客"以为它是"属性",想通过" obj_1.area = 60 "这语句
对数据进行篡改,但他惊讶的发现,既然失效了?他很困惑,但我们却都明白
这个所谓的 obj_1.area 根本就不是属性,而是经过伪装的"方法(函数)"
"""


# 低级玩法:
class Rect_ordinary:
    def __init__(self, area):
        self.__area = area

    def area(self):
        return self.__area


# 实例化对象
obj_2 = Rect_ordinary(10)

# 间接调用私有属性"__area"
print(obj_2.area())

"""
小结:
这种方式,菜鸡黑客一眼看穿它是"方法"而不是属性,
所以,他会立刻寻找其他方法进行数据篡改,
而不是一脸懵逼的思考为什么直接篡改不了
"""

"""总结"""
# 既要保护类的封装特性,又要让开发者可以使用“对象.属性”的方式操作类属性,Python 提供了 @property 装饰器。
# 通过 @property 装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对“()”小括号。

增删改查

"""类和对象("读" "改" "删")"""


# 为私有属性 __age 提供 "读" "改" "删" 的操作
# 即:为私有属性 __age 提供 getter() setter() deleter() 方法
# 注意!对某数据提供"读" "改" "删"的前提是>>>数据有"读"操作---getter方法,因为可读,证明数据存在
class Human():
    def __init__(self, age):
        self.__age = age

    # 下面的操作是getter方法,即:"读"
    @property
    def age(self):
        return f"年龄>>>{self.__age}"

    # 注意,在定义setter方法时,方法名称必须与只读属性的名称相同,并且应该在定义getter方法之后
    # 下面的操作是setter方法,即:"改(设置)"
    @age.setter
    def age(self, new_age):
        if type(new_age) is not int:
            raise "数据错误! 请传入int数据类型!"
        if not 0 <= new_age <= 150:
            raise "数据错误!请输入0~150范围的数据!"
        self.__age = new_age

    # 注意的地方同setter方法一样
    # 下面的操作是deleter方法,即:"删"
    @age.deleter
    def age(self):
        del self.__age
        print("已删除")


# 创建对象
obj_1 = Human(18)

"""调用对象功能"""

# 执行"读"操作---getter
print(obj_1.age)

# 执行‘改’的部分---setter
obj_1.age = 10
print(obj_1.age)  # 验证

# 执行‘删’的部分---deleter
del obj_1.age

类方法

"""类方法"""


class Hero:
    # 实例方法————之构造方法
    def __init__(self, age):
        self.__age = age

    # 实例方法————之读取年龄方法
    def info(self):
        return self.__age

    # 类方法
    @classmethod
    def creat_obj(cls, age):
        obj_new = cls(age)
        return obj_new

    # 静态方法(对象和类都可以调用它,而且也没有了自动传参的效果了)
    @staticmethod
    def func():
        print("我是个静态方法,跟放到'类'外面的普通函数没什么区别")


# 创建对象
obj_1 = Hero(188)

"""执行部分"""

# 调用对象的---实例方法---info()
print(obj_1.info())

# 调用Hero类的---类方法---create_obj()
print(Hero.creat_obj(666).info())

# 调用---静态方法
obj_1.func()
Hero.func()

继承

"""继承"""


# 父类
class Human:
    star = 'earth'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 子类(1)
class Chinese(Human):
    nation = 'China'

    def speak_chinese(self):
        print(f"{self.name}正在说普通话")

    def __init__(self, name, age, gender, money):
        Human.__init__(self, name, age, gender)
        self.money = money


# 子类(2)
class American(Human):
    nation = 'America'

    def speak_English(self):
        print(f'{self.name}正在说英语')


# 实例化对象
dy_obj = Chinese('董永', 18, "男", 1000)

# 调用部分
dy_obj.speak_chinese()
print(dy_obj.star)
print(dy_obj.nation)

MixIns 机制

"""MixIns机制"""


# mix in 混合


class Fowl:  # 家禽类
    pass


class SwimMixIn:  # 这个类,必须表示某种功能而不是事物
    def swimming(self):
        pass


class Chicken(Fowl):  # 鸡类
    pass


class Duck(SwimMixIn, Fowl):  # 鸭类
    pass


class Goose(SwimMixIn, Fowl):  # 鹅类
    pass

super

"""super()方法---是用于调用父类的一个方法"""

"""

首先提一下,新式类和经典类:
新式类都从object继承,经典类不需要
super只能用在新式类里面,不能用在经典类

super() 是用来解决"多重继承"问题的
当子类继承多个父类时候,先查找哪个父类??
通过 "类名.mro" 可以查看super的调用表
此表是根据某算法得出---解决了查找问题

super()函数的用法:
以下面的代码为例
super(Chinese, self).__init__()
1.根据mro的调用表查找--输入的"chinese类"后面的类是什么[而输入的self一般不变]
2.super-->将它下一个类返回(假设chinese类的下一个类是A类,则返回A类)
3.A类.__init__() ---> 调用 它的__init__()方法

补充:
如果在Human类中,要写 super(Human, self).xxx
可以直接使用 super().xxx (简写模式,但这种写法仅在 Python 3 中支持)

"""


# 父类
class Human:
    star = "earth"

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 子类(1)
class Chinese(Human):
    nation = "China"

    def speak_chinese(self):
        print(f"{self.name}正在说普通话")

    def __init__(self, name, age, gender, money):
        super(Chinese, self).__init__(name, age, gender)
        self.money = money


# 子类(2)
class American(Human):
    nation = "America"

    def speak_English(self):
        print(f'{self.name}正在说英语')


# 实例化对象
dy_obj = Chinese('董永', 18, "男", 1000)

# 调用部分
print(Chinese.mro())

多态

"""多态"""


class Car:
    def run(self):
        print("开始跑", end=' ')


class Benz(Car):
    def run(self):
        super().run()
        print('加98号汽油')


class Lx(Car):
    def run(self):
        super().run()
        print("充电")


class Auto(Car):
    def run(self):
        super().run()
        print("加92号汽油")


# 实例化:造三台汽车
car1 = Benz()
car2 = Lx()
car3 = Auto()

car1.run()
car2.run()
car3.run()

print('\n', Benz.mro())

反射

"""反射"""

""" 反射机制---"判断" "读取" "修改" "删除" XXX的属性"""
# hasattr()
# getattr()
# setattr()
# delattr()
"""
补充:
getattr(obj, 'name', False) 它可以传3个参数
如果 obj 没有 ’name‘ 这个属性
它将返回--->我们指定的’第三个参数‘
在本例中,它会返回 False
"""


class Hero():
    def __init__(self, name):
        self.name = name


# 创建对象
obj = Hero("yexun")

# 判断对象obj是否有"name"的属性,有则返回True,否则False
print(hasattr(obj, 'name'))

# 读取对象obj的"name"属性
print(getattr(obj, 'name'))

# 修改对象的的"name"属性
setattr(obj, 'name', 'I am not yexun again!')
print(obj.name)

# 删除对象的"name"属性
delattr(obj, 'name')
print(obj.__dict__)

"""反射的具体案例:(体验一下它的魅力)"""


class Ftp:
    def put(self):
        print('正在上传数据...')

    def get(self):
        print('正在下载数据...')

    def warning(self):
        print('此功能不存在!')

    def use(self):
        option = input('请输入功能>>>')
        # [读取对象]getattr(obj, 'name', XXX) 如果对象obj没有"name"属性,它将返回第三个参数XXX
        getattr(self, option, self.warning)()


# 创建对象
obj_new = Ftp()

# 使用ues()方法来"控制"其他方法
while True:
    s = input("\nQ退出>>>").strip()
    if s == "Q" or s == "q":
        break
    obj_new.use()

其他方法

"""
__str__方法(可以实现 print(对象) 得到一个自定义的值)
注意!使用这个函数必须要有"字符类型"的返回值!
"""

""" 1.普通打印对象 """


class Human:
    def __init__(self, name):
        self.name = name


# 实例化对象
obj_1 = Human("Xiao_Ming")

# 打印对象,得到的是它的内存空间的地址
print(obj_1)

""" 2.使用__str__"改变"打印对象的效果 """


class Hero:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "哈哈哈"


# 实例化对象
obj_2 = Hero("Peter")

# 打印对象,得到的是__str__的返回值
print(obj_2)

""" __ del__方法 """
# 通常,它是程序运行完之后,需要释放内存空间,才运行__del__方法。也就需要删除对象
# 除非,你在程序过程中调用了它,它就会执行

补充内容

# class People:
#     def __init__(self, name):
#         self.__name = name
#
#     def name(self):
#         return self.__name
#
#     name666 = property(name)
#
#
# obj = People('yexun')
# print(obj.name666)


# class People:
#     def __init__(self, name):
#         self.__name = name
#
#     @property
#     def name(self):
#         return self.__name
#
#
#
# obj = People('yexun')
# print(obj.name)

# class People:
#     def __init__(self, name):
#         self.__name = name
#
#     def get_name(self):
#         return self.__name
#
#     def set_name(self, name):
#         self.__name = name
#
#     def del_name(self):
#         print('del error')
#
#     name123 = property(get_name, set_name, del_name)
#
#
# obj = People('yexun')
# print(obj.name123)
# obj.name123 = '王强'
# print(obj.name123)
# del obj.name123


class People:
    def __init__(self, name):
        self.__name = name

    @property
    def name123(self):
        return self.__name

    @name123.setter
    def name123(self, name):
        self.__name = name

    @name123.deleter
    def name123(self):
        print('del error')


obj = People('yexun')
print(obj.name123)
obj.name123 = '王强'
print(obj.name123)
del obj.name123
# class People:
#     def __init__(self, name, age, sex):
#         self.name = name
#         self.age = age
#         self.sex = sex
#
#     def f1(self):
#         print(self.name)
#
#
# class Teacher(People):
#     def __init__(self, name, age, sex, level, salary):
#         People.__init__(self, name, age, sex)
#         self.level = level
#         self.salary = salary
#
#
# obj = Teacher('yexun', 18, 'male', 10, 3000)
# print(obj.__dict__)


class People:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def f1(self):
        print(self.name)


class Teacher(People):
    def __init__(self, name, age, sex, level, salary):
        # 在Python3 中直接写super().__init__...即可达到同样的效果
        super(Teacher, self).__init__(name, age, sex)
        self.level = level
        self.salary = salary


obj = Teacher('yexun', 18, 'male', 10, 3000)
print(obj.__dict__)

print(Teacher.mro())

print(isinstance(obj, Teacher))  # 判断对象是否为该类的实例

# '我爱你'.__repr__()   # 交互

造类

认识元类

"""造类"""

"""定制一个Human类"""

# 1 类名
class_name = 'Human'

# 2 基类
class_bases = (object,)

# 3 类子代码
class_dict = {}
class_body = """
def __init__(self, name, age):
    self.name = name
    self.age = age

def scan_age(self):
    print(self.name, "年龄:", self.age)
"""
exec(class_body, {}, class_dict)

# 4 调用元类
abc = type(class_name, class_bases, class_dict)  # 元类处理完毕后,会返回一个返回值---即Human类,但是你可以用 abc 或其他符号 接着这个类.
# 通过以上的步骤和代码,我们已经造好了一个类,这整个过程等价于我们平时用 class XXX 造的类


# 看看这个类名:
print(abc)  # abc 不是类,也不是类名, abc只是一个承接着----'类名为 Human 的 类' 的工具. 因此可以通过它调用Human类.
# 注意,也可将 abc 换成 Human,这样操作更方便,也更人性化.

# 通过这个自定义类,看看是否能够成功实例化对象

# 实例化:
person = abc('Xiao Ming', 18)
# 运行一下对象:
person.scan_age()

自定义元类

"""造类"""

"""
1.
class Human(Father) 等价于 class Human(Father, metaclass=type)
元类放到最后,Human类
最后面的参数 metaclass=type的意思是
默认使用内置的元类---"type"
"""

"""
2.
如果类定义了__call__方法,那么它的实例可以变为可调用对象
调用方式>>> 对象()   # 像函数一样
"""

"""
网络编程.
__new__方法先被调用,返回一个实例对象,接着 __init__ 被调用
__new__方法的返回值就是类的实例对象,
这个实例对象会传递给 __init__ 方法中定义的 self 参数,
以便实例对象可以被正确地初始化
 
如果 __new__ 方法不返回值(或者说返回 None)
那么 __init__ 将不会得到调用,这个也说得通,
因为实例对象都没创建出来,调用 init 也没什么意义

__init__方法负责对象的初始化,系统执行该方法前,
其实该对象已经存在了,要不然初始化什么东西呢?
"""

"""
4.
自定义一个类   ----> 使用 ----> 得到"初始化的对象"(可进一步使用对象的属性和方法)
自定义一个元类 ----> 使用 ----> 得到"初始化的类"
"""

"""
5.
class Myselftpye(type):

    # 一个能造"空对象"的新工厂(自己的__new__) == 底层的原始工厂(官方的__new__) + 自己添点东西
    def __new__(cls, *args, **kwargs):
        # Python 网络编程 可以使用直接使用 super().__new__ 代替 super(Class, self).__new__
        return super().__new__(cls, *args, **kwargs)

    # 将"空对象"进行初始化加工
    def __init__(self, name, bases, dic):
        if "_" in name:
            raise NameError("类名不能有下划线")
        if not dic.get('__doc__'):
            raise SyntaxError('定义类必须写注释')

    # 它的实例可以变为可调用对象:
    # 例如当self为Human时候,使用"Human()"就会执行下面的代码
    def __call__(self, *args, **kwargs):
        ...
"""

"""
下面这个自定义元类 Mytpye 是在"继承"了官方的元类 type 的基础上
对__call__这个方法进行了'个性化重造' 
"""


# 自定义元类
class Mytpye(type):

    # 它的实例可以变为可调用对象:
    # 例如当self为Human时候,使用"Human()"就会执行下面的代码
    def __call__(self, *args, **kwargs):  # (Human, XiaoMing, ?)
        cls_obj = self.__new__(self)  # cls_obj = Human.__new__(Human) "返回空对象赋值给cls_obj"
        self.__init__(cls_obj, *args, **kwargs)  # Human.__init__(空对象, XiaoMing, ?)为空对象进行初始化


# 创建一个Human类
class Human(object, metaclass=Mytpye):
    def __new__(cls, *args, **kwargs):  # (Human, ?, ?)
        obj = object.__new__(cls)  # object.__new__(Human) "返回一个空对象"
        return obj

    def __init__(self, name):
        self.name = name


# 实例化对象
obj_1 = Human("XiaoMing")

使用元类

"""造类"""

"""
查看当前对象的属性
print(obj.__dict__)

为了方便用户查看类中包含哪些属性,
Python 类提供了 __dict__ 属性。
需要注意的一点是,该属性可以用类名或者类的实例对象来调用,
用类名直接调用 __dict__,会输出该由类中所有类属性组成的字典;
而使用类的实例对象调用 __dict__,会输出由类中所有实例属性组成的字典。
"""


class Base(type):

    # class()将触发__call__()方法
    def __call__(self, *args, **kwargs):  # 参数(Human, ("Peter", 19), ?)
        obj = self.__new__(self)  # Human.__new__(Human) 返回值为"空对象"
        self.__init__(obj, *args, **kwargs)  # Human.__init__(空对象, ("Peter", 19), ?)

        # 改造开始
        dict_new = {}
        for key in obj.__dict__:
            dict_new[f"YX_{key}"] = obj.__dict__[key]
        obj.__dict__ = dict_new
        # 改造完成

        return obj  # class()--->[返回一个初始化好的对象]


class Human(object, metaclass=Base):

    def __new__(cls, *args, **kwargs):  # 参数(Human, ?, ?)
        obj = object.__new__(cls)  # 创建了空对象>>>object.__new__(Human)
        return obj

    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 经过了"改造部分",对象的name属性变成了对象的YX_name属性,同理age属性变成了YX_age属性
    def info(self):
        print("姓名>>>%s\n年龄>>>%d" % (self.YX_name, self.YX_age))


# Human类的实例化:
person = Human("Peter", 220)

# 应用
print(person.__dict__)  # obj.__dict__以字典的形式展示"对象"的属性

person.info()  # 使用对象的info方法

print(Human.__dict__)  # class.__dict__以字典的形式展示"类"的属性

单例模式

前三种方法

"""
单例模式【实现方法有以下的6种】
1.模块
2.类装饰器
3.类绑定方法
4.__new__方法
5.元类
6.并发
"""

# 1.用模块实现
"""
A.创建一个新的Python文件
B.在这个文件里面写入以下代码:

class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj = Human('Xiao Ming', 18)

3.在另一个Python文件中写入以下代码:

from settings import obj
from settings import obj
from settings import obj
# 不论导入多少次模块,都是同一个对象
# 即:实现了单例的模式
"""

# 2.类装饰器
from functools import wraps


def singleton_mode(cls):
    obj = None

    @wraps(cls)
    def wrapper(*args, **kwargs):
        nonlocal obj
        if not obj:
            obj = cls(*args, **kwargs)
        return obj

    return wrapper


@singleton_mode  # Human = singleton_mode(Human)
class Human:
    def __init__(self, name, age):
        self.name = name
        self.age = age


obj_1 = Human('Xiao Ming', 90)
print(obj_1.name123, obj_1.age)

obj_2 = Human('Zhang San', 20)
print(obj_2.name123, obj_2.age)

print(obj_2 is obj_1)

后三种方法

# """
# 单例模式【实现方法有以下的6种】
# 1.模块
# 2.类装饰器
# 3.类绑定方法
# 4.__new__方法
# 5.元类
# 6.并发
# """
#
#
# # 3.类绑定方法
# class Human:
#     obj_1 = None
#
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
#     @classmethod
#     def get_obj(cls, *args, **kwargs):
#         if not cls.obj:
#             cls.obj = cls(*args, **kwargs)
#         return cls.obj
#
#
# obj_1 = Human.get_obj('Xiao Ming', 90)
# obj_2 = Human.get_obj('Xiao Ming', 20)
# print(obj_2 is obj_1)
#
#
# # 4、__new__方法
# class Human:
#     obj_1 = None
#
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
#     def __new__(cls, *args, **kwargs):
#         if not cls.obj:
#             cls.obj = super().__new__(cls)  # 等价于 object.__new__(Human) 不信的话可以使用print(Human.__mro__)检验
#         return cls.obj
#
#
# obj_1 = Human('张大仙', 73)
# obj_2 = Human('张大仙', 75)
# print(obj_1)
# print(obj_2)
#
#
# # 5.元类方法
#
#
# class Mytpye(type):
#     obj_1 = None
#
#     def __call__(self, *args, **kwargs):
#         if not self.obj:
#             self.obj = self.__new__(self)
#         self.__init__(self.obj, *args, **kwargs)
#         return self.obj
#
#
# class Singleton(metaclass=Mytpye):
#     pass
#
#
# class Human(Singleton):
#
#     def __init__(self, name, age):
#         self.name = name
#         self.age = age
#
#
# obj_1 = Human('Xiao Ming', 20)
# print(obj_1.__dict__)
#
# obj_2 = Human('Zhang Tao', 66)
# print(obj_2.__dict__)
#
# print(obj_2 is obj_1)

你可能感兴趣的:(Python基础,python)