关于Python的面向对象

  • 面向对象
    • 对象(object)
    • 类(class)
    • 方法(def -> function)
    • 装饰器

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

面向对象

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

对象(object)

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

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

class A:passa = 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.钱数 = 10000self.外号 = 外号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 selfclass 耳机(物):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.钱数 = 10000self.外号 = 外号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():passprint(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, cfor 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) + 1return 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,也欢迎大家指正。

关于Python的面向对象相关推荐

  1. 16.1、python初识面向对象(1)

    初识面向对象 楔子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做<人狗大战>的游戏,你就思考呀,人狗作战,那至少需要2个角色,一个是人, 一个是狗,且人和狗都有不同的技能,比如人 ...

  2. Python初识面向对象

    一.Python初识面向对象 1.1 封装 class Person:country='中国' #静态字段,可以直接调用def __init__(self,name,pwd): #Python类自带的 ...

  3. Python之面向对象类和对象

    Python之面向对象类和对象 定义一个类:class 定义类的语法: class Test(object):"""类里定义一类事物共同的技能.可以是变量,也可是函数.& ...

  4. Python之面向对象进阶

    Python之面向对象进阶 进阶有:Python 类的成员.成员修饰符.类的特殊成员. 一.类的成员 类的成员可以分为三大类:字段.方法和属性. 注:所有成员中,只有普通字段的内容保存对象中,即:根据 ...

  5. python 内存溢出能捕获吗_从0基础学习Python (19)[面向对象开发过程中的异常(捕获异常~相关)]...

    从0基础学习Python (Day19) 面向对象开发过程中的=>异常 什么是异常 ​ 当程序在运行过程中出现的一些错误,或者语法逻辑出现问题,解释器此时无法继续正常执行了,反而出现了一些错误的 ...

  6. Python之面向对象继承和派生

    Python之面向对象继承和派生 什么是继承: 继承是一种创建新的类的方法.在Python中,新建的类可以继承自一个或多个父类.原始类称为基类或超类. 新建的类称为派生类或子类. Python中类的继 ...

  7. python基础——面向对象的程序设计

    python基础--面向对象的程序设计 1 什么是面向对象的程序设计 面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...

  8. python是面向对象还是面向过程的语言_关于python是面向对象还是面向过程的分析...

    关于python是面向对象还是面向过程的分析 发布时间:2020-04-07 16:10:55 来源:亿速云 阅读:24 作者:小新 今天小编给大家分享的是关于python是面向对象还是面向过程的分析 ...

  9. Python之面向对象的程序设计

    Python之面向对象的程序设计 优点:解决了程序的扩展性,对某一个对象单独修改.会立刻反应到整个体系中,如对一个游戏中人物参数的特征和技能进行修改都很容易. 缺点:可控性差,无法向面向过程的程序设计 ...

最新文章

  1. 经典贪心法:时间序列问题及其全局最优性证明
  2. 观看自由!B站上线斯坦福最新「机器学习系统(MLSys)」全集
  3. Win8Metro(C#)数字图像处理--2.14Prewitt 边缘检测
  4. 2108 ACM 向量积 凹凸
  5. 中年失业都去做什么_2020年失业是种什么体验?这位吉他手去做了外卖小哥,演出时还穿着工作服...
  6. 除非另外还指定了 TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。...
  7. 局域网Ubuntu与WinXP实现文件共享
  8. CentOS Linux服务器实现攻防演练
  9. 如何获取jar包的在执行机上面的路径
  10. ios 解压下载数据包(zip)
  11. 图像处理_如何保存浮点型数值的图像? (C++ / OpenCV)
  12. shell 批量修改文件名字
  13. 复制VIM编辑的文件和代码到别的地方
  14. Java使用自动化测试脚本selenium
  15. PS 模糊图片背景(滤镜)
  16. NTFS文件系统结构及文件恢复
  17. windows10去桌面图标小箭头和恢复小箭头
  18. 探索汇率变动与股票价格的关系
  19. ABAP基本语法(一)附带思维导图学习材料等
  20. 自我提升解决bug的能力(一)

热门文章

  1. 基于ESp8266的智能插座
  2. git push 拒绝连接_git push被拒绝的处理方式
  3. 在自建虚拟环境中出现的问题
  4. 记录今天解决的一个poi的问题
  5. js截取url问号前面_JS获取URL中问号后面参数值
  6. Warning:The `android.dexOptions.incremental` property is deprecated and it has no effect on the buil
  7. 用格布拉斯准则剔除异常值,求不确定度
  8. SVN各种错误提示产生原因及处理方法
  9. U盘和存储卡实际上可以轻松的创建隐藏分区制作PE启动盘
  10. leaflet运动轨迹