目录:


类(class)和实例

整数、字符串、浮点数等,不同的数据类型就属于不同的类。

想想看当初学数据类型,我们用type验证数据类型后打印的结果

忘了就再来看看:

strs = '字符串'
ints = 1
floats = 2.3

print(type(strs)) # <class 'str'>
print(type(ints)) # <class 'int'>
print(type(floats)) # <class 'float'>

以上,class就是类。

顾名思义class 'str'就表示是字符串类。

同理,剩下俩个就是整数类、浮点数类...

类之所以为类,是因为每一个类之下都包含无数相似的不同个例。

类,是对某个群体的统称。
比如:人类、犬类

实例

在Python的术语里,我们把类的个例就叫做实例 (instance),可理解为“实际的例子”。

比如上边代码中的'字符串'、1、2.3。这三个就分别是字符串类的实例、整数类的实例、浮点数类的实例。

类是某个群体,实例是群体中某个具体的个体。

群体里的每个个体都有着相同/相似的特征和行为。也就是说实例之间会有相同/相似的特征和行为。

比如,字符串中的实例举几个例子:

str1 = '我是字符串'
str2 = '1'
str3 = '2.3'
str4 = 'True'

以上四个都是字符串,因为他们都是用英文引号包裹。这就是他们的相同特征。

即使他们四个的内容值完全不一样。

而也因此,值不一样就是他们实例之间的区别、是区别于其他实例个体的特征。

小测试

请问:狗、秋田犬、忠犬八公、list、[1,2]

以上这五个元素,哪个是类、哪个是实例?

答案见源码同目录下files中同名py文件

对象(object)

佛说:万事万物,皆可为对象。

咳咳,佛说,我说的不是男女对象那个对象!

这里所谓Python中的对象,等于类和实例的集合:类可以看作是对象,实例也可以看作是对象。

比如列表list是个类对象,[1,2]是个实例对象,它们都是对象。

再比如说人类是个类对象,也可以说小红是个实例对象(这里小红依旧不是你的女对象!!!清醒点!!蚂蚁竞走了十年了!!!)。

属性和方法

区别于其他类的依据,细分可以分成两种:

  1. 第一种是描述事物是怎样的,有什么特征 - 这就是所说的【属性】
  2. 第二种是描述事物能做什么,有哪些行为和作用 - 也就是所说的【方法】

Python中每个类都有自己独特的属性(attribute)和方法(method),是这个类的所有实例都共享的。换言之,每个实例都可以调用类中所有的属性和方法。

不过各个类的属性和方法,是需要我们自行创建的。除了python中已有的数据类型其属性和方法是内置建好的。

比如:列表的内置方法有append、pop等。而这些方法任何列表实例值都可以使用

listObject = [1,3,'列表实例里的第三个元素']  # 一个列表实例
listObject.append('我是列表实例利用类上的append方法添加进来的元素') # 调用列表类的内置方法append
print(listObject) # [1, 3, '列表实例里的第三个元素', '我是列表实例利用类上的append方法添加进来的元素']

类的创建

上节,函数用def关键字定义。

本节,类的创建用class关键字定义。

伪代码

class 首字母大写的类变量名:
  自定义属性名 = 属性值
  def 自定义方法名(self,参数1,可以没有参数2):
    方法函数体内容

具体的含义:

  1. class关键字创建,class+类名+英文冒号
  2. 类名首字母大写,是自定义命名,大写字母开头,不能和python关键字冲突。
  3. 类的代码体要放在缩进里。
  4. 属性名自定义,不能和python关键字冲突。属性值直接用等号赋值给自定义属性名即可
  5. 实例方法名自定义,不能和python关键字冲突。方法(也就是函数)通过def关键字定义,和函数的定义语句很类似,
  6. 实例方法的第一个参数必须传self,固定值。(下详)
  7. 类中创建的属性和方法可以被其所有的实例调用
  8. 实例的数目在理论上是无限的。我们可以同时“新建”多个实例【类被称为“实例工厂”的由来】

示例代码

# 创建一个男朋友类对象
class MyBoyfriend:
  sex = 'male'
  def caring(self):
    print('好了,不哭了~')
  
boyfriend = MyBoyfriend() # 调用类对象,得到男朋友实例对象。
print(type(MyBoyfriend)) # <class 'type'>
print(boyfriend) # <__main__.MyBoyfriend object at 0x109922400> MyBoyfriend类的是一个实例对象。后面的一串字符(0x109922400)表示这个对象的内存地址。
print(type(boyfriend)) # <class '__main__.MyBoyfriend'> 表示boyfriend类属于MyBoyfriend类。

属性(attribute)

在类中赋值的变量叫做这个类的“属性”

方法(method)

在类中定义的函数叫做这个类的“方法”。

类中带self的参数的方法是实例方法,是类方法的一种形式,也是最常用的一种方法。

类的实例化

还是以上边创建男朋友类的代码为例,类的实例化过程就是MyBoyfriend()这句。
最后创建的实例对象被赋值给变量boyfriend

调用类对象的过程叫作类的实例化,即用某个类创建一个实例对象。

实现形式/伪代码是

实例变量名 = 类名() # 类名后+小括号调用

实例对象调用类属性和方法

实例化类对象后,得到一个实例对象。因为类的方法和属性,实例对象都有。所以实例对象boyfriend可以调用类中的属性sex和方法caring

调用类的属性

实例名.属性

调用类的方法

实例名.方法(传参) # 参数不用考虑self

示例代码

# 调用类的属性
print(boyfriend.sex) # 打印"male"

# 调用类的方法
boyfriend.caring() # 打印“好了,不哭了~”

值得说明的是,调用类方法时,传参不用考虑self参数的存在。
fa

特殊参数:self

可以看到上例,为什么实例调用方法时不用传参,在定义时那个参数self又是什么意思呢?

这个参数self的特殊之处:“在定义时不能丢,在调用时要忽略。”

1、代指实例化对象的作用

其实这个self有点像JS中构造函数内部的this。self是所有实例化对象的替身。指的是任何用这个类生成的实例化对象:

# self
class SelfMean:
  content = '类SelfMean中的属性'
  def oneFn(self):
    print(self.content) # self在此指向实例化的对象"selfMean"
selfMean = SelfMean()
selfMean.oneFn() # 打印类中content的值 - "类SelfMean中的属性"

注意上例中,在oneFn函数内部,使用类中的属性content时,不能直接当变量使用,否则如下写法就会报错:

class SelfMean:
  content = '类SelfMean中的属性'
  def oneFn(self):
    print(content) # 不用self调用类属性,就会报错NameError: name 'content' is not defined
selfMean = SelfMean()
selfMean.oneFn()

变量未经定义就使用,就会报这种NameError的问题。详见第三章错误类型总结篇

有人会疑问,代码中oneFn上边不是定义了content还给她赋值了吗?怎么能说未定义呢?

函数的作用域中也说了,自己oneFn函数内部找不到的变量,会向上找父级作用域、层层向上查询乃至全局作用域的变量啊,他自己虽然没有、但是他爸爸有啊!为啥还说未定义呢?

同志啊,醒醒。这里是类啊!不是函数。类内部的变量是定义给实例化对象的属性的啊。换句话说,上述代码实例化对象转换成字典的模样长下边这样:

selfMean = {
  'content': '类SelfMean中的属性',
  'oneFn': 一个函数体在这里~
}

所以你如果不用字典的方式(1、selfMean.content;2、selfMean['content'])调用这个属性,他是拿不出来的。

而在类内部,实例化对象还没出生,你不知道他未来的名字叫selfMean1、还是叫selfMean37。也就没有办法用selfMean.content或selfMean37['content']的方式去调用它。

所以在这之前,需要有一个统一的self,来代指未来的实例化对象,并达到提前在类内部使用实例化对象的属性和方法的目的

使用方式就是self.属性self.方法名(除self以外的传参)。看下例:

class SelfMean:
  content = '类SelfMean中的属性'
  def oneFn(self):
    print(self.content) # 提前在类中使用了实例化对象的属性 content,等价于selfMean.content
    self.twoFn('哈哈哈哈哈~') # 提前在类中使用了实例化对象的方法 twoFn、并传参
  def twoFn(self, txt):
    print('实例化对象的第二个方法,打印内容:', txt)
selfMean = SelfMean()
selfMean.oneFn()

2、定义方法必传self

看上边的代码中,oneFn和twoFn都有self参数,并且都是第一个参数,这并不是巧合。

只要在类中定义的方法,第一个参数就必须是self。不过调用方法时,可以忽略它,不用给self传参。

3、调用方法传参时self可忽略

我们调用实例方法的时候,传参不用考虑self。以此往后类推就行:

class SelfParams:
  content = '类SelfParams中的属性'
  def twoFn(self,name,sex,age,weight):
    print(self.content)
    print(name,sex,age,weight) # 2、依次打印传递过来的位置参数的值:小石头 female 19 91
selfParams = SelfParams()
selfParams.twoFn('小石头','female',19,91) # 1、调用方法时忽略self参数,依次按位置传递name,sex,age,weight的参数

初始化方法(构造函数)

1、定义初始化方法

定义初始化方法的格式是def __init__(self),是由init关键字加左右两边的【双】下划线(__)组成。

双下划线是英文输入法下,shift + 0右边的那个键打出来的。

2、初始化方法的作用

无需调用自执行

一、当每个实例对象创建时(即类调用时),该方法内的代码无须调用就会自动运行。无需"实例名.init"的方式调用

# init
class InitTest:
  def __init__(self):
    a = 321
    b = 345

    print("初始化就会执行init里的代码: ", a+b)
initTest = InitTest()

# 运行后直接打印:初始化就会执行init里的代码:  666

可见 ,触发类对象的调用时,就直接触发了__init__方法的调用。

为类属性设置初始值

一般情况下,我们都会在初始化方法内部完成类属性的创建,为类属性设置初始值,这样类中的其他方法就能直接、随时调用。

上述代码改写如下:

class InitTest:
  def __init__(self):
    # 为类属性设置初始值,要写在__init__函数内部的最上方,否则会报错
    self.a = 321 # 注意self的存在。
    self.b = 345 # 同上

    # 定义完属性的初始值以后,才能在下变写__init__里边要处理的其他逻辑
    print("初始化就会执行__init__里的代码")
    self.plusAd()

  def plusAd(self):
    print(self.a + self.b) # 使用类属性

initTest = InitTest()
# 打印结果如下
# 初始化就会执行init里的代码
# 666

3、初始化方法接收其他参数

除了设置固定常量,初始化方法同样可以接收其他参数,并把这些参数赋值给类的属性并被类中其他方法使用:

# 初始化方法接收参数
class InitParams:
  def __init__(self,aP,bP):
    self.a = aP
    self.b = bP

    print('初始化执行并设置属性、把参数aP和bP的值给了属性a和b')
    self.plusAd()

  def plusAd(self):
    print(self.a + self.b) # 其他方法也能用同一个属性

  def sub(self):
    print(self.a - self.b) # 其他方法也能用公用的属性

initParams1 = InitParams(12, 4) # __init__需要的参数在类调用时传递
# 打印结果:
# 初始化执行并设置属性、把参数aP和bP的值给了属性a和b
# 16
# 8

initParams2 = InitParams(30, 5) # __init__需要的参数在类调用时传递,可以多次调用,传不同的参数,进而得到不一样的结果
# 打印结果:
# 初始化执行并设置属性、把参数aP和bP的值给了属性a和b
# 35
# 25 

当初始化方法__init__有多个参数的时候,在实例化(类调用)的时候就要传入相应的值。

上例第一次调用,12传给了aP、4传给了bP。

上例第二次调用,30传给了aP、5传给了bP。

这也是初始化方法的好处,传参一次可被多次调用,

番外 - 面向对象

面向过程

面向过程编程:首先分析出解决问题所需要的步骤(即“第一步做什么,第二步做什么,第三步做什么”),然后用函数实现各个步骤,再依次调用。一个示例:

# 全局变量定义
globalA = 12
globalB = 20
globalCount = 0

# 加
def plus():
  global globalCount
  globalCount = globalA + globalB
  sub()

# 减
def sub():
  global globalCount
  globalCount = globalCount - globalA/2
  print(globalCount)

# 主流程
def main():
  plus()

# 启动流程
main()

我们根据“全局变量数据整理——主流程——加法计算——减法计算”这个过程封装了三个函数,再依次调用,按规定顺序执行程序。

面向对象

面向对象编程,会将程序看作是一组对象的集合。通过调用对象的属性和方法,来拼凑完成一段功能。

# 面向对象
class Calculator:
  def __init__(self,a,b):
    # 公共属性定义
    self.globalA = a
    self.globalB = b
    self.globalCount = 0

  # 是加法方法,能做加法
  def plus(self):
    self.globalCount = self.globalA + self.globalB
    print(self.globalCount)

  # 是减法方法,能做减法
  def sub(self):
    self.globalCount = self.globalCount - self.globalA/2
    print(self.globalCount)

calculator = Calculator(12,20)
calculator.plus()
calculator.sub()

用这种思维设计代码时,考虑的不是程序具体的执行过程(即先做什么后做什么),而是考虑先创建某个类,在类中设定好属性和方法,即是什么,和能做什么。

接着,再以类为模版创建一个实例对象,用这个实例去调用类中定义好的属性和方法(plus、sub)即可。

面向对象的好处

  1. 参数的传递会比普通函数要省事很多。(不必考虑全局变量和局部变量,因为类中的方法可以直接调用属性。)
  2. 代码的可复用性也更高。(类能封装更多的东西,既能包含操作数据的方法,又能包含数据本身。)
  3. 代码结构会更清晰。(代码的可读性、可拓展性和可维护性这几个方面都会优于面向过程编程。)
  4. 一目了然。(面向对象编程将代码具体的数据和处理方法都封装在类中,不用完全了解过程也可以调用类中的各种方法。并且还可以分开调用)
  5. 可以在 Python 中轻松地调用各种标准库、第三方库和自定义模块(别人写好的类框架代码)

本文使用 mdnice 排版

【python系统学习13】类(class)与对象(object)的更多相关文章

  1. Python 系统学习梳理_【All】

    Python学习 1. Python学习---Python安装与基础1205 2. Python学习---PyCharm的使用学习 3. Python学习---Python数据类型1206 4. Py ...

  2. python基础学习笔记——类的成员

    一. 细分类的组成成员 之前咱们讲过类大致分两块区域,如下图所示: 每个区域详细划分又可以分为: class A: company_name = '老男孩教育' # 静态变量(静态字段) __ipho ...

  3. java的类class 和对象object

    java 语言的源代码是以类为单位存放在文件中,已public修饰的类名须和存放这个类的源文件名一样.而 一个源文件中只能有一个public的类,类名的首字母通常为大写. 使用public修饰的类可以 ...

  4. 【python系统学习14】类的继承与创新

    目录: 目录: [toc] 类的继承 子类和父类 继承的写法 继承示例 父类可以被无限个子类所继承 子类实例可调用父类属性和方法 类的始祖(根类) 根类 - object 实例归属判断 - isins ...

  5. python学习13类2之封装

    '''''''''面向对象三大特性:封装,继承,多态1.封装: 类中以_或者__的属性,都是私有属性,禁止外部调用.'''class Student(object): def __init__(sel ...

  6. 【Python系统学习】基础篇

    这次真的是最后一次了!第三次滚Python的基础.走了太多弯路.认真一点!菜鸟! 教程 转义字符 \ 可以转义很多字符,比如\n表示换行,\t表示制表符,字符\本身也要转义,所以\\表示的字符就是\ ...

  7. python基础学习笔记——类的约束

    ⾸先, 你要清楚. 约束是对类的约束. 用一个例子说话: 公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下: class QQpay: def pay(self,money): print ...

  8. Python快速学习10: 循环的对象及设计 (生活的规律)

    前言 系列文章:[传送门] 生活逐渐规律,按时睡觉.今天写博客,明天补时间看会书.慢慢的时间很珍惜 我很喜欢! 时钟就像个循环体,我们将它融入生活. 正文 循环对象的并不是随着Python的诞生就存在 ...

  9. 【Python系统学习02】数据类型与类型转换

    一.数据类型 字符串 整数 浮点数 [补充中...] 1.字符串 str 字符串:英文string,简写str. name = '小石头:' print(name,'2019', '12', '24' ...

随机推荐

  1. Docker部署LAMP项目

    前言 之前我们学习了如何在Linux部署LAMP项目,今天我们来学习一下如何在Docker下部署LAMP项项目吧! Docker 要求 CentOS 系统的内核版本高于 3.10 ,查看本页面的前提条 ...

  2. 【学习笔记】Golang学习方向整理

    前言 作为一个Java开发,给大家说Golang方向,好吓人...溜了溜了... 哦对了,如有不对的地方,还请指出.感谢! 某面试平台golang技能要求简要摘录 掌握 GO 语言,熟悉常用 pack ...

  3. 用反射机制和pandas,实现excel数据的读取以及参数化${arg}的赋值

    反射类:class GetData: index = pd.read_excel(file_name, sheet_name).loc[0, ['index']].values[0] email = ...

  4. vue的watch

    watch它可以用来监测Vue实例上的数据变动  尽量一张图解释清楚(尝试用圈圈区分关系): 写的很简单,watch本来就没啥东西我理解为响应式侦听全局变量 watch里绑定全局变量,被绑定全局变量发 ...

  5. feign源码解读

    对于feign的接口请求失败的重试配置可通过如下自定义配置文件实现(一般不建议配置) @Configuration public class FeignConfig { @Bean public Re ...

  6. mybatis返回自增主键踩坑记

    背景 MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map ...

  7. tableZen maxHeight 解决方案 如果数据条数小于N,不进行高度设置,超过N条,直接设置高度,解决原生iview Table 对于右侧固定列,不能计算出正确数值的解决方案

    tableZen maxHeight 解决方案 如果数据条数小于N,不进行高度设置,超过N条,直接设置高度,解决原生iview Table 对于右侧固定列,不能计算出正确数值的解决方案 if (thi ...

  8. 常用的 Git 命令与场景

    Git 分布式版本控制系统 它拥有完整的版本控制功能,能够解决多人协作的问题 将自己的代码同步到 Github 上能够提升开发效率 git 会记录你每一次的版本修改操作 常用的 Git 操作 # 指定 ...

  9. 042.集群网络-flannel及calico

    一 Flannel组件 1.1 flannel介绍 Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中.若需要实现这个网络假设,需要实现不同节点上的Docker容器之间 ...

  10. Python Django撸个WebSSH操作Kubernetes Pod

    优秀的系统都是根据反馈逐渐完善出来的 上篇文章介绍了我们为了应对安全和多分支频繁测试的问题而开发了一套Alodi系统,Alodi可以通过一个按钮快速构建一套测试环境,生成一个临时访问地址,详细信息可以 ...