it编程 > 软件设计 > 面向对象

面向对象编程:一切皆对象

102人参与 2024-08-02 面向对象

面向对象(oop)是一种编程范式,它使用''对象''来设计软件。对象可以包含数据和代码:数据代表对象的状态,而代码代表操作数据的方式。在面向对象编程中,一切皆对象,这意味着将现实世界事务使用类与实例来模拟,如灯,汽车,导弹,杯子,都可以用类和实例来模拟。

一 、类与实例

类是对现实世界描述的一种类型。它定义了一组具有相同属性和方法的对象的结构。类名通常使用大驼峰命名法,例如 electriccar

class electriccar:
    pass

类是抽象的,约定了未来实例应该有的内容,是实例的模板。

实例

实例是类的具现化。通过调用类来生成实例:

class electriccar:
    pass
my_car = electriccar()

实例是具体的,具有具体的数据。实例的内容依赖于类。

二、self

self 是类的一个特殊变量,用于代表未来的实例。在类的内部,self 用于访问类的属性和方法。

初始化函数

__init__ 是一个特殊的方法,称为构造器,用于初始化新创建的对象。

class electriccar:
    def __init__(self, make, model):
        self.make = make
        self.model = model

 魔法函数

python 提供了一系列特殊的方法,称为魔法函数,例如 __str____len__ 和比较方法 __eq__ 等。

# 内部编写所有魔法方法的使用案例
'''
以双下滑线开头和结尾的为魔法函数
__init__: 用于初始化对象。
__str__: 返回实例用字符串表示,自定义内容
__len__:当使用 len() 函数时调用,返回容器类型的长度。

实例与实例之间也可以比较了
__eq__ :==触发
__ne__ :!=触发
__gt__ :>触发
__ge__ :>=触发
__lt__ :< 触发
__le__ :<=触发

__add__ :+触发
__sub__ :-触发
__mul__ :*触发
__truediv:/触发
__floordiv__://触发
__mod__:%触发
__divmod__:div(x,y)触发
'''


# class myclass:
#     def __init__(self, name, age):
#         print('初始化函数执行了')
#         self.name = name
#         self.age = age
#
#     def __str__(self):
#         return f'姓名:{self.name},年龄:{self.age}'
#
#     def __len__(self):
#         return len(self.name)
#
#     def __gt__(self, other):
#         '''
#         用>来判断年龄大小
#         :param other:
#         :return:
#         '''
#         return self.age > other.age
#
#     def __lt__(self, other):
#         '''
#         用<来判断 年龄大小
#         :param other:
#         :return:
#         '''
#         return self.age < other.age
#
#     def __ge__(self, other):
#         '''
#         用>=来判断 年龄大小
#         :param other:
#         :return:
#         '''
#         return self.age >= other.age
#
#     def __le__(self, other):
#         '''
#         用<=来判断 年龄大小
#         :param other:
#         :return:
#         '''
#         return self.age <= other.age
#
#     def __eq__(self, other):
#         '''
#         判断两个实例age和name是否完全相等
#         :param other:
#         :return:
#         '''
#         return self.age == other.age and self.name == other.name
#
#     def __ne__(self, other):
#         '''
#         判断两个实例 age 或者 name 是否有一方不相等
#         :param other:
#         :return:
#         '''
#         return self.age != other.age or self.name != other.name
#
#     def __add__(self, other):
#         '''
#         返回两个实例的age相加
#         :param other:
#         :return:
#         '''
#         return self.age + other.age
#
#     def __mul__(self, other):
#         '''
#         返回两个实例的age乘积
#         :param other:
#         :return:
#         '''
#         return self.age * other.age
#
#     def __divmod__(self, other):
#         '''
#         先求除 再求余
#         :param other:
#         :return:
#         '''
#         return divmod(self.age, other.age)
#
#     def __mod__(self, other):
#         '''
#         返回两个实例的
#         :param other:
#         :return:
#         '''
#         return self.age % other.age
#
#
# mc = myclass('亲亲亲', 18)
# print(mc)
# # __len__
# print(len(mc))
#
# mc2 = myclass('顺子', 18)
# # __str__
# print(mc2)
# __gt__
# print(mc > mc2)
# # __lt__
# print(mc < mc2)
# # __ge__
# print(mc >= mc2)
# __le__
# print(mc <= mc2)
# __eq__
# print(mc == mc2)
# # __nq__
# print(mc != mc2)
# # __add__
# print(mc + mc2)
# # __mul__
# print(mc * mc2)
# __mod__
# print(mc % mc2)
# __divmod__
# print(divmod(mc, mc2))

构造函数与析构函数

构造函数用于创建实例,返回实例,通过父类来创建实例,super()._new()而析构函数在实例不再使用时执行,用于清理资源。

"""
构造函数:创建并且返回实例(self)
初始化函数: self已经创建完成,可以向self中添加数据
析构函数: 销毁实例 清理实例内存  实例不在使用则回收实例内存之前汇执行对应的析构函数
"""


# class myclass:
#     def __new__(cls, *args, **kwargs):
#         # 调用父类的new方法创建一个实例
#         instance = super().__new__(cls)
#         print(f"构造函数执行了", id(instance))
#         # 将创建好的实例返回 返回给初始化函数
#         return instances
#
#     def __init__(self, name):
#         print(f"初始化函数执行了", id(self))
#         self.name = name
#
#     def __del__(self):
#         print(f"析构函数执行了")
#
#
# mc1 = myclass("阿拉伯")
# print(id(mc1), id(none), mc1 is none)
#
# mc1 = none
# print("程序执行完毕  将要退出")
# #  程序退出执行析构mc1



class myopen:
    def __init__(self, filename, mode="r", encoding="utf8"):
        self.f = open(filename, mode=mode, encoding=encoding)

    def read_all(self):
        return self.f.read()

    def __del__(self):
        self.f.close()


mo = myopen("./65.魔法函数.py")
print(mo.read_all())

三、三大特性

封装

封装是将数据(属性)和操作数据的方法组合在一起的过程。封装确保了数据的安全性,只能通过特定的方法来访问和修改。

# 装饰器:一个函数,用于增强或修改另一个函数的行为,通常通过返回一个新的函数来实现。
import random
import time

datas = [random.randint(0, 10000) for i in range(10000)]
# 通过浅拷贝 得到一模一样的列表
datas_copy = datas.copy()


def time_cost(f):
    def calc():
        stat = time.time()
        f()
        print(f'{f}花费的时间开销为:{time.time() - stat}')

    return calc


@time_cost
def my_fun1():
    datas.sort()
    print(datas)


my_fun1()


@time_cost
def my_fun2():
    new_list = sorted(datas_copy)
    print(new_list)


my_fun2()

import random
import time

datas = [random.randint(0, 10000) for i in range(10000)]
# 通过浅拷贝 得到一模一样的列表
datas_copy = datas.copy()


def time_cost(f):
    def calc():
        stat = time.time()
        f()
        print(f'{f.__name__}花费的时间开销为:{time.time() - stat}')

    return calc


def fun1():
    datas.sort()
    print(datas)


fun1 = time_cost(fun1)
fun1()  # 此时的fun1()不是fun1()而是calc()


def fun2():
    new_list = sorted(datas_copy)
    print(new_list)


fun2 = time_cost(fun2)
fun2()  # 此时的fun2()不是fun2()而是calc()

继承

继承允许新创建的类(子类)继承现有类(父类)的属性和方法。

多继承

继承多个父类-java,c# 只支持单继承,通过接口等来实现多继承的功能,python直接就可以有多个父类。

# 多继承 继承多个父类

class speakable:
    def __init__(self, la):
        self.la = la

    def speak(self):
        return print(f'i can speak {self.la}')


class speedable:
    def __init__(self, speed):
        self.speed = speed

    def move(self):
        print(f'moving at a speed of {self.speed} km/h')


class person(speedable, speakable):
    def __init__(self, name, la, speed):
        self.name = name
        speedable.__init__(self, speed)
        speakable.__init__(self, la)

    def __str__(self):
        return f'name: {self.name}, language: {self.la}, speed: {self.speed}'


class atm(person):
    def __init__(self, name, speed, la, skill):
        super().__init__(name, la, speed)
        self.skill = skill

    def show(self):
        return print(f'{self.name},{self.speed},{self.la},{self.skill}')

    def attack(self):
        print(f'{self.name} is attacking with a skill: {self.skill}')


atmo = atm('赛罗', 1000, '光环语言', '赛罗光纤')
atmo.show()
atmo.move()
atmo.speak()
atmo.attack()
# 多继承 mro : method(方法) retrieval(检索)  order(顺序)
# python3 使用广度优先

# print(atm.mro())

多态

多态允许同一个接口接受不同的数据类型。在python中,多态是隐式实现的,不需要显式定义。

# 同名不同参数

# def my_fun(a):
#     print(a)
#
#
# def my_fun(a, b):
#     print(a, b)
#
#
# # 后一个的my_fun()覆盖掉了上方的my_fun
# my_fun(10, 2)


# 在面向对象编程中,子类可以重写父类的方法,当调用子类实例的方法时,将执行子类中的方法定义。
class animal:
    def walk(self, speed):
        print('walk')


class dog(animal):
    def walk(self, speed):
        print('run')


class cat(animal):
    def walk(self, speed):
        print('sheep')


# 类似于多态!结果以元组的形式输出
def my_fun(*args):
    print(args)


my_fun(10)
my_fun(10, 11)
my_fun(10, 11, 22)
my_fun(10, 11, 22, 33)


抽象类

抽象类是一种特殊的类,它不能被实例化,但可以包含抽象方法。子类继承抽象类时,必须实现这些抽象方法。

'''
抽象类是一种不能被实例化的类
'''

from abc import abc, abstractmethod


class animal(abc):
    '''
    通过装饰器abstractmethod把walk变为抽象方法
    '''

    @abstractmethod
    def walk(self):
        pass

    def eat(self):
        print('可以吃')


class dog(animal):
    def walk(self):
        print('dog can walk')


class cat(animal):
    def walk(self):
        print('cat can walk')


dog = dog()
dog.walk()  # 输出: woof!

cat = cat()
cat.walk()  # 输出: meow!

四、类中内容

实例属性

向实例中添加的数据,可以通过类内 self 或类外实例来添加。

实例方法

第一个参数是 self 的方法,可以通过类内或类外实例来调用。

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

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

    def __str__(self):
        return f'类名:{self.name} 类别:{self.sex}'


p = person('泉', '男')
print(p)

类属性

类属性可以通过类名直接访问和设置。

class myclass:
    # 类属性
    class_attribute = 'i am a class attribute'

    @classmethod
    def class_method(cls):
        print(cls.class_attribute)

    @classmethod
    def update_class_attribute(cls, new_value):
        cls.class_attribute = new_value


print(myclass.class_attribute)  # i am a class attribute

myclass.class_method()          # i am a class attribute

类方法

使用 @classmethod 装饰器的方法,第一个参数通常是 cls,表示类本身。

class myclass:
    @classmethod
    def class_method(cls):
        # cls 代表 myclass 类
        print(f"这是 {cls} 的类方法")


# 类方法可以通过类直接调用,也可以通过类的实例调用,但推荐通过类直接调用。

myclass.class_method()  # 推荐方式

# 实例也可以调用类方法,但这不是推荐的做法
my_instance = myclass()
my_instance.class_method()

静态方法

使用 @staticmethod 装饰器的方法,没有特殊的参数,通常用于辅助功能。

# 静态方法  不需要 self 或 cls 参数,不能访问类或实例的属性。
class gameperson:
    @staticmethod
    def play_name():
        pass

    @staticmethod
    def play_age():
        pass

    @staticmethod
    def play_sex():
        pass

    @staticmethod
    def play_address():
        pass


gameperson.play_name()
gameperson.play_age()
gameperson.play_address()
gameperson.play_sex()

五、python的灵活性

python 是一种解释性语言,允许动态地向类中添加内容,包括属性、方法等。

数据的访问级别

在面向对象编程中,数据的访问级别(也称为访问修饰符)用于控制类成员(属性和方法)的可见性和可访问性。python 没有像 java 或 c++ 那样的严格访问级别,但是它遵循一些约定来模拟访问控制。以下是 python 中常见的数据访问级别:

公有(public)
# 公有(public)
class car:
    def __init__(self, color):
        self.color = color  # 公有属性

    def start(self):    # 公有方法
        return f'the car starts.'

print(car.start())
私有(private)

六、属性封装 

使用 @property 装饰器可以创建只读属性,使用 @属性名.setter 可以定义设置属性值的方法。

上方的代码保护(protected)_color 属性是一个受保护的成员,这意味着它按照惯例应该只在类内部或子类中访问。然而,由于 python 的动态特性仍可以通过从类的外部访问和修改它。

为了更好地封装,可以使用属性装饰器 @property 来提供对属性的受控访问:

# 保护(protected)
class car:
    def __init__(self):
        self._color = 'red'  # 受保护的属性

    @property
    def color(self):
        # 只读属性,外部不能直接设置_color的值
        return self._color

    @color.setter
    def color(self, new_color):
        # 可以在这里添加验证逻辑
        self._color = new_color

# 使用 setter 方法修改颜色
car = car()
car.color = 'yellow'  # 使用属性的方式调用 setter 方法
print(car.color)  # 使用属性的方式获取颜色,将输出 'yellow'

在这个修改后的版本中,color 是一个属性,提供了对 _color 的受控访问。外部代码应该使用 car.color 来获取和设置颜色值,而不是直接使用 car._color。这样,您可以在 color 的 setter 方法中添加验证逻辑,确保属性值的有效性。

单例类

单例类确保只有一个实例存在。它通过控制构造函数来实现这一点。

class person:
    pass


# 每次调用类都可以生成一个新的实例
p1 = person()
p2 = person()
p3 = person()

print(p1 is p2, p2 is p3, p3 is p1)


class manage(object):
    instance = none

    def __new__(cls, *args, **kwargs):
        '''
        对构造函数进行控制 不是每次都生成新的实例
        1. 对类属性instance判断 如果为空 就构造一个实例 并且把实例赋予instance
        2. 对类属性instance判断 如果不为空 则直接把他返回
        '''
        if not manage.instance:
            manage.instance = super().__new__(cls)
        return manage.instance

    def __init__(self):
        print('初始化函数执行了')


m1 = manage()
m2 = manage()
print(m1 is m2, m1 is none, m2 is none)

结论

面向对象编程是一种强大的范式,它通过类和实例的概念,提供了一种自然的方式来模拟现实世界中的事务。python 的灵活性和动态特性使得oop在python中得以广泛应用。通过封装、继承和多态,oop提高了代码的可重用性、灵活性和可维护性。

(0)
打赏 微信扫一扫 微信扫一扫

您想发表意见!!点此发布评论

推荐阅读

ES6的类 vs TypeScript的类:解密两种语言中的面向对象之争

08-02

一行一行讲解深度学习代码(一)保姆级教程!!!如何看懂一个开源深度学习项目的代码

08-04

Scala 入门指南:从零开始的大数据开发

07-28

【大数据开发语言Scala的入门教程】

07-28

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论