11. Pythin语言的面向对象(上)
Pythin语言的面向对象(上)
- 1. 面向对象简介
- 2. 类(class)
- 3. 对象的创建流程
- 4. 类的定义
- 5. 类中的属性和方法
- 6. 参数self
- 总结小便条
1. 面向对象简介
Python 是一门 面向对象 的 编程语言。
所谓 面向对象的语言,简单理解就是:语言中的 所有操作 都是通过 对象 来进行的。
还是有点抽象,那我们来打几个 比方:你想做件事,你要先去找个 对象;你想要一个 数值,我先找一个 对象 来保存需要的 数值,之后再对 对象 进行调取;你想要一个 字符串,我先找一个 对象 来保存需要的 字符串,之后再对 对象 进行调取;你想要一个 函数,我要先有一个 函数对象 来保存需要的 函数,之后再对 对象 进行调取……回到最初,我们开篇讲的第一句话:Python一切皆对象。这就是对 面向对象的语言 的简单理解。
在我们进入 面向对象 的世界之前,我们先来对 编程思想 的发展简单的了解一下。
面向对象 的 编程思想 是由 面向过程 的 编程思想 在实际操作过程中一步一步更进和迭代衍化过来的。那什么是 面向过程 呢?
面向过程:
面向过程 指将我们的程序 分解 为一个一个的 执行步骤,通过对 每个步骤 的 抽象 来完成程序;
举个例子:孩子想吃瓜了,怎么办?
1. 妈妈穿衣服穿鞋出门
2. 妈妈骑上电动车
3. 妈妈到超市门口放好电动车
4. 妈妈买西瓜
5. 妈妈 结账
6. 妈妈骑电动车回家
7. 到家孩子吃西瓜
案例看完了,其实整个的这些步骤如果要编写一成一个程序,我们一般会按照 面向过程 的编写方法进行编写;从 妈妈穿衣服穿鞋出门 --> 到家孩子吃西瓜 这整个步骤就是一个 面向过程 的编写思想;这整个事情的 目的 呢,我们需要 7步 来完成实现。我们把实现这个 目的 编写成了 第1步实现什么,第2步实现什么,第3步实现什么……把整个事情分成了一个步骤一个步骤,这就是一个 面向过程 的编写方式;整个这个过程,我们关注的不是“人”,不是“东西”……而是“事”。
回到我们现实生活,这整个的步骤和这种生活方式是没什么问题的;但是一旦到了我们 程序 中,我们写完了一段代码不可能就这么完了对吧;更多可能的还是我们还需要 复用 的。假如,这一段代码我们需要 复用 1000次,该怎么办呢?而且我们大家都知道:单纯的 复用 不是最麻烦的,真正麻烦的是程序后期的 更新、维护 和 迭代。现在是“妈妈买瓜”;今天妈妈不在家,怎么执行“爸爸买瓜”呢?再或者,外面现在在下暴雨,妈妈不能穿常规衣服去买瓜了,现在妈妈外面需要加套一件“雨衣”,这又该怎么操作呢?等等等等,这是不是每出现一次 需求微调,我们是不是就要 重新编写 代码;这不仅给我带来很多的不方便,更多的是对 代码的正常运行 进行 不断的挑战。
面向过程 这种编写方式往往 只适用 于 一个功能,如果要实现 别的功能 需重新编写新的程序,往往对代码的 复用性 比较 低。
这种编程方式 符合 人类的思维,编写起来 比较容易。
假设上面这段 代码 我一定要它实现别的功能,比如说 我一定要这段代码 重复1000次,或者说我就是要 “孩子吃肉” 该怎么办?出门左转,我是不是刚写完三篇我对 Python语言的函数 的理解;我们把上面这段 代码 放进 函数 里,如果我想 执行1000次 直接调用或者循环 函数 1000次就可以了;我只要改原函数的一行代码,这整个循环的1000次的代码都改了。
这样的操作没什么问题,而且 函数 的出现也是为了来解决类似的问题而存在的,而单纯 函数 的这个功能仅仅也只是增加的 函数复用性 这一个功能,而上面这个 函数 也只是在做一件事“孩子吃瓜”。如果我想要 “孩子吃肉”、“孩子吃蔬菜”、“孩子吃水果” 该怎么办?它们是不是有很多 相同 或者 相似 的地方;最起码,它整体的运行框架是一致的,只是一些小细节是不一样。讲到这,有些一直追更的读者可能会说:最近的一篇文章 10.Python语言的函数(下) 里刚讲过的 高级函数 和 Python语言的装饰器 来扩展函数的功能;通过 高级函数 来对 孩子 的一些行为进行进行管理;这么操作,虽然需求效果是达到了,但是 高级函数 和 Python语言的装饰器 是否又增加的程序的复杂性;所以,还是前面的那句话:这种编程方式 符合 人类的思维,编写起来 比较容易,但是 功能 比较单一,不利于代码的 复用性。
现在 面向过程 编程编写出来的代码的功能过于单一,用 函数 和 装饰器 进行修改增加的程序的复杂性。那我们还有别的方法吗?
还是用我们现实生活小事情来作为实例:如果大家你现在是 一家之主,我们什么事都要 操心,指挥别人做这个做那个。孩儿他妈爱,你出门别忘了穿鞋啊;你说孩子他妈,你买东西别忘了骑车;孩子妈你买这个瓜别忘了结账……你是操碎了心,对吧?你这个孩他妈去买东西不能明抢对吧,我还是要结账的对吧。所以,你这样子在家肯定是天天要干仗的对吧。
现在我们就有一种新的思维方式,你想轻松怎么办?是不是你只需要告诉别人做什么的过程,别的就不管了;比如我就跟他妈说 一句话:给孩子买个西瓜。是不是就O了,对吧。那至于你穿没穿鞋,开没开车,结没结账,我就不管了。最终孩子他妈把西瓜买回来了;然后,叭,孩儿,吃吧,你妈给你买的。这不是OK了。这种行为方式,在编程里我们称之为:面向对象 的编程语言。
刚刚我们通过 面向过程 完成整个操作用了 7个步骤,那 面向对象 是不是只是把这 7个步骤 变成 一个操作:孩子他妈给孩子买西瓜。完成。是不是就O了,很快速、简单、简洁。现在就是用 一行代码 替换了 七行代码 。作为一个 立志 成为 优秀计算机工程师 的你,会选择用那种方法?毫无疑问,一定是 面向对象 的编程方法了。
那我们再来思考思考:这个 面向对象 我们面对的是谁?或者说这个 对象 是谁?函数?我?孩子?孩子他妈?西瓜?吃西瓜?再次回到我们的 起点:Python一切皆对象。其实对于 面向对象 的编程语言来说 一切都是对象。
举几个例子:“穿鞋” 这个动作是不是就是一个 对象;“电动车” 这个动作是不是就是一个 对象;“骑” 这个动作是不是就是一个 对象;包括“结账” 这个动作是不是也是一个 对象……那么大家会说:这么多的 对象 有什么好处?我们把一系列的数据或者行为保存到一个个的 对象 当中。
比如说:我要给孩子吃瓜这个事情;我就可以把这个事情保存到 妈妈 这个 对象 当中,至于她怎么去买,都是由这个 对象内部定义的信息决定 的。对象是什么?对象 就是一个 存储数据的容器;它的好处是什么呀?好处就是:我想让孩子吃瓜,我就让孩子他妈去买瓜;我想让孩子吃菜,我就让孩子他妈去买菜……真正的细节就在 对象 里,我不需要再操心了。什么 穿鞋、开电动车、结账……只要我们把 对象 写好了就不需要担心了。
再比如说大家用过这个爬虫的一个模块:requests;requests.get(‘http://xxxxxxxxxxxx’)。这个 get(’’) 里面需要传递一个URL地址;此时你愿意传 百度 你就传 百度,你愿意传 新浪 就传一个 新浪,你愿意传一个 小说网站 你就传一个 小说网站……具体细节我不管,我只是把这个对象给你定义好了,你直接用是不是就OK了。其实 这些操作 都是什么?其实,这些操作就是 面向对象 。
那个此时大家心里可能有一个 疑问:这个叫 孩子吃瓜 这件事,里面 妈妈 这个对象中不也得是这么一步一步实现这个步骤吗?对吧,这个确实没错,但是 区别 在于什么呀?区别在于 是不是这些 步骤 已经存在 于妈妈这个==对象当中==了。我们只要写好这个 对象 是不是OK了,对吧?所以呢,我们来小小的总结一下:
1) 面向对象 的编程语言,关注 的是 对象,而 不注重 过程,对于 面向对象来说:一切皆对象;
2) 面向对象 的 编程思想,将 所有功能 统一保存 到 对应 的 对象 中,要使用某个功能,直接找到 对应的对象 即可;
3) 这种 编码方式 比较 容易阅读,并且 易于维护,容易复用。但是编写的过程中 不太符合 常规的思维方式,刚开始编写的时候相对会比较麻烦。
2. 类(class)
我们目前学习的 对象 都是 Python的内置对象,但是 内置对象 并不都能 满足我们的需求,所以我们在开发中经常要 自定义一些对象。
类 简单理解:它就是相当于一个 图纸。这个图纸是干嘛呀?我们以前说 对象 相当于是 一个容器,那么你现在要 创建一个对象,或者你要自己 定义这么一个对象,前面我们说:对象 就像是 容器,那这个这个 容器 是 方 的还是 圆 的呀?对吧?这个容器里面是有 一个格、两个格 还是 N个格,那这些都是 由谁决定 的呢?由谁?是不是就是由我们说的这个 图纸 来决定的,对吧。那么你要创建这个 容器,那就得选择 图纸;这个 图纸 就是我们所说的这个 类 ;所以 类 简单的理解 就是一张 图纸,在程序中我们需要根据 类 来 创建对象;类 就是对象的 图纸。
如果上面的这些介绍还没有让你完全明白,那我们来 举个例子:现在呢,我们手上有张 图纸,现在假设,这是一张可以造汽车的图纸;这个时候,我们是不是可以根据这张 图纸,我们造一辆 红色汽车、一辆 蓝色汽车、一辆 黑色汽车……对吧,那么这些车是不是就是 对象,红色汽车 一个 对象、蓝色汽车 一个 对象、黑色汽车 一个 对象、等等等等;那这些对象是从哪来的?是不是根据 图纸 造出来的。所以说我们可以这么理解:我们又称 对象 是 类 的 实例(instance)。“ 对象 是 类 的 实例 ”这句话我们又怎么理解?我们说这张 图纸 它只是一张 纸,它没有什么 实际的形态,但是我们可以 根据原纸来造出一个车,是不是就相当于把这张 图纸 给他 实例 出来,就是有一个现实中大家可以看的到的东西。
所以,我们也称:对象 是 类 的 实例(instance)。如果 多个对象 是通过 一个类 创建的,我们称 这些对象 是:一类对象。这 一类对象 我们可以用前面的“造汽车”来理解:虽然 车 的 颜色 不一样,但 车 的 型号 全部都是一样的。再比如说你这个对象是通过“人”这个对象创建的,那就是一个 “人类”;假如这个对象是通过“狗”这个对象创建的,那就是一个 “狗类”……到此呢,类的介绍就已经差不多了;那我们现在再一起回顾一下:我们到现在都学过那些类?int() 、string() 、float() 、bool() 、list() ……那么这些这些都是什么?这些都是 类。为什么这么说?来看 参考实例:
a = 1
print(a) # 1a = int(1)
print(a) # 1
实例中,第一个a
是什么?是不是一个整数;两个print()
的结果都是一样的吧,都是“整数 1”;只是这第二种方法我们平时写的比较少,第二个a
的意思是不是:接收数据强制类型转换为整形。
那我们再来看一下:int() 、string() 、float() 、bool() 、list() ……这些Python语言内置的 类 有什么特点?是不是他们都是 小写字母开头,(括号)结尾 的。所以,当我们需要 自定义类 的时候需要以 大写字母 来开头。当然,这是下一块内容,我们等下再说。
回到前面,既然我们刚刚说:int()
是是一个类;那么a = int(1)
这行代码就今天就可以完整的理解:它是创建了一个int()
的类的实例。那这个int()
的类的实例我们怎么理解?来看下面的 参考实例:
def fn_a():passa = fn_a
print(a,type(a)) # <function fn_a at 0x0000028125B6D160> <class 'function'>a = int(1)
print(a,type(a)) # 1 <class 'int'>a = str('Python')
print(a,type(a)) # Python <class 'str'>
通过观察 参考实例 的运行结果我们可以逐渐清晰:通过 type() 函数 返回对象的类型我们发现 a = int(1)
的对象类型是 class(类),class(类) 的属性是 'int'
;而 a = fn_a
的对象类型是 function(函数)。虽然它们都很像,但是它们 不是一个东西。同样的 a = str('Python')
的对象类型也是 class(类),class(类) 的属性是 'str'
。
说这么多,那读者朋友们一定会问了:我们怎么自己来定义一个 类 啊?其实,我们自定义一个 类 就非常简单了;我们自己定义一个类就使用Python语言 内置的关键字 class。
语法实例:
# 创建 类 的语法:
class Class_name([父类]):pass
我们本篇文章暂时不讲类 () 里的内容(下一篇),我们先讲一个老生常谈的话题:规范。在这里,我们说当然也就是 类的命名规范。自定义的 类, 类 的名字要使用大写字母开头;常规的 类 的命名方法我们一般使用 大驼峰命名法
自定义 类 的 语法 以及 相关的注意事项 都已经讲过了,那我们现在就一起来创建我们的第一个类吧。
class MyClass():passprint(MyClass) # <class '__main__.MyClass'>
我们已经成功的自己创建了第一个 类,并且通过print(MyClass)
打印出的结果得到:<class '__main__.MyClass'>
得到的结果是什么意思呢?当前打印的结果是一个 类,__main__
表示当前的 类文件 是 主文件,运行在 主文件 里这个 类 的名字叫MyClass
。
前面说过:类 就是 对象 的 图纸。我们现在已经成功的完成一个 类 的创建了,那我们怎么来创建一个 对象 呢?其实呢,这个操作也是非常的简单。来看 参考实例:
class MyClass():passmc = MyClass()
这个操作是什么意思呢:我使用MyClass
这个 类 创建了一个对象,这个对象叫做 mc
;mc
就是通过 MyClass
这个 类 创建的 对象;mc
就是通过 MyClass
这个 类 的 实例(instance)。我们来通过 函数print()
和 函数type()
一起来看看 mc
打印出来的结果。
参考实例:
class MyClass():passmc = MyClass()print(mc,type(mc)) # <__main__.MyClass object at 0x000002698C928400> <class '__main__.MyClass'>
跳过解释操作,直接翻译结果的意思:首先解释 print(mc)
出来的结果 <__main__.MyClass object at 0x000002698C928400>
;我们当前所在的 运行文件 是 主文件,打印的 变量mc
是 类 MyClass
实例化 后的 对象,存储于 0x000002698C928400
这个内存位置当中。type(mc)
打印的是 变量mc
的类型,意思是 变量mc
是通过MyClass
这个 类 创建的 对象。
现在我们已经知道 如何创建一个 对象 已经 对象 打印出来的结果,那么如果一个 类 被多个 对象 实例化 会怎么样呢?
参考实例:
class MyClass():passmc_1 = MyClass()
mc_2 = MyClass()
mc_3 = MyClass()
mc_4 = MyClass()
看上面的 参考实例 我们会发现 4个对象 mc_1
、mc_2
、mc_3
、mc_4
其实都属于一个 类 MyClass()
的实例,它们都是 一类对象;当然了,参考实例 毕竟相对的还是比较简单,我们一眼就能看出来。不过,如果以后我们在真实的开发中如何证明 mc_1
、mc_2
、mc_3
、mc_4
4个对象都属于 一类对象 呢?此时,我们来介绍 Python语言 中第一个对 类 进行操作的 函数 isinstance()
。
参考实例:
class MyClas():passclass MyClass():passmc_1 = MyClass()
mc_2 = MyClass()
mc_3 = MyClass()
mc_4 = MyClass()
mc_5 = MyClas()q = isinstance(mc_1,MyClass)
w = isinstance(mc_2,MyClass)
e = isinstance(mc_3,MyClass)
r = isinstance(mc_4,MyClass)
t = isinstance(mc_5,MyClass)
y = isinstance(int,MyClass)print(q,w,e,r,t,y) # True True True True False False
通过观察上面的 参考实例 我们会发现:如果 函数 isinstance()
返回的是 True
则证明 对象 mc_n
是 类 MyClas()
的 实例化对象;如果返回 False
则证明 对象 mc_n
不是 类 MyClas()
的 实例化对象。
到此,我们先小结一下:
类 简单理解:它就是相当于一个 图纸,在编写程序前 汇总 我们的 各种需要,再根据 类 来 创建对象。
所以说:类 就是 对象 的 图纸。
我们也称:对象 是 类 的 实例(instance)。
# 创建 类 的语法:
class 类名([父类]):pass
实例化类 / 引用 类 创建 对象 的方法:
class MyClass():passmc = MyClass()
如果 多个对象 是通过 一个类 创建的,我们称 这些对象 是:一类对象。
最后是 验证函数 isinstance()
,验证 实例化对象 是否是由 类MyClas()
实例化的对象:
class MyClas():passclass MyClass():passmc_1 = MyClass()q = isinstance(mc_1,MyClass)print(q) # True / False
3. 对象的创建流程
类 和 对象 的简介大致的我们都已经说完了,接下来呢,我们一起来说说 对象的创建流程。
看到这个内容,有些朋友就会问了:前面在讲 类 的时候不是已经说过 对象 是 类 的 实例(instance)。这还有什么 创建流程 的吗?还真有。接下来呢,我们就一起的来唠唠。
前面我们说了 类 就是 对象 的 图纸;我们可以根据这个 图纸 重复的 创建N个对象。你 创造 一台大众不够,我还要 创造 一台奥迪、 创造 一台宝马……我们 创造 了这么多的东西,举了这么多的案例,我们现在再回头看看:我们今天一直说的这个 类 到底是干嘛的?
其实 类 也是 一个 对象,类 就是 用来 创建对象 的 对象。(这句话很重要!!!)
换个理解说法:类 这个 对象 的 主要功能 或者说 唯一功能 就是:创建对象。
上面我们讲过:一个 对象 里要有 id、type 和 value。
举个例子 现在有一个 对象 a = 1
,这个 对象 在我们的 计算机内存 里 开辟 了一个 空间,在这个 新开辟的 内存空间 里除了存储 对象a
,还有 对象 在 新开辟的 内存空间 里的 地址id
,对象 本身的 类型type
,以及 对象 对应的 值value
。
那么我们说即然一个 对象 里要有 id、type 和 value;那么一个 类 里是不是也要有 id、type 和 value 这三个值啊?一起来看一下:
class MyClass():passprint(id(MyClass),type(MyClass)) # 2855264727088 <class 'type'>
看上面实例的返回值:第一个2855264727088
,我想读者朋友你应该没什么问题,这就是这个 对象 在 计算机内存里新开辟的 内存空间 的 地址id
,这个还是很简洁明了,很好理解的;可是后面返回的结果<class 'type'>
就有些不明白了,MyClass
它的 类型 是 'type'
?这个怎么理解?这返回值的意思是不是说明了:类 是'type'
类型的一个对象;定义 类 实际上是定义了一个'type'
类型的 对象。
看到这,大家可能已经有点懵了。这绕来绕去怎么像是 绕口令 似的~其实也没那么的复杂,我来解释一下这在 “定义一个 类” 的过程中究竟都发生了哪些事。
参考实例:
class MyClass():passmc = MyClass()
通过拆解上面的 参考实例 我们得到以下的 思维导图:
通过 导图 我们发现:我们首先呢创建了一张 图纸 叫做MyClass
,这是我们 自定义类,我们把它呢存放在一个 变量 里,寄存的变量 你叫它MyClass
也行,叫它ABC
都可以; 变量MyClass
的内存地址值为0x123
,前面说过:只要是 对象,就一定会在 计算机的内存 里开辟一个专属于某一变量的 内存空间。那么 变量MyClass
的 内存空间 里是否就有 id:0x123
、type:class 'type'
(只不过 自定义类MyClass
的 类型 有点 特殊) 和 value(现在暂时不讲它的内容) 这几个基础信息。
接下来呢,我们又写了另外的一行代码:mc = MyClass()
;通过 变量mc
实例化了我们 自定义 的这个 对象 MyClass()
形成的一个 新的对象,既然是一个 新的对象 那也就有它自己专属的 内存空间,既 id:0x223
。那么 变量mc
的 内存空间 里是否有 id:0x223
、type:MyClass
和 value(现在暂时不讲它的内容) 这几个基础信息;只不过呢,此时我们实例化的对象mc
它的属性 type 是 MyClass
这个 类对象,而不是 自定义类 MyClass
的 类型class 'type'
。
到此呢,我们算是把 类 以及它是如何 实例化,还有 实例化 后的 对象 和 原本的 类 到底有什么区别 算是解释清楚了。那么我们接着往下看。
现在我们发现通过这个MyClass
这个 自定义类 创建的 对象,但它三个 基础属性 里的 value
是不是 没有值 啊?是不是?也就是说:这个 对象 的里面实际上是 什么都没有 的对吧,就相当于是一个 空的盒子。那么,此时,就会有读者疑问了,你们一定会问:小编,这个 空的盒子 它有什么用啊?那么此时,小编我就也要问你一句了:既然是 空的盒子,那我们是不是就可以往里面 添加东西 了?😃
那这个 添加东西 要怎么 添加 呢?我们先来讲解语法:
首先呢,我们要先定义 添加东西 的操作的意义:我们可以向 对象 中 添加变量,对象 中 添加的变量 我们称之为 属性。 语法:对象.属性名 = 属性值
只看这些抽象的文字,大家肯定也是看不懂,接下来跟着小编我的 参考实例 一起来理解,上面这段话究竟是什么意思。
参考实例:
回到前面我们创建的 自定义类对象MyClass
和 实例化对象mc
class MyClass:passmc =MyClass()
此时,我们添加一行代码mc.name = '蜘蛛侠'
,即:
class MyClass:passmc = MyClass()mc.name = '蜘蛛侠'
运行后我们会发现:最后什么都没输出。什么都没有?不过没关系,问题等等说,对于 励志未来做一个 优秀程序员 的我们来说:我们当下编辑的代码,只要 没报错 就是最大的 进步。在此,给我们彼此一个掌声~ 😃 闲言少叙,那我们来自问自答一句:我们添加的代码mc.name = '蜘蛛侠'
是在做无用功吗?肯定不是的了。来看 参考实例:
class MyClass:passmc = MyClass()mc.name = '蜘蛛侠'print(mc.name) # 蜘蛛侠
通过参考实例我们发现:代码mc.name = '蜘蛛侠'
的这个操作的意思是 我们向 实例化对象mc
的 value 里添加了一个对象 name = '蜘蛛侠'
。
至于如何查看我们的 添加 是否成功,我们只需要通过print( )
打印以下这个新添加的 对象 就可以确定了。
现在,我们已经知道如何的向 实例化对象 的 value 里添加 对象属性,也知道如何的 验证 我们向 value 里添加的 对象属性 是否完成。那么又有一个问来了:现在我们的 自定义类对象MyClass
实例化 了两个 实例化对象,分别是 实例化对象mc
和 实例化对象mc_1
,通过上面的 案例 已知我们向 实例化对象mc
里添加了一个属性mc.name = '蜘蛛侠'
,不过,此时我们如果打印 实例化对象mc_1
的 value 里的name
属性,最后会是什么结果呢?即 print(mc_1.name)
。看以下 参考实例:
class MyClass:passmc = MyClass()
mc_1 = MyClass()mc.name = '蜘蛛侠'print(mc_1.name) # AttributeError: 'MyClass' object has no attribute 'name'
AttributeError: 'MyClass' object has no attribute 'name'
翻译一下:属性错误:对象'MyClass'
里不存在名叫'name'
的属性。那么,我们来解释一下,系统为什么会反馈回这个错误:此时在内存空间中多出了一个名为mc_1
的变量,此时我们也假设这个变量开辟的 内存空间 的地址值为0x323
。此时,我们发现:新的 实例化对象mc_1
只是实例化了我们的 自定义类对象MyClass
;而代码mc.name = '蜘蛛侠'
的这个操作的意思是向 实例化对象mc
里添加一个 name = '蜘蛛侠'
的 属性,此操作和 自定义类对象MyClass
没任何关系。所以,我们打印 实例化对象mc_1
的 value 里的name
属性,自然也就会反馈 属性错误 这个提示了。
此时,如果有读者朋友们说:我就是想要向 实例化对象mc_1
添加一个属性怎么办呢?自然是:想添加就添加咯。再看 参考实例:
class MyClass:passmc = MyClass()
mc.name = '蜘蛛侠'mc_1 = MyClass()
mc_1.name = '钢铁侠'print(mc.name) # 蜘蛛侠
print(mc_1.name) # 钢铁侠
到此,我们先小结一下:
前面我们小结过了 实例化类 / 引用 类 创建 对象 的方法:
class MyClass():passmc = MyClass()
这一块呢,我们主要讲了:1) 什么是实例化对象;2) 整个自定义对象实例化的创建流程;以及呢 3) 如何向实例化对象中添加属性 value 的 值:
class MyClass():passmc = MyClass()
mc.name = '蜘蛛侠'print(mc.name) # 蜘蛛侠
4. 类的定义
自古:没有规矩,不成方圆。曾几何时,我最好的朋友 L先生 和我讲过一段话,让我对 整个计算机的认识 产生了 醍醐灌顶 的 升维,也让我在后来自学编程的时候有 降维打击 的畅通感;那他和我说了什么呢?
L先生 问我:你认为 计算机 或者说 编程 它 真正的核心 是什么?是 语法?是 语言?是 算法?是 数学?虽然它们都有或多或少的关系,但是 也只是 有点关系。计算机 真正的核心是 管理。你没有听错,就是 管理。管理 这个词在 普通人 的理解里就是:上级管理下级,让他们好好干活,别出幺蛾子、别犯错;管理 这个词在 管理高手 的理解里就是:场控;了解管理 市场、了解管理 客户、了解管理 产品、了解管理 公司、了解管理 行政、了解管理 供需、了解管理 员工……通过 不同的管理方法 管理着 各个对象 的 平衡,让他们彼此之间 和谐良性 的 交互运转,彼此 共同的平稳增长,直至达成我们最终的目标。你看,这和 计算机原理 是不是 一模一样 的。了解管理 每个代码、了解管理 语言语法、了解管理 前端后端、了解管理 不同框架、了解管理 交互运行、了解管理 环境变化、了解管理 访问运行、了解管理 数据变化……通过对 不同模块运转 的 管理 使 各个对象 运转达到 一定的平衡,让他们彼此之间 和谐良性 的 交互运转,彼此 共同的平稳增长,直至达成我们最终的目标。再把各个 限制、条件、规则、原理、因果 再 细分、拆解、拼装,你看“计算机”真正的核心法则是不是就这些。
在讲接下来的一块前我没什么要用这么大的一段这么隆重的开场白呢?因为我们接下来要讲“计算机”真正的核心法则之一: Python语言 的 类的定义。
OK,闲言少叙,即然我们要开始讲 Python语言 的 类的定义,那么就把我们先前的 自定义类MyClass
拿过来吧。
参考实例:
class MyClass:passmc = MyClass()
mc.name = '蜘蛛侠'mc_1 = MyClass()
mc_1.name = '钢铁侠'print(mc.name) # 蜘蛛侠
print(mc_1.name) # 钢铁侠
实例 看完了,结果 呢也知道了,此时我们是不是该问一问:一顿操作看着虎,你这操作是在干什么呀? 或者说:我们添加的这个name
有什么用?
其实,我们这么添加的name
没什么用,而且这个 操作 也 不太对。为什么 不太对?这最后的结果不是并没有 报错 吗。
我们现在呢来详细的看一看:首先,我们先来看看这个 MyClass()
,这个MyClass()
是什么,是不是我们 自定的义类 啊;我们前面说过这个 MyClass()
相当于是一个 盒子,虽然这个 盒子 里现在啥都没有,现在通过 MyClass()
创建的 对象 也是一个 空对象;但是呢,我们也不要小瞧了这个 空盒子,因为它是 万能 的。哪它是怎么个 万能 法呢?既然是个 空盒子 当然就是你想放什么就放什么;比如:name、age、title……等等等等,但是呢 代码mc.name = '蜘蛛侠'
和 代码mc_1.name = '钢铁侠'
这两个操作都是向 对象 里添加了 一个属性;我们是不是可以往这个容器里多放一些。
前面我们说过:类这个容器 相当于一个 图纸,那么既然是 图纸 那是不是就要有它的 规矩 啊。既不能 什么都不放,也不能 肆意的添加 属性 和 元素。
既然,我们说 图纸 要有它的 规矩,那么 我们接下来就来讲一个 概念:类 和 对象 都是对 现实生活中事物 的 抽象。
怎么 理解 这个 概念,或者说 我们要怎么 抽象 呢?举个例子 :假设,我现在想对一个人 抽象,那我们该怎么 抽象 呢?或者说 我们该怎么通过 一个类 或者 一个对象 来 描述 一个人。所谓的 抽象 不是说把什么东西 拓印 出来一个,而是把 某一事物整个 的 特点 和 属性 放到 程序里的一个容器 当中。
所以,我们先来简单的总结一下:所有实际的事物都是由 两部分 组成:
1. 数据(属性);
2. 行为(方法);
我们先来说这第一部分 数据(属性):人 有 年龄、身高、体重、三维、多少骨头、几个牙、几个眼睛、几个嘴巴、几处受伤……这些是不是都是 一个人 的 数据;一个人 除了 数据 还有什么?人 是不是还 可以跑、可以打架、可以骂人 等等,你可以做 很多很多 好的事情,也可以做 很多很多 不好的事情;这些是什么?是不是都是 一个人 的 行为(方法)。
和大家磨叽了这么多,接下来给大家整个案例来换换脑子:
参考实例: 尝试定义一个人类
class Person():passp_1 = Person()
p_2 = Person()
我们 自定义 了一个 类Person
,并 实例化 了两个对象,分别是 p_1
和 p_2
。这两个 人 在 程序 里呈现的形式在这里我们就不再重复了。
这里呢,我给大家画了一个简单的 思维导图。如果 不太清楚 这两个 对象 在 程序 里呈现的形式,回到上面的 3. 对象的创建流程,把这两个 对象 代入到我为你画的 思维导图 里再仔细的思考一下,在这我们就不浪费大家的阅读空间了。
前面我们说过,现在的两个 实例化对象 p_1
和 p_2
是两个 空对象,或者说是两个 空盒子,两个 对象 里面现在啥东西都没有;虽然我们前面介绍过 可以通过 实例类名.属性 = 'xxxxx'
向 实例对象 里添加 属性,但是没啥用。为什么没啥用? 因为我们对 自定义 的这个 类 没什么约束,自然了 我们向这个 类 里添加的 属性 自然的也就也没什么意义。创建一个 对象,这个 对象 里如果什么 属性 都可以添加的话,那 创建的这个 对象 也就凉了,它就没什么意义了。此时,我们是不是就要问一句:怎么办? 我们 怎么做 才能让我们 创建的这个 对象 有意义呢?
在我们自己 自定义类 的时候是不是说过:类 里面有个东西,它叫做 代码块。此时,我们 自定义的类Person()
里代替了 代码块 的是不是 代码pass
啊。接下来我们就要再说一个 类的定义 的 概念 了,那就是:在 类 的 代码块 中,我们可以 定义 变量 和 函数;在 类 中我们定义的 变量 将会成为 所有实例对象 的 公共属性,所有实例对象 都可以访问这些 属性。
参考实例: 向 自定义类 Person
里添加两个属性,分别是 a = 10
和 b = 20
。
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20p_1 = Person()
p_2 = Person()
按照我们刚刚说的 类的定义 的 概念,通过 自定义类Person
实例化 的两个对象 p_1
和 p_2
是不是就可以访问 类 里的两个属性了?闲言少叙,直接来 打印一下:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20p_1 = Person()
p_2 = Person()print(p_1.a, p_2.b) # 10 20
通过最后 打印出来的结果 我们 验证 了 在 类 的 代码块 中,我们可以 定义 变量 和 函数;在 类 中我们定义的 变量 将会成为 所有实例对象 的 公共属性,所有实例对象 都可以访问这些 属性 这个定义。
那么我们接着往下看:前面说了,我们这个 自定义类Person
是一个 人类,但是我们刚刚定义的这两个变量 a = 10
和 b = 20
在实际的 Person()
操作中是不是并没有什么 意义 啊?在本块内容的开始时我们说过:我们 自定义类Person
要有 人类 共同的 特点 或者是 特征。所以,我们在 自定义类 的 代码块 里要尽可能多的定义一些 有意义 的 属性 和 方法。那什么样的 属性 和 方法 才是 有意义 的 属性 和 方法 呢?再简化一下问题:在我们 自定义类Person
定义哪些 属性 和 方法 才是 有意义 的 属性 和 方法 呢?一个 人,他是最起码的是不是要有一个 名字 啊。
参考实例: 向 自定义类 Person
里添加一个 name
属性。
class Person():name = '钢铁侠'p_1 = Person()print(p_1.name) # 钢铁侠
虽然我们最后 打印的返回值 和上一个 参考实例 最后 打印的返回 的结果差不多,但是,你有没有发现,我们通过这种方式最后 打印出来的结果 是不是比 p_1.name = '钢铁侠'
这种通过 实例化类p_1
传输进去的属性信息要 方便、安全 而且还 好用 很多。
这里呢,我给大家画了一个简单的 思维导图。以画图的方式向大家 简明扼要 的表达一下 参考实例 的小程序在整个的计算机内存中的 演变过程。
回到我们 最初 的总结:所有实际的事物都是由 两部分 组成:
1. 数据(属性);
2. 行为(方法);
刚刚我们介绍完了 自定义类Person
的第一部分 数据(属性) 的 创建 和 访问,接下来我们再来讲讲==自定义类==Person
的第二部分 行为(方法) 的 创建 和 访问。
我们说了 人 除了有 年龄、身高、体重、三维、多少骨头、几个牙、几个眼睛、几个嘴巴、几处受伤……这些,一个 人 是不是还 可以跑、可以打架、可以骂人 等等,你可以做 很多很多 好的事情,也可以做 很多很多 不好的事情;那 一个人 的这些 行为(方法) 我们又该怎么 创建 和 访问 呢。
闲言少叙,我们接下往下看 参考实例:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak() # TypeError: speak() takes 0 positional arguments but 1 was given
咦,怎么报错了?我们先不看代码,我们先来看看这个 错误提示 TypeError: speak() takes 0 positional arguments but 1 was given
是什么意思。我们把这个 错误提示 翻译成中文,大致意思就是:对象错误:调用函数speak
时没有在 () 里传递进 位置参数 但是 在调用函数时最少要传递一个 位置参数。用大白话讲就是:你在 调用 我的时候什么信息都 没传,你要给我 传递一个参数。
在我们前面学习 函数 的时候知道:当我们 创建的函数后面 定义几个 形参,我们 调用 的时候就要传递几个 实参;如果我们在 定义函数 的时候没有定义 形参 的话,那我们在 调用该函数 的时候是不是就不用 再传递 进什么 实参 了。但此时我们调用 自定义类Person
里面的 方法函数 时,自定义类Person
里面的 方法函数 里明明没有定义 形参,可是 系统 现在需要我们传递进一个 实参,不然就给 报错提示;这不就 矛盾 了吗。
为什么会出现这个问题呢,等会呢我们在 5. 参数 self 里再详细的讲解,现在我们先尝试着向 自定义类Person
里创建 方法函数speak()
里添加一个 参数,然后我们再试着调用一下 p_2.speak(a)
,看下这最后的打印结果:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(a): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak(a) # NameError: name 'a' is not defined
咦,怎么还报错?我 最爱的读者朋友,你先消消气,先稳定一下 情绪。我们还是先不看代码,我们先来看看这个 错误提示 NameError: name 'a' is not defined
是什么意思。我们把这个 错误提示 翻译成中文,大致意思就是:名称错误:内有找到名字叫 'a'
的对象。
没有 实参 的调用没有定义 形参 的 自定义类Person
里创建 方法函数speak()
结果报错;添加了 实参 调用定义了 形参a
的 自定义类Person
里创建 方法函数speak(a)
结果也是报错;这,这,这……这在正常情况,我们都是要心态爆炸的了。但是,编程就是个 手艺 + 经验 的活,首先我们要保持自身的心态平衡。一次、两次的尝试 都还 出错,这只能证明 我们尝试的次数还是不够。废话不多说,我们现在就开始下一种方法的尝试。
参考实例:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak(a) # NameError: name 'a' is not defined
还是 报了 NameError
错误;没事,两个 () 最多最多我们也就尝试 四次 就能得到所有结果了。
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(a): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak() # Hi~
咦,成功了?这是不是有点 不合常理 哦。最初我们在调用 自定义类Person
里创建 方法函数speak()
出现错误时,我们就复习了一下前面的我们学的有关于 函数 的知识,我们知道:当我们 创建的函数后面 定义几个 形参,我们 调用 的时候就要传递几个 实参;如果我们在 定义函数 的时候没有定义 形参 的话,那我们在 调用该函数 的时候是不是就不用 再传递 进什么 实参 了。可是现在的情况却是:想要正常的调用 自定义类Person
里面的 方法函数,我们就需要定义好 自定义类Person
里面的 方法函数 里的 形参,而我们在调用 自定义类Person
里面的 方法函数 时却不需要传递进 实参。这又是什么情况?这是不是也太反常里了。
这个 反常理 的问题呢,我们在后面的 5. 参数self 着重的再解释一下。这里呢我们先把整个 4. 类的定义 先介绍完,马上就要结束了。
我们调用 自定义类 里面的 方法函数 的语法:对象.方法名()
。
方法调用 和 函数调用 的 区别:
如果是 函数调用,调用函数时 有几个形参,就会传递 几个实参;
如果是 方法调用,自定义类 里 默认 传递进 一个参数,所以 方法 中 至少 得有 一个形参。
到此呢,有关 4. 类的定义 小编我算是简单的介绍完了,接下来我们简单的小结一下:
- 类 和 对象 都是对 现实生活中事物 的 抽象。所谓的 抽象 不是说把什么东西 拓印 出来一个,而是把 某一事物整个 的 特点 和 属性 放到 程序里的一个容器 当中。
- 所有实际的事物都是由 两部分 组成,分别是:1) 数据(属性) 和 2) 行为(方法);
- 在 自定义类 的 代码块 中,我们 可以定义 变量 和 函数。
变量 会成为该 自定义类 实例 的 公共属性,所有由该 自定义类 实例化的对象 都可以通过print(对象.变量)
的形式访问;
函数 会成为该 自定义类 实例 的 公共方法,所有由该 自定义类 实例化的对象 都可以通过对象.方法名()
的形式访问。 - 方法调用 和 函数调用 的 区别:
如果是 函数调用,调用函数时 有几个形参,就会传递 几个实参;
如果是 方法调用,自定义类 里 默认 传递进 一个参数,所以 方法 中 至少 得有 一个形参。
5. 类中的属性和方法
对于 如何 自定义类 以及这 自定义类 有什么 作用,我们已经很详细的讲解过了。接下来呢 我们就要仔细的讲解 类 中的 属性 和 方法 的调用。
参考实例:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(a): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak() # Hi~
我们 自定义 的这个 类,不管是这 自定义类 里面的 属性 还是它里面的 方法 我们都是放在这个 类对象 当中;而且呢,在我们后面的 实例对象 p_1
和 p_2
当中,都没有任何的一个 属性 或者 方法 的。
在讲 类 和 对象 的时候,我们知道:所有的 实例对象 都可以访问 被实例 的 类 里的 任何的一个 属性 或者 方法。此时,我们就要问一个问题了:这个 实例对象 为什么能访问到我们 自定义 的这个 类 里的 属性 或者 方法 呢?这是为什么呀?
看完 问题 后,就有读者朋友就会说了:这个 实例对象 本身就是根据我们 自定义 的这个 类 造出来 的,能访问到 自定义类 里的 属性 或者 方法 这不是正常的吗。
在开始回答大家这个问题之前呢,我们首先要从 根 上明确一个问题,那就是:类 中 定义的 属性 和 方法 都是 公共的,任何该 类 的 实例 都 可以访问。明确这个 根 问题之后呢,我们接下来就开始来聊聊上面的 为什么?
在说这 为什么 之前呢,我们要先了解 自定义类 里的 属性 和 方法 的 查找流程。这个 属性 和 方法 的 查找流程 又该怎么体现呢?
闲言少叙,先拉一个 参考实例:
class Person():name = '钢铁侠'p_1 = Person()print(p_1.name) # 钢铁侠
单看 代码 也看不出什么所以然,我们再拉一个 基于 这段 小代码 在我们 计算机的 内存 当中运转的 思维导图:
通过 参考实例 和 思维导图 我们发现:虽然 参考实例 最后的 print(p_1.name)
打印出了 钢铁侠
,但是我们通过看 思维导图 发现 实例化对象 的 value
里其实 什么都没有。
那如果,我现在想往 实例化对象p_1
的 value
里添加些 属性 我们该怎么操作?是不是 对象.属性名 = 'xxx'
就可以了。
参考实例:
class Person():name = '钢铁侠'p_1 = Person()
p_1.name = '蜘蛛侠'print(p_1.name) # 蜘蛛侠
基于 参考实例 的 思维导图:
通过 参考实例 和 思维导图 我们发现:参考实例 最后打印p_1.name
的结果是 蜘蛛侠
。咦,怎么和最初 参考实例 的结果不一样啊?这 参考实例 最后打印 print(p_1.name)
究竟是怎么一个情况呢?
其实呢 我们打印的 p_1.name
,程序(Python解析器) 会 优先 就近 去 自己的对象当中 找 属性相对应的 值,如果 自己的对象当中 存在 相对应的属性 则 直接返回 相对应的 值;如果 自己的对象当中 没有 相对应的属性值,程序则会再去我们 自定义的 类 中找 相对应的属性值;
class Person():age = '28'p_1 = Person()
p_1.name = '蜘蛛侠'print(p_1.age) # 28
如果在 自定义类 中再找不到 相对应的属性,系统则会返回 AttributeError: 'Person' object has no attribute '……'
错误提示。
class Person():age = '28'p_1 = Person()
p_1.name = '蜘蛛侠'print(p_1.title) # AttributeError: 'Person' object has no attribute 'title'
讲到这,我们是不是又 间接 的回顾了一遍我们之前说的 代码优先级;5.1 类的属性和方法 的调用 和我们之前讲的 算术优先级 、 函数优先级 以及 高级函数 以及 函数的作用域 是不是很相似。😃
讲完了 类 的 属性 和 方法 的 查找优先级 流程之后,新的一个问题就 又来了。是 什么问题呢?那就是:我们什么时候应该把 属性 放在 类对象 当中?什么时候又应该把 属性 放在 实例对象 当中?这是一个 在未来 我们 经常会遇到 的重要问题。
那这 属性 和 方法 我们该怎么存放呀?我们先来看一个问题:一个人 他 最少也必须 要有一个名字吧,而且还是 每个人 都是 最少也必须 要有一个名字吧;但是,每个人 的 名字 在不考虑 重名 的基础前提上,他们又都是 不一样 的 对吧。张三、李四、空、大仙、。、Tor、Tol、アリバ、サイト、한국어、Чернобыль ……不仅不一样,而且还可能是 各种各样 的 对吧。
介绍完了一种 人类 必须有但又必须都不相同的 属性,接下来我们来看那些 人类 必须有且都相同的 属性:在 排除所有特殊问题 的基础上,每个人 他都会 睡觉、说话、行走、吃饭、喝水、喜欢 …… 等等的这些 日常行为操作 对吧。
讲到这,我想大家隐隐的能感觉接下来我会讲什么了。那就是:
类对象 和 实例对象 中 都可以保存 属性 和 方法。
如果这个 属性 或 方法 是 所以实例 共享 的,则应该将其保存到 类对象 中;
如果这个 属性 或 方法 是 某个实例所 独有 的,则应该将其保存到 实例对象 中。
至于这 属性 或 方法 的添加方法,在这里就不再重新的详细描述了;对象.属性 = 'xxx'
和 对象.方法名()'
。
一般情况下,属性 保存到 实例对象 中,实例对象.属性 = 'xxx'
;而 方法 需要保存在 类对象 中。
请注意:我们在这里讲的 属性 和 方法 的 保存方法 讲的是 在一般常规的情况下。以后,在我们参加工作中,如果出现一些 特殊情况 的话我们还要根据 具体的情况 具体处理。
到此呢,有关 5. 类中的属性和方法 小编我算是简单的介绍完了,接下来我们简单的小结一下:
对于在 实例对象 中,调用 属性(方法) 的优先级:
当我们调用一个 对象 的 属性(方法) 时,程序(Python解析器) 会 就近 先在 当前的对象 中寻找是否有 该属性,如果 有,则直接返回 当前对象 的 属性值。如果 没有,则去 当前对象 实例化的类对象 中去寻找,如果 有 则返回 类对象 中的 属性值。如果再没有则会返回 AttributeError: 'Person' object has no attribute '……'
错误提示。
对于 属性 和 方法 一般情况下 的 定义思路:
1) 类对象 和 实例对象 中 都可以保存 属性 和 方法。
2) 如果这个 属性 或 方法 是 所以实例 共享 的,则应该将其保存到 类对象 中;
3) 如果这个 属性 或 方法 是 某个实例所 独有 的,则应该将其保存到 实例对象 中。
4) 一般情况下,属性 保存到 实例对象 中,实例对象.属性 = 'xxx'
;而 方法 需要保存在 类对象 中。
6. 参数self
在开始介绍 参数self 之前呢我们先回顾一下在 4. 类的定义 里留下的一个大问题:
class Person():a = 10 # 向 自定义类Person() 里添加一个属性 a = 10b = 20 # 向 自定义类Person() 里添加一个属性 b = 20name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(a): # 向 自定义类Person() 里添加一个方法 speak()print('Hi~')p_1 = Person()
p_2 = Person()print(p_1.name) # 钢铁侠
p_2.speak() # Hi~
咦,成功了?这是不是有点 不合常理 哦。最初我们在调用 自定义类Person
里创建 方法函数speak()
出现错误时,我们就复习了一下前面的我们学的有关于 函数 的知识,我们知道:当我们 创建的函数后面 定义几个 形参,我们 调用 的时候就要传递几个 实参;如果我们在 定义函数 的时候没有定义 形参 的话,那我们在 调用该函数 的时候是不是就不用 再传递 进什么 实参 了。可是现在的情况却是:想要正常的调用 自定义类Person
里面的 方法函数,我们就需要定义好 自定义类Person
里面的 方法函数 里的 形参,而我们在调用 自定义类Person
里面的 方法函数 时却不需要传递进 实参。这又是什么情况?这是不是也太反常里了。
接下来呢,我们就一起来好好的研究研究:为什么 会出现这样的情况呢?
参考实例里的 自定义类 我就不再仔细的介绍了,在 4. 类的定义 里面已经讲烂了。参考实例 中我们先把 代码def speak(self):
里的 self
改为 a
,我们说 函数def speak(a):
里面有个 参数a
,我们在调用这个 类对象 的 方法函数 的时候,Python语言的解析器 会 默认 的来传递这么一个 形参a
;所以,我们以后写 类对象 的 方法函数 的时候, 方法函数 的后面至少要定义一个 形参。至于说这个 形参self
有什么作用,我们现在先别管,到了后面我们会再详细的解释的;我们先来看一个 参考实例:
# 让 p_1.speak() 和 p_2.speak() 最后的输出结果分别是:'你好,我是蜘蛛侠' 和 '你好,我是绿巨人' 。class Person():name = '钢铁侠' # 向 自定义类Person() 里添加一个属性 name = '钢铁侠'def speak(a): # 向 自定义类Person() 里添加一个方法 speak()print('你好')p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好
p_2.speak() # 你好
通过 参考实例 我们发现,我们的需求是 需要 让程序的 p_1.speak()
和 p_2.speak()
最后的输出结果分别是:‘你好,我是蜘蛛侠’ 和 ‘你好,我是绿巨人’ 。单看我们的需求还是很简单的吧,但是,程序运行后 最后 实际的输出结果 却分别只是:你好
和 你好
。
如果我们修改一下 方法函数def speak(a):
里输出参数;我们一起来看下最后的输出结果。
参考实例:
class Person():name = '钢铁侠'def speak(a):print('你好,我是蜘蛛侠')p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好,我是蜘蛛侠
p_2.speak() # 你好,我是蜘蛛侠
通过 参考实例 我们发现,程序运行后 最后 实际的输出结果 却分别是:你好,我是蜘蛛侠
和 你好,我是蜘蛛侠
。而且我们还发现:程序最后之所以 只输出 你好,我是蜘蛛侠
实际原因是因为我们把 方法函数def speak(a):
最后的输出结果 写死了 呀,这么 写的代码 是不是违反了 程序设计的 开闭原则(OCP)。
那假如我们把 方法函数def speak(a):
里输出参数再修改一下;我们一起来看下最后的输出结果。
参考实例:
class Person():name = '钢铁侠'def speak(a):print('你好,我是%s'%'绿巨人')p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好,我是绿巨人
p_2.speak() # 你好,我是绿巨人
通过 参考实例 我们发现,程序运行后 最后 实际的输出结果 却分别是:你好,我是绿巨人
和 你好,我是绿巨人
。而且我们还发现:虽然我们把 方法函数def speak(a):
最后的输出结果使用了 占位符 进行拆分,其实实际上也是 间接 的把方法函数def speak(a):
最后的输出结果写死了 呀。在上一个 参考实例 里我们说过:这么 写的代码 违反了 程序设计的 开闭原则(OCP)。
既然说,我们的前两个操作都是直接或者间接的把 方法函数def speak(a):
里输出参数 写死了;那假如我们把 方法函数def speak(a):
里输出参数修改为 print('你好,我是%s'%name)
;我们一起来看下最后的输出结果。
class Person():name = '钢铁侠'def speak(a):print('你好,我是%s'%name)p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak()
p_2.speak()
# NameError: name 'name' is not defined
很好,很优秀,很卓越。 这次的修改最后的 输出结果 直接就 报错 了 NameError: name 'name' is not defined
。访问的变量名不存在: 名字为 ‘名字’ 的变量未定义。
在这里有个 注意点:参考实例 里的 自定义类 里的 方法 它不是个 函数闭包。如果只是一个 函数闭包 是可以访问到 变量name = '钢铁侠'
的,但我们现在是在一个 自定义类 里对它的 方法 进行操作;自定义类 里的 方法 是 无法访问 到 自定义类 里的 属性 的。
def Person():name = '钢铁侠'def speak():print('你好,我是%s'% name)return speakp_1 = Person()print(p_1()) # 你好,我是钢铁侠# None
很明显,上述三种操作都无法通过我们的 自定义类Person
来实现需求:让程序的 p_1.speak()
和 p_2.speak()
最后的 输出结果 分别是:你好,我是蜘蛛侠
和 你好,我是绿巨人
。那我们该如何正确的使用我们的 自定义类Person
来实现甲方爸爸对我们的需求呢?
其实,抛开一切,我们 只是希望 代码print('你好,我是%s'% name)
里的 name
访问到是p_1.name = '蜘蛛侠'
和 p_2.name = '绿巨人'
。那我们该怎么操作?
参考实例:
class Person():name = '钢铁侠'def speak(a):print('你好,我是%s'% p_1.name)p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好,我是蜘蛛侠
p_2.speak() # 你好,我是蜘蛛侠
虽然,最后 p_1.speak()
和 p_2.speak()
的 输出结果 还是一样的,但是程序 最后的输出结果 不是通过 写死输出结果 来实现的。最起码,在编码上我们 符合 了 程序设计的 开闭原则(OCP)。
我们再把 代码print('你好,我是%s'% p_1.name)
里的 p_1
改为 p_2'
。让我们再来看看最后的 操作结果。
参考实例:
class Person():name = '钢铁侠'def speak(a):print('你好,我是%s'% p_2.name)p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好,我是绿巨人
p_2.speak() # 你好,我是绿巨人
虽然在编码上我们 符合 了 程序设计的 开闭原则(OCP)。但是程序 最后的输出结果 还是要通过我们手动对 p_1
和 p_2
进行修改的。所以,如果真的要 计较 的的话,其实上面的 参考实例 还是不符合 程序设计的 开闭原则(OCP) 的。
其实,我们希望 谁调用 最后就输出 谁的名字,那我们的 代码 该怎么编写才能让程序 最后的输出结果 符合我们的需求?我们的 代码 该怎么编写才能让最终的结果符合 程序设计的 开闭原则(OCP)?
那么 新的问题 就来了:我怎么知道 谁在调用 呢?
我们当然是无法知道的了。我们现在只是在我们的 自定义类 里定义了 def speak(a):
这么一个 方法函数,我们在定义 方法函数 的时候是 无法确定 最后是谁会 需要调用 该方法的。此时我们看到这个 自定义类 里的 方法函数 def speak(a):
里有个 a
,它又能干什么?
老方法:遇事不清就 打印。我们现在就先来 打印 这个 a
,看看最后输出的结果。
class Person():name = '钢铁侠'def speak(a):print(a)p_1 = Person()p_1.name = '蜘蛛侠'p_1.speak() # <__main__.Person object at 0x0000027ACC628400>
我们现在 打印 这个 a
是不是只需要调用 p_1.speak()
把这个 方法输出就可以了。最后调用输出的这个结果为:<__main__.Person object at 0x0000027ACC628400>
这是个什么呀……<主文件.Person 对象 在内存 0x0000027ACC628400>
。
简单的讲:我们打印的这个 a
最后返回输出的是一个 对象。
此时,我们再 打印 一下我们的 实例化对象p_1
,看看 打印 它最后会输出一个什么结果:
class Person():name = '钢铁侠'def speak(a):print(a)p_1 = Person()p_1.speak() # <__main__.Person object at 0x0000027ACC628400>
print(p_1) # <__main__.Person object at 0x0000027ACC628400>
咦,怎么会这样? 通过最后返回的 打印 结果我们发现:我们对 实例化对象p_1
的 打印结果 和 我们前面 打印 的 自定义类 里的 方法函数 def speak(a):
里的形参 a
的 打印结果 竟然完全的一模一样,连所在的 内存地址值 都一样。会不会有什么问题?我们尝试着再打印一次看看:
class Person():name = '钢铁侠'def speak(a):print(a)p_2 = Person()p_2.speak() # <__main__.Person object at 0x000002A08C2A8400>
print(p_2) # <__main__.Person object at 0x000002A08C2A8400>
我们再一次看到 实例化对象p_2
的 打印结果 和 我们前面 打印 的 自定义类 里的 方法函数 def speak(a):
里的形参 a
的 打印结果 竟然也同时指向一个对象。
如果我们分别通过 实例化对象p_1
和 p_2
打印 自定义类 里的 方法函数 def speak(a):
里的形参 a
最后会返回什么结果呢?打印 一下看看不就知道了。
class Person():name = '钢铁侠'def speak(a):print(a)p_1 = Person()
p_2 = Person()p_1.speak() # <__main__.Person object at 0x00000270C6B68400>
print(p_1) # <__main__.Person object at 0x00000270C6B68400>
p_2.speak() # <__main__.Person object at 0x00000270C6B8BF70>
print(p_2) # <__main__.Person object at 0x00000270C6B8BF70>
这 打印 的是 同一个 自定义类 里的 方法函数 def speak(a):
里的形参 a
为什么最后返回的指向的结果还 不一样了呢?
此时,读者朋友们你们有没有发现什么 规律 啊?此时我们是不是发现:如果 实例化对象p_1
在调用 自定义类 里的 方法函数 def speak(a):
,那么 方法函数 def speak(a):
里的形参 a
是不是就是 p_1
;如果 实例化对象p_2
在调用 自定义类 里的 方法函数 def speak(a):
,那么 方法函数 def speak(a):
里的形参 a
是不是就是 p_2
。
既然发现了这个规律,那么对 自定义类 里的 方法函数 def speak(a):
的形参 a
或者说是 形参 self
进行一个 总结:
自定义类 里的 方法函数 每次 被调用 时,解析器 都会 自动 传递一个参数;
传递的 第一个参数 就是 调用方法的 本身。
如果是 p_1 调用,第一个参数就是 p_1 对象;
同理,如果是 p_2 调用,第一个参数就是 p_2 对象。
即然现在我总结出了上面这个结论,那么 回到最初 :对 让程序的 p_1.speak()
和 p_2.speak()
最后的输出结果分别是:你好,我是蜘蛛侠
和 你好,我是绿巨人
这个需求,此时我们应该怎么写?
参考实例:
# 让 p_1.speak() 和 p_2.speak() 最后的输出结果分别是:'你好,我是蜘蛛侠' 和 '你好,我是绿巨人' 。class Person():name = '钢铁侠'def speak(self):print('你好,我是%s'% self.name)p_1 = Person()
p_2 = Person()p_1.name = '蜘蛛侠'
p_2.name = '绿巨人'p_1.speak() # 你好,我是蜘蛛侠
p_2.speak() # 你好,我是绿巨人
最后呢,对于前面的 总结 再做最后一点的 补充:自定义类 里的 方法函数 的 第一个参数 一般我们习惯把这个参数命名为 self。
下一次,我们再在别的程序或这项目的类对象中看到 self 时,希望大家别还是 一脸懵 哦。如果担心自己可能还是会 一脸懵 的话,那就请你 点击“收藏” 下这篇文章吧。
到此呢,有关 6. 参数 self 小编我算是简单的介绍完了,接下来我们简单的小结一下:
1) self 在 定义函数 时 需要定义,但是在 调用 时会 自动传入;
2) 自定义类 里的 方法函数 每次 被调用 时,解析器 都会 自动 传递一个参数;
3) 传递的 第一个参数 就是 调用方法的 本身。
4) self 的 名字 并不是 规定死 的,但是最好还是 按照约定是用 self;
5) self 总是指 调用时 的 类的实例。
总结小便条
本篇文章主要讲了以下几点内容:
- 什么是 面向对象?
答:为了方便程序员 快捷的开发 和 方便的维护,以及代码的 灵活性 和 复用性;我们通过传统的 面向过程 的编程方式衍化出了 面向对象 的编程方式。
面向对象 的编程方式虽然方便了程序员 快捷的开发 和 方便的维护,也涵盖了代码的 灵活性 和 复用性,但是编写的过程中 不太符合 常规的思维方式,刚开始编写 的时候相对的会比较麻烦。 - 面向对象 中的 类 到底是什么?
答: 类 简单的理解 就是一张 图纸,在程序中我们需要根据 类 来 创建对象;类 就是对象的 图纸。自定义类 的 语法:class ClassName:
。
class MyClass():passprint(MyClass,type(MyClass)) # <class '__main__.MyClass'> <class 'type'>
- 类 该怎么使用:
答:通过 自定义变量 将它 实例化。
class MyClass:passmc = MyClass()
mc.name = '蜘蛛侠'mc_1 = MyClass()
mc_1.name = '钢铁侠'print(mc.name) # 蜘蛛侠
print(mc_1.name) # 蜘蛛侠
-
现实开发中,对 类 在定义时,我们需要注意哪些 细节 和 要素:
答:- 类 和 对象 都是对 现实生活中事物 的 抽象。所谓的 抽象 不是说把什么东西 拓印 出来一个,而是把 某一事物整个 的 特点 和 属性 放到 程序里的一个容器 当中。
- 所有实际的事物都是由 两部分 组成,分别是:数据(属性) 和 行为(方法);
- 在 自定义类 的 代码块 中,我们 可以定义 变量 和 函数。
变量 会成为该 自定义类 实例 的 公共属性,所有由该 自定义类 实例化的对象 都可以通过print(对象.变量)
的形式访问;
函数 会成为该 自定义类 实例 的 公共方法,所有由该 自定义类 实例化的对象 都可以通过对象.方法名()
的形式访问。 - 方法调用 和 函数调用 的 区别:
如果是 函数调用,调用函数时 有几个形参,就会传递 几个实参;
如果是 方法调用,自定义类 里 默认 传递进 一个参数,所以 方法 中 至少 得有 一个形参。
-
在 实例对象 中,调用 属性(方法) 的优先级:
答:当我们调用一个 对象 的 属性(方法) 时,程序(Python解析器) 会 就近 先在 当前的对象 中寻找是否有 该属性,如果 有,则直接返回 当前对象 的 属性值。如果 没有,则去 当前对象 实例化的类对象 中去寻找,如果 有 则返回 类对象 中的 属性值。如果再没有则会返回AttributeError: 'Person' object has no attribute '……'
错误提示。 -
属性 和 方法 一般情况下 的 定义思路:
答:类对象 和 实例对象 中 都可以保存 属性 和 方法。
如果这个 属性 或 方法 是 所以实例 共享 的,则应该将其保存到 类对象 中;
如果这个 属性 或 方法 是 某个实例所 独有 的,则应该将其保存到 实例对象 中。
一般情况下,属性 保存到 实例对象 中,实例对象.属性 = 'xxx'
;而 方法 需要保存在 类对象 中。 -
解释一下 参数self 的意义。
答:1) self 在 定义函数 时 需要定义,但是在 调用 时会 自动传入;
2) 自定义类 里的 方法函数 每次 被调用 时,解析器 都会 自动 传递一个参数;
3) 传递的 第一个参数 就是 调用方法的 本身。
4) self 的 名字 并不是 规定死 的,但是最好还是 按照约定是用 self;
5) self 总是指 调用时 的 类的实例。
本章回顾暂时就到这了,如果还有点晕,那就把文章里所有引用的案例代码再敲几遍吧。拜拜~
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 使用富文本编辑器(图片伪上传)
1,先下载的工具包: 富文本编辑器官网下载地址 2,导入下载的包到对应的包下面: css包下导入 : editormd.min.css editormd.preview.min.css 导入 fonts包,images包 js包下导入:lib,plugins,editormd.min.js 目录结构:3,重要代码 (1)编辑界面对应的代码段: 注意:引…...
2024/4/24 11:33:16 - python导出依赖包&安装全部依赖包
导出依赖包列表: pip freeze >requirements.txt安装依赖包: 普通安装 pip install -r requirements.txt使用清华源安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt...
2024/4/27 14:33:10 - ab 压力测试
下载ad压力测试器yum install httpd-tools -y执行完成之后输入ad查看是否安装完成使用: ab -c 10 -n 100 url-C 并发用户数-N 标识请求总数url 要测试的网址...
2024/4/26 15:05:30 - Yarn - 安装与基本使用
yarn是javascript库的包管理工具。yarn相对于npm具有 速度快、安全、稳定的特性。一、安装安装前先确认已安装node.js,Node 版本支持: ^4.8.0 || ^5.7.0 || ^6.2.2 || >=8.0.01、通过下载软件程序在windows上安装:下载msi后缀安装程序:点击下载运行安装程序根据引导安装即…...
2024/4/27 6:41:35 - Linux的基本命令
1、常见的目录结构 /bin 命令、二进制可执行程序 /boot 内核以及与系统启动有关的文件 /dev 设备文件 /lib 库文件 /etc 系统配置文件 /uer 用户安装的软件 或 系统运行过程中不常改变的文件 /proc 虚拟目录,进程在内存中的信…...
2024/4/20 11:06:52 - 深入理解Spring(二)
深入理解Spring之自动装配自动装配式spring满足bean依赖的一种方式 spring会在上下文自动寻找,并自动给bean装配属性 spring由三种装配的方式 1.在xml中显示配置 2.在java中显示配置 3.隐式的自动装配bean【重要】1.byName自动装配 注意:byName自动装配的时候,需要保证所有的…...
2024/4/18 23:32:43 - js高级02之构造函数和原型,ES5中的新增方法
js高级02 一、构造函数和原型: 1.构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初值,它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面 2.new在执行时会做4件事: 1)在内存中创建一个新的空对象 2)让this…...
2024/4/17 4:18:35 - 关于C++基础知识,你必须知道这些专业术语(2)
道阻且长,行则将至。埋头苦干,不鸣则已,一鸣惊人!加油,骚年!前言根据《C++ Primer》,第二章《变量和基本类型》总结而来;提示:善于利用 Ctrl + F 快捷键,快速搜索相关内容哦! 1 本章小结类型是 C++ 编程的基础; 类型规定了其对象的存储要求和所能执行的操作; 类型…...
2024/4/27 14:11:40 - 弹性盒-圣杯布局
效果图:实现方式: 下面代码中 关于html,body{height:100%},看不太懂的可以参考https://blog.csdn.net/javaloveiphone/article/details/51098972<style>* {margin: 0;padding: 0;}body,html {height: 100%;}body {display: flex;flex-direction: column;}.header {hei…...
2024/4/26 17:46:56 - .NET Core 数据库查询语句
Linq 语法查询1. 结果不要属性名以数组形式返回var role = from e in _masterDB.EmployeeRoleAdminAcljoin a in _masterDB.AdminAccessControlList on e.AdminAccessId equals a.AccessIdwhere e.CompanyId == employee.CompanyId&& employee.RoleIds.Contains(e.Role…...
2024/4/20 16:42:04 - 【nowcoder】珂朵莉的数列 (树状数组 逆序对)
珂朵莉的数列 题意 珂朵莉给了你一个序列,有n(n+1)2\frac{n\times(n+1)}22n(n+1)个子区间,求出她们各自的逆序对个数,然后加起来输出。 思路 对于一个逆序对(l,r)而言,它属于(n−r+1)∗l(n-r+1)*l(n−r+1)∗l个区间,理由如下,在这个逆序对左边有l-1个数,右边…...
2024/4/24 11:33:15 - 如何提高你的Microsoft Store的下载速度
效果如图所示1、按下“Win+R”组合键呼出运行,在框中输入“wsreset”按下回车;2、按下“Win+X”组合键呼出系统快捷菜单,选择“命令提示符(管理员)”;3、在命令提示符框中首先输入:DISM.exe /Online /Cleanup-image /Scanhealth 按下回车键,等待系统修复组件,接着输入…...
2024/4/24 11:33:13 - 图论算法学习
文章目录图的基本概念和术语定义和基本术语无向图术语树和图的关系有向图的术语图的表示邻接矩阵邻接表 图的基本概念和术语 定义和基本术语➢图( graph)是种网状数据结构 ,图是由非空的顶点集合和一个描述顶点之间关系的集合组成。 ➢图由顶点和边组成,顶点表示对象,边表示两个…...
2024/4/24 9:35:55 - 关键字“const”用法
参考内容:北京大学信息科学技术学院《程序设计实习》,郭伟老师&刘家瑛老师目录一、定义常量二、定义常量指针三、定义常引用一、定义常量const int MAX_VAL = 23; const string SCHOOL_NAME = “Peking University”; (在C语言中,用#define 定义常量,但无法定义常量…...
2024/4/24 11:33:11 - word2016设置当前页码为第一页
方法:word2016设置当前页码为第一页...
2024/4/26 5:22:03 - mysql workbench no connection established解决和服务启动后停止
文章目录一、启动服务1.出现的问题2.启动服务二、服务启动后停止1.Data复制、删除2.初始化数据库文件一、启动服务 1.出现的问题 数据库中没有表,报错no connection established2.启动服务 win+R输入命令 services.msc找到你的MYSQL_XXX,比如我的MYSQL80如果成功了,就没事了…...
2024/4/24 11:33:10 - appium+python 存在多个类时,不用每次都初始化driver解决办法
appium+python写自动化测试用例时,为了代码的可维护性,分成不同的类是很常见的办法, 但是在运行时,每一个类都要初始化一次,即每次都会重启应用,这很麻烦,通过__new__可进行多个类之间的复用。 driver_configure.py# coding:utf-8 __author__ = **description:driver配…...
2024/4/24 11:33:09 - 栈的应用----括号匹配问题
栈的应用----括号匹配问题(这里借鉴朱战立老师的算法思想) 一、问题引入: 假设一个算数表达式种包含圆括号、方括号和花括号三种类型的括号,编写一个函数,用来判别表达式中的括号是否正确配对。 二、算法思想: 括号匹配共有以下4种情况:左右括号配对次序不正确 左括号多于右括…...
2024/4/26 18:50:55 - Guava 心得:Range
在Guava中新增了一个新的类型Range,从名字就可以了解到,这个是和区间有关的数据结构。从Google官方文档可以得到定义:Range定义了连续跨度的范围边界,这个连续跨度是一个可以比较的类型(Comparable type)。比如1到100之间的整型数据。在数学里面的范围是有边界和无边界之分…...
2024/4/27 0:21:28 - 第一章 SpringCloud Alibaba简介——学习笔记
一、SpringCloud系统版本认识1、SpringCloud版本发布时间统计springcloud官方网站:https://spring.io/1.1、SpringCloud的版本更新发布时间(统计时间2020.04.28)Angel版本:2015年3月Brixton版本:2016年5月Camden版本:2016年9月Dalston版本:2017年4月Finchley版本:2018年…...
2024/4/24 11:33:06
最新文章
- (学习日记)2024.04.20:UCOSIII第四十八节:各文件功能概览
写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…...
2024/4/27 15:15:09 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【Locust分布式压力测试】
Locust分布式压力测试 https://docs.locust.io/en/stable/running-distributed.html Distributed load generation A single process running Locust can simulate a reasonably high throughput. For a simple test plan and small payloads it can make more than a thousan…...
2024/4/27 9:20:29 - 【JavaScript】如何在npm中切换源以及使用指定源安装依赖
忘不掉的是什么我也不知道 想不起当年模样 看也看不到 去也去不了的地方 也许那老街的腔调是属于我的忧伤 嘴角那点微笑越来越勉强 忘不掉的是什么我也不知道 放不下熟悉片段 回头望一眼 已经很多年的时间 透过手指间看着天 我又回到那老街 靠在你们身边渐行渐远 …...
2024/4/27 13:48:31 - DDIM,多样性与运行效率之间的trade off
DDPM的重大缺陷在于其在反向扩散的过程中需要逐步从 x t x_t xt倒推到 x 0 x_0 x0,因此其推理速度非常缓慢。相反,DDPM的训练过程是很快的,可以直接根据 x 0 x_0 x0到 x t x_t xt添加的高斯噪声 ϵ \epsilon ϵ完成一次训练。 为了解…...
2024/4/25 10:12:11 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/4/26 18:09:39 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/4/26 20:12:18 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/4/26 23:05:52 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/4/27 4:00:35 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/4/25 18:39:22 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/4/27 14:22:49 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/4/26 21:56:58 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/4/27 9:01:45 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/4/26 16:00:35 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/4/25 18:39:16 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/4/25 18:39:16 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/4/26 19:03:37 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/4/26 22:01:59 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/4/25 18:39:14 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/4/26 23:04:58 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/4/25 2:10:52 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/4/25 18:39:00 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/4/26 19:46:12 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/4/27 11:43:08 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/4/27 8:32:30 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57