关于Python的面向对象


本文是我第一个关于代码的文章作品,我会逐个解释介绍我所写的内容,尽量用一种通俗易懂的文字来阐述使得我的讲述便于大家理解。
PS:我以前一直觉得写此类文很麻烦,宁愿花时间去写小说或者研究游戏代码,也不想花很多时间去做一篇需要很严谨的文章。

面向对象

“面向对象”,到处都能听到这个词的解释。什么是对象,什么是面向对象,又怎么面向对象,这些到处都可以看到的各种定义我就不解释了。

对象(object)

具体解释对象是什么是一件比较麻烦的事。而实际上,在python中,没有什么不是对象。即你输入一个数字,它是int对象;在数字旁加上“ ’ ”(引号),它是str对象;再在前方加上一个“b”,它是一个bytes对象。

用print方法打印一个对象,即可看到它的样子。
试运行以下代码:

class A:
    pass

a = A()

print(a)
print(type(a))
print(A)

根据输入结果看来,其实很多对象样子是我们不想看到的样子。python的基本类型都可以直接打印看到结果,而其他对象的打印出来,我们看到的实际上是和html标签一样的<__main__.xxx object at 0x000001D3F3E2C8C8>,这就是对象,而它是什么对象,那就是紧跟着__main__.的xxx。
输出结果:

<__main__.A object at 0x000001D3F3E2C8C8>
<class '__main__.A'>
<class '__main__.A'>

第一个输出的,就是a这个变量所绑定的对象;
第二个输出的,是a的类型,为A类;
第三个输出的,是A类(这个A类,也是一个对象)。

因此,我们可以把对象进行分“类”,所属的类,就是对象分类的依据。而获取对象的办法,就是通过类实例化出一个对象:“()”。
如以上的a,通过类名A加括号的方式来实例化对象并绑定。

如果还不信,可以id()一下,看看对象在内存中存储的位置,没有加载的程序永远只是程序,程序跑起来了才有已经创建好的对象,此时才会占用内存。

类(class)

我用过这样一道题来考察过对对象的理解,其实很简单,但很容易出错:

class(object):
    def __init__(self, 价格: int, 名称: str):
        self.价格 = 价格
        self.名称 = 名称


class 手机():
    def __init__(self, 价格: int, 品牌: str, 名称: str):
        super().__init__(价格, 名称)
        self.品牌 = 品牌
        self.配件 = []

    def 搭配(self, 东西):
        self.配件.append(东西)
        self.价格 += 东西.价格


class 耳机():
    def __init__(self, 价格: int, 品牌: str, 名称: str):
        super().__init__(价格, 名称)
        self.品牌 = 品牌


class iphone(手机):
    def __init__(self):
        价格 = 9000
        品牌 = '苹果'
        名称 = 'iphone'
        super().__init__(价格, 品牌, 名称)


class Airpods(耳机):
    def __init__(self):
        价格 = 1000
        品牌 = '苹果'
        名称 = 'Airpods'
        super().__init__(价格, 品牌, 名称)


class 黑天鹅(耳机):
    def __init__(self):
        价格 = 300
        品牌 = '铁三角'
        名称 = '黑天鹅'
        super().__init__(价格, 品牌, 名称)


class 荣耀(手机):
    def __init__(self):
        价格 = 3000
        品牌 = '华为'
        名称 = '荣耀'
        super().__init__(价格, 品牌, 名称)


class(object):
    def __init__(self, 姓名: str, 性别: str, 外号: list = []):
        self.姓名 = 姓名
        self.性别 = 性别
        self.物品 = []
        self.钱数 = 10000
        self.外号 = 外号

    def(self, 东西:):
        if 东西.价格 <= self.钱数:
            self.钱数 -= 东西.价格
            self.物品.append(东西)
        else:
            print('没钱')

    def(self, 东西:):
        if 东西 in self.物品:
            self.物品.remove(东西)
            self.钱数 += 东西.价格
        else:
            print('没法卖')

注意:请不要在自己的代码中搞出这么多的中文,在此处这样写是因为没有实用意义,只是为了作为讲解使用,真正编写项目时请尽量遵守代码规范。(除非完全是自己用来玩的项目)

之后,执行以下语句会发生什么?

=('张三', '男', ['法外狂徒']) # 没错,在下就是罗翔老师口中的张三
need_result = [
    '我.买(荣耀())',  # 有什么变化?
    '我.买(iphone())',  # 能否成功?
    '我.卖(荣耀())',  # 有什么变化?
    '我.买(iphone())',  # 能否成功?
    '我.买(黑天鹅())',  # 有什么变化?
    '我.买(物(1000, "手表"))',  # 能否成功?
    '我.卖(物(1000, "手表"))',  # 有什么变化?
    '我.买(iphone().搭配(Airpods()))'  # 为什么不能成功?
]

实际上,在代码运行过程中,第三句是新实例化的对象,和以前的是不一样的,就像一个工厂先后加工出的两款手机,型号一样配置一样,对于手机个体来说,一定还是不用的(手机标识码一定不同)。
可以使用下面语句来验证:

# 运行代码检测
for need in need_result:
    print(need)
    try:
        eval(need)
        for 物品 in.物品:
            print(物品.名称)
    except Exception as error:
        print(error)
    finally:
        print(.钱数)
        print('-'*88)

而至于最后一句不能成功的原因,可能很多小白会认为与之前相同,钱不够买不起,实际上是因为此方法为默认的return None,虽然处理了本对象,但是并没有将本对象返回,相当于是我.买(None),如果在后面加上return self,将本对象返回,此时才可以直接将其置于方法中。

此时代码如下:

class(object):
    def __init__(self, 价格: int, 名称: str):
        self.价格 = 价格
        self.名称 = 名称


class 手机():
    def __init__(self, 价格: int, 品牌: str, 名称: str):
        super().__init__(价格, 名称)
        self.品牌 = 品牌
        self.配件 = []

    def 搭配(self, 东西):
        self.配件.append(东西)
        self.价格 += 东西.价格
        return self


class 耳机():
    def __init__(self, 价格: int, 品牌: str, 名称: str):
        super().__init__(价格, 名称)
        self.品牌 = 品牌


class iphone(手机):
    def __init__(self):
        价格 = 9000
        品牌 = '苹果'
        名称 = 'iphone'
        super().__init__(价格, 品牌, 名称)


class Airpods(耳机):
    def __init__(self):
        价格 = 1000
        品牌 = '苹果'
        名称 = 'Airpods'
        super().__init__(价格, 品牌, 名称)


class 呆鹅(耳机):
    def __init__(self):
        价格 = 300
        品牌 = '铁三角'
        名称 = '黑天鹅'
        super().__init__(价格, 品牌, 名称)


class 荣耀(手机):
    def __init__(self):
        价格 = 3000
        品牌 = '华为'
        名称 = '荣耀'
        super().__init__(价格, 品牌, 名称)


class(object):
    def __init__(self, 姓名: str, 性别: str, 外号: list = []):
        self.姓名 = 姓名
        self.性别 = 性别
        self.物品 = []
        self.钱数 = 10000
        self.外号 = 外号

    def(self, 东西:):
        if 东西.价格 <= self.钱数:
            self.钱数 -= 东西.价格
            self.物品.append(东西)
        else:
            print('没钱')

    def(self, 东西:):
        if 东西 in self.物品:
            self.物品.remove(东西)
            self.钱数 += 东西.价格
        else:
            print('没法卖')


if __name__ == '__main__':=('张三', '男', ['法外狂徒'])

    # 不运行代码时,判断以下结果
    need_result = [
        '我.买(荣耀())',  # 有什么变化?
        '我.买(iphone())',  # 能否成功?
        '我.卖(荣耀())',  # 有什么变化?
        '我.买(iphone())',  # 能否成功?
        '我.买(呆鹅())',  # 有什么变化?
        '我.买(物(1000, "手表"))',  # 能否成功?
        '我.卖(物(1000, "手表"))',  # 有什么变化?
        '我.买(iphone().搭配(Airpods()))'  # 为什么不能成功?
    ]

    # 运行代码检测
    for need in need_result:
        print(need)
        try:
            eval(need)
            for 物品 in.物品:
                print(物品.名称)
        except Exception as error:
            print(error)
        finally:
            print(.钱数)
            print('-'*88)

方法(def -> function)

讲对象为什么要讲方法,因为万物皆对象,使用def搞出来的方法,他也是一个对象。
首先方法是什么?通俗来说,方法就是用一定语句,达到一定的目的,同时将一些东西变为另一些东西。在开始到结束的过程中,我们有可能想要他的过程,有可能想要他的结果。

python是一个灵活的语言,你可以不用强迫症一样每个方法外一定都套一个类,也不用考虑它在内存中到底怎么存储会节省更多空间。如果只是为了能达到你的目的,编写其实很简单。

def a():
    pass

print(a)
print(type(a))

此时的输出如下:

<function a at 0x0000017673184948>
<class 'function'>

如果此时还有人在纠结为什么输出不同:为什么at后面那串数字不是很一样,那我建议你直接askdnbausfqioafw

好了没什么,有了上面的经验,很明显,方法是一个对象,类型为function,方法名就像是一个变量,在调用时便于取值;而实际上他就是一个变量,你也可以讲方法存在一个列表中,之后删除del掉他们的绑定关系,就像删除变量与对象的绑定关系一样,干掉他,之后你就会发现,该调用的还是可以调用,只是麻烦了很多。

def a(j):
    print('a is', j)


def b(j):
    print('b is', j)


def c(j):
    print('c is', j)


d = [a, b, c]

for i in d:
    i(i)


del a, b, c


for i in d:
    i(i)

你猜会输出什么?
当然,删除了并不是不在,这里会牵扯到python的垃圾处理机制,往下看看,你会发现:

a is <function a at 0x000001A9D94DE678>
b is <function b at 0x000001A9D94DE8B8>
c is <function c at 0x000001A9D9654438>
a is <function a at 0x000001A9D94DE678>
b is <function b at 0x000001A9D94DE8B8>
c is <function c at 0x000001A9D9654438>

再请注意,此处的is并非python语法中的is,是打印出的is.

看到了吧,实际上在上文给出的用汉字填满的代码中,汉字出现的部分,除了字符串,其余的都是变量,只是有的出现在绑定关系,赋值语句=的左侧,我们称他为变量;有的出现在def的后面,我们称他为方法名;另外一些出现在class后的,我们则称他为类名。

装饰器

毋庸置疑,装饰器是一个方法,它的作用实际上是为了加工方法或类,将一个方法变为另一个方法或者将一个类变为另一个类,为其附上新功能。而因为此特殊性也让他有了一个新用法@装饰器名,以此可以调用装饰器。
在下方附上一截普通代码来表示装饰器:

def decorator(function):
    def deal(param):
        return function(param) + 1
    return deal

这就是一个装饰器,如果需要解释,内层方法通过调用原方法使其与原方法产生关联,然后在通过对结果的处理来为其附上新功能,参数就可以写在内层方法中;要处理的方法,就得写在外层方法中的参数位置,以此可以使每次调用都可以传入新的方法对其进行处理。
而刚刚提到的内层方法的参数,实际上也是可以人为控制的,并非一定要与原方法相同,你可以多传参进行处理,也可以少传参在里面写死几行代码,只要你在调用原方法时传参与原方法参数匹配,这就是没有问题的。
装饰器其实就是这样的:

def function():
    pass
function = decorator(function)

从这也能看出,方法名其实也只是一个变量而已。
了解了这个,其实也可以通过多次调用装饰器来达到一个目的,每个装饰器加工后返回一个新方法,再传到上一层装饰器中继续加工。不过这个其实并不是很实用:

@decorator
@decorator
@decorator
@decorator
def b(i):
    return i*10

如果想要装饰器传参呢?我们还用上文中的“中文代码”,在原题基础上增加两题:

  1. 如果我们想要给每个手机出厂时带上一款呆鹅耳机
  2. 如果我们想要给每个手机出厂时带上一款出厂房想要带的耳机

涉及到了出厂,即要改变原类,在不改变源代码的情况下,最好的办法还是加装饰器。

我们再次重复装饰器:返回一个方法或类。我们现在想要一个类,最好是调用原类产生一个对象,为其附上我们想要的属性后再返回这个对象,这就是我们的新类。这个附上我们想要的属性的过程,就是我们需要加工的过程。

1题其实比较简单,下方直接给出一个2题的解法:

def 原装(耳机类型):
    def 搭配(手机类型):
        class 原装手机(手机):
            def __new__(cls, *args, **kwargs):
                出厂手机 = 手机类型()
                出厂手机.搭配(耳机类型())
                return 出厂手机
        return 原装手机
    return 搭配

内部的此部分内容,即为装饰器,外层是为了返回一个装饰器。调用时如此调用:

@原装(Airpods)
class iphone(手机):
    def __init__(self):
        价格 = 9000
        品牌 = '苹果'
        名称 = 'iphone'
        super().__init__(价格, 品牌, 名称)

首先运行原装(Airpods)此部分内容可以获取到装饰器,然后装饰器再加工下面的方法或类。
以此,装饰器的目的就达到了,为我们就可以选择是否手机附上了一款他想附带的耳机。

可能本文的内容还是对一些小白来说难以理解或者一时不好接受,大家可以在评论区说出一些问题,我收集到足够多的之后会出下一篇来进行解释。另外,如果大家有对对象思想独到的理解也可以指出;同时由于时间仓促,文中总会有一些内容出现bug,也欢迎大家指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盒刷念路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值