1.对象

在面向对象程序设计中,对象(object)可以看作数据以及可以操作这些数据的一系列方法的集合。(这里的方法,就是函数),只是这些函数写在了类中,为了区分全局函数,将这些写在类中的函数称为方法。想要访问这些类中的函数,必须要对类实例化,实例化后的产物被称为对象。实例化后,调用方法时需要先指定对象名称,然后才可以调用这些方法。

2.类

类中的方法其实就是函数,定义的方法也完全一样,只是由于函数定义在类的内部,所以为了区分,将定义在类内部的函数称为方法。

'''类:拥有共同特征的同一类事物的总称或抽象。(鸟)对象:将抽象的事物具体化, 从类创建对象也称为类的实例化。(喜鹊)1.  类是代码块,用冒号(:)结尾
2.  如果类是空的,必须加pass语句
3.  类方法和函数的定义方式类似,如果是实例方法(对象),第1个参数必须是selfself表示当前类的实例,self可以是任何的变量名,这里之所以用self就是一种习惯。在调用方法时,这个参数的值不需要自己传递,系统会将方法所属的对象传入这个参数。在方法内部可以利用这个参数调用对象本身的资源,如:属性、方法等
'''
class MyClass:pass
class Person:  #定义Person类# 定义setName方法,def setName(self,name):self.name = name# 定义getName方法def getName(self):return self.name# 定义greet方法def greet(self):print("Hello, I'm {name}.".format(name = self.name))#创建person1对象=Person类的实例化,(使用类创建对象的方式与调用函数的方式相同。)
person1 = Person()#调用person对象的setName方法
person1.setName("Bill")
#调用person对象的getName方法
print(person1.getName())#调用person1对象的greet方法
person1.greet()
#调用person1对象的name属性。(通过self参数添加的name变量是Person类的属性,可以在外部访问。)
# 与调用person1.setName方法效果一样。
print(person1.name)

结果:

Bill
Hello, I'm Bill.
Bill

2.1 属性

通常会将类的成员变量称为属性,在创建类实例后,通过类实例访问这些属性,也就是读写属性的值。不过,直接在类中定义成员变量,尽管可以读写属性的值,但无法对读写的过程进行监视。

例如:在读取属性值时无法对属性值进行二次加工,在写属性值时也无法校验属性值是否有效。在Python语言中,可以通过property函数解决这个问题,该函数可以将一对方法与一个属性绑定,当读写该属性值时,就会调用相应的方法进行处理。当然,还可以通过某种机制,监控类中所有的属性。

2.1.1 传统的属性

在Python语言中,如果要为类增加属性,需要在构造方法(init)中通过self添加;如果要读写属性的值,需要创建类的实例,然后通过类的实例读写属性的值。

# 将类的成员 变量 称为属性
class Myclass:def __init__(self):self.value=0  # 为Myclass类添加一个value属性
c=Myclass()           # 创建Myclass类的实例
print(c.value)        # 输出结果:0c.value=20            # 改变value的值
print(c.value)        # 输出结果:20

2.1.2 property函数

property函数可以与三个方法绑定,该函数会创建一个属性,并通过返回值返回这个属性。property函数的第一个参数需要指定用于监控读属性值的方法,第二个参数需要指定用于监控写属性值的方法,第三个参数需要指定删除该属性时调用的方法。

""""
property函数使用注意事项:
1、通过property函数设置与属性绑定的方法(函数)名称没有任何限制。但是,方法的参数需要符合要求。
用于监控属性读和删除的操作方法只能有一个self参数,用于监控属性写操作的方法除了self,还需要一个参数,
用于接收设置属性的值。
2、删除对象的属性只是调用了通过property函数绑定的回调方法,并没有真正删除对象的属性。
删除对象的实际意义,需要在该回调方法(本例是在deletePosition)中定义。本例是在deletePosition
方法中重新初始化了left属性和top属性。
"""
class Rectangle:def __init__(self):self.left = 0self.top = 0# 用于监控position属性的写操作,可以同时设置left属性和top属性。def setPosition(self,position):print('setPosition被调用')self.left, self.top = position# 用于监控position属性的读操作,可以同时获取left属性和top属性。def getPosition(self):print('getPosition被调用')return self.left, self.top# 用于监控position属性的删除操作def deletePosition(self):print('position属性已被删除')#重新初始化left和top属性self.left = 0self.top = 0""""通过property函数将上面3个方法与position属性绑定,对position属性进行相关操作时,就会调用相应的方法"""position = property(getPosition, setPosition,deletePosition)r = Rectangle()
r.left = 100
print(r.left)# 通过position属性设置left属性和top属性的值,在设置属性值的过程中,setPosition方法被调用。
r.position= 123,456
print(r.position)# 删除position属性,deletePosition方法被调用,left属性和top属性被重新设置为0。
del r.position
# 通过position属性获取left和top属性的值,在获取属性的过程中,getPosition方法被调用。
print(r.position)

结果:

100
setPosition被调用
getPosition被调用
(123, 456)
position属性已被删除
getPosition被调用
(0, 0)

2.1.3 监控对象中所有的属性

尽管,使用property函数可以将三个方法与一个属性绑定,在读写属性值和删除属性时会调用相应的方法进行处理,但是如果需要监控的属性很多,则这样做意味着在类中需要定义大量的getter和setter方法。(习惯上,将与getValue和setValue类似的方法称为getter方法和setter方法)

# 将类的成员 变量 称为属性
class Myclass:def __init__(self):self.value=0  # 为Myclass类添加一个value属性# 获取value属性的值def getValue(self):print("value属性的值已经被读取")return self.value# 读取value属性的值def setValue(self,value):print("value属性的值已经被修改")self.value=valuec=Myclass()           # 创建Myclass类的实例
c.value=20            # 改变value的值
c.setValue(100)       # 通过setValue方法设置value属性的值print(c.getValue())   # 通过getvalue方法获取value属性的值
print(c.value)        # 输出结果:1000

结果:

value属性的值已经被修改
value属性的值已经被读取
100
100

所以说,property函数只是解决了外部调用这些属性的问题,并没有解决内部问题。本节介绍三个特殊成员方法(getatrrsetattrdelattr),当任何一个属性进行读写和删除操作时,都会调用它们中的一个方法进行处理。

# 监控对象中的所有属性
'''
__getatrr__(self, name):用来监控所有的属性读操作,其中name表示监控的属性名。
__setattr__(self,name,value):用来监控所有的属性写操作,其中name表示监控的属性名,value表示设置的属性值。
__delattr__(self,name):用来监控所有的属性的删除操作,其中name表示监控的属性名。当任何一个属性进行读写和删除操作时,都会调用它们中的一个方法进行处理
'''class Rectangle:def __init__(self):self.width = 0self.height = 0self.left = 0self.top = 0# 对属性执行 写 操作时,调用该方法,当设置size属性和position属性时,# 实际上设置了width属性、height属性以及left属性和top属性的值def __setattr__(self, name, value):print('{}被设置,新值为{}'.format(name, value))if name == 'size':self.width, self.height = valueelif name == 'position':self.left, self.top = valueelse:self.__dict__[name] = value  #__dict__是内部维护的一个特殊成员变量,用于保存成员变量。必须加上# 对属性执行 读 操作时调用该方法,当读取size属性和position属性值时,# 实际上返回的是width属性、heigth属性以及left属性和top属性的值def __getattr__(self,name):print('{}被获取'.format(name))if name == 'size':return self.width,self.heightelif name == 'position':return self.left,self.top# 当删除属性时调用该方法,当删除size属性和position属性时,# 实际上是将width属性、heigth属性以及left属性和top属性设置为0def __delattr__(self,name):if name == 'size':self.width,self.height = 0,0elif name == 'position':self.left,self.top = 0,0r = Rectangle()
r.size = 100,200    # 设置size属性的值
r.position = 1,2    # 设置position属性的值print(r.size)       # 获取size属性的值
print(r.position)   # 获取position属性的值del r.size,r.position  # 删除size属性和position属性
print(r.size)
print(r.position)

结果:

width被设置,新值为0
height被设置,新值为0
left被设置,新值为0
top被设置,新值为0
size被设置,新值为(100, 200)
width被设置,新值为100
height被设置,新值为200
position被设置,新值为(1, 2)
left被设置,新值为1
top被设置,新值为2
size被获取
(100, 200)
position被获取
(1, 2)
width被设置,新值为0
height被设置,新值为0
left被设置,新值为0
top被设置,新值为0
size被获取
(0, 0)
position被获取
(0, 0)

2.2 静态方法和类方法


定义静态方法需要使用@staticmethod装饰器(decorator),定义类方法需要使用@classmethod装饰器。

# 实例方法、静态方法和类方法
# 在实例方法中,可以调用静态方法和类方法,反之,不成立
class MyClass:name = 'Bill'   # 静态变量,可以被静态方法和类方法访问def __init__(self):print('MyClass的构造方法被调用')self.value =20    # 定义实例变量,静态方法和类方法不能访问该变量。(value 属性)# 定义静态方法@staticmethoddef run():print('*',MyClass.name, '*')  # 访问MyClass类中的静态变量nameprint('MyClass的静态方法run被调用')# 定义类方法@classmethod# 这里面的self是类的元数据,不是类的实例。def do(self):print(self)print('[',self.name,']') # 访问MyClass类中的静态变量name。self.run()# 在类方法中不能访问实例变量,否则会抛出异常(因为实例变量需要用类的实例访问)# print(self.value)# 定义实例方法def do1(self):print(self.value)print('<', self.name, '>')print(self)self.run()# 调用静态方法run
MyClass.run()
# 通过 类 访问 类的静态变量
print(MyClass.name)c = MyClass()   # 创建MyClass类的实例
c.do()          # 通过类的实例也可以调用 类方法
c.do1()         # 通过类的实例访问 实例方法
c.run()MyClass.do()    # 通过 类 调用 类方法

结果:

* Bill *
MyClass的静态方法run被调用
Bill
MyClass的构造方法被调用
<class '__main__.MyClass'>
[ Bill ]
* Bill *
MyClass的静态方法run被调用
20
< Bill >
<__main__.MyClass object at 0x000000000284A3C8>
* Bill *
MyClass的静态方法run被调用
* Bill *
MyClass的静态方法run被调用
<class '__main__.MyClass'>
[ Bill ]
* Bill *
MyClass的静态方法run被调用

2.3 迭代器(iterator)

迭代:就是循环的意思,也就是对一个集合中的元素进行循环,从而得到每一个元素。对于自定义的类,也可以让其支持迭代。

2.3.1 自定义可迭代的类

列表:列表可以用索引来快速定位其中的任何一个元素,是因为列表一下子将所有的数据都装载在内存中,而且是一块连续的内存空间。当数据量比较小时,实现较容易;当数据量很大时,会非常消耗内存资源。
迭代:迭代是读取多少元素,就将多少元素装载到内存中,不读取就不装载。
这就有点像XMl的两种方式:DOM和SAX。DOM是一下子将所有的XML数据全部都装载到内存中,所以可以快速定位任何一个元素,但代价就是消耗内存;而SAX是顺序读取XML文档,没读到的XML文档内容是不会装载到内存当中的,所以SAX比较节省内存,但只能从前向后顺序读取XML文档的内容。
如果在一个类中定义__iter__方法,那么这个类的实例就是一个迭代器。 __iter__方法需要返回一个迭代器,所以就返回对象本身即可(也就是self)。当对象每迭代一次时,就会调用迭代器中的另一个特殊成员方法 __ next __。该方法需要返回当前迭代的结果。

'''__iter__(self)__next__(self)
'''# 可无限迭代直角三角形的 行
class RightTriangle:def __init__(self):self.n = 1  # 定义一个变量n,表示当前的 行数# 该方法必须返回一个迭代器def __iter__(self):return selfdef __next__(self):result = '*' * (2 * self.n - 1)  # 通过字符串的乘法获取直角三角形每一行的字符串,每一行字符串的长度 2*n-1self.n += 1  # 行数加1return resultrt = RightTriangle()  # 类的实例 就是一个 迭代器
# 对迭代器进行迭代
for e in rt:# 限制输出行的长度不能大于6,否则会无限输出行if len(e) > 6:break;print(e)

结果:

*
***
*****

2.3.2 将迭代器转换为列表

迭代器缺点:通过索引获取某个元素,进行分片操作等。这些都是列表的专利,所以在很多时候需要将迭代器转换成列表。但很多迭代器都是无限迭代的。因此,在将迭代器转换成列表时,需要给迭代器 能够 迭代的元素限定一个范围,否则内存就会溢出。要想让迭代器停止迭代,只要抛出StopIteration异常即可。
通过list( )函数直接将迭代器转换为列表

# 将迭代器转换为列表class Fibonacci:# 在构造方法中定义两个变量a和b,用来表示菲波那切数列最开始的两个值def __init__(self):self.a = 0self.b = 1# 该方法必须返回一个迭代器def __iter__(self):return selfdef __next__(self):result = self.a   # self.a就是当前要迭代的值self.a,self.b = self.b, self.a + self.b   # 计算菲波那切数列的下一个值,并将a变成原来的b,将b变成下一个值# 要想让迭代停止,需要抛出StopIteration异常if result > 10: raise StopIterationreturn result  # 返回当前迭代的值fibs = Fibonacci()   # 类的实例 就是一个 迭代器
print(list(fibs))   # 将迭代器转换为列表fibs1 = Fibonacci()
# 使用for循环对迭代器进行迭代
for fib in fibs1:print(fib,end="  ")

结果:

[0, 1, 1, 2, 3, 5, 8]
0  1  1  2  3  5  8

在__next__ 方法中,当result大于10时,抛出了StopIteration异常,但是这个异常是在迭代的过程中由系统处理的,并不会在程序中抛出,所以要想将无限迭代改成有限迭代,可以在适当的时候抛出StopIteration异常。

2.4 生成器(generator)

迭代器:以类为基础的单值产生器
生成器:以函数为基础的单值产生器

相同点:迭代器和生成器都只能一个值一个值地生产。每迭代一次,只能得到一个值。
不同点:迭代器需要在类中定义__iter__ 和__next__ 方法,在使用时需要创建迭代器的实例。 生成器是通过一个函数展现的,可以直接调用,所以从某种意义上来说,生成器在使用上更简洁。

2.4.1 创建生成器

要定义一个生成器,首先定义一个函数,在函数中对某个集合或迭代器进行迭代,然后使用yield语句产生当前要生成的值,这时函数会被冻结,直到调用生成器的代码继续迭代下一个值,生成器才会继续执行。


# 生成器也是用于迭代的# 定义一个生成器函数
def myGenerator():numList = [1,2,3,4,5,6,7,8]for num in numList:yield num         # yield语句会冻结当前函数,并提交当前要生成的值(本例是num)# 对生成器进行迭代
for i in myGenerator():print(i, end = ' ')

结果:

1 2 3 4 5 6 7 8

如果将yield num 换成print(num),则对numList列表进行迭代,并输出该列表中每一个元素值。 但是,这里使用了yield语句来提交当前生成的值,也就是for循环中num的值,然后myGenerator( )函数会被冻结(暂停不再往下执行了),直到for循环继续下一次循环,再次对myGenerator( )函数进行迭代,myGenerator( )函数才会继续执行,继续使用yield语句提交下一个要生成的值,直到numList列表的最后一个元素为止。从这一点看出,生成器函数是惰性的,在迭代的过程中,每取一个值,生成器函数就往下执行一步。

2.4.2 递归生成器

对多维列表进行一维化处理,可以采用递归的方式进行处理。处理的方式:先对多维列表进行迭代,然后判断每个列表元素是否还是列表:如果仍是列表,则继续对这个列表进行迭代;如果只是普通的值,则使用yield语句返回生成的值。

# 将多维列表进行一维化处理
nestedList = [[1,2,3],[4,3,2],20,[1,2,[4,5]],[1,2,3,4,5]]
def enumList(nestedList):try:for subList in nestedList:  # 对多维列表进行迭代"""将多维列表中的每一个元素传入ennumList函数,如果该元素是一个列表,那么会继续迭代,否则会抛出TypeError异常,在异常处理代码中直接通过yield语句返回这个普通的元素值。这个异常也是递归的终止条件"""for element in enumList(subList):yield elementexcept TypeError:yield nestedList   # 将普通的列表值作为生成值返回。# 迭代生成器
for num in enumList(nestedList):print(num, end=' ')

结果:

1 2 3 4 3 2 20 1 2 4 5 1 2 3 4 5

如果多维列表中的某个元素值是字符串类型,那么也会进行迭代,原因:字符串可以看作字符的列表。因为希望将字符串作为一个整体输出,所以在进行迭代之前,先要判断当前元素值是不是字符串类型,如果是字符串类型,则直接通过yield语句返回即可。判断一个值是否是字符串的最简单的方法就是使用try语句。因为只有字符串才能与另一个字符串进行连接(使用 “+”运算符),所以一个非字符串类型的值与字符串相加一定会抛出异常。这样就很容易可以判断与一个字符串相加的另一个值是否为字符串类型。

# 在生成器中阻止字符串被迭代# 将多维列表进行一维化处理,字符串整体返回
nestedList = [[1,2,3],[4,3,2],"20",[1,2,[4,5]],"hello world",[1,2,3,4,5]]
def enumList(nestedList):try:try:nestedList + ''  # 如果nestedList不是字符串类型的值,会抛出异常except:pass             # 如果nestedList不是字符串类型的值,会继续使用for语句对其进行迭代else:# 如果nestedList是字符串类型的值,直接抛出TypeError异常,在异常处理代码中# 会直接通过yield语句返回该值raise TypeError# 继续对nestedList进行迭代for subList in nestedList:for element in enumList(subList):yield element   # 通过yield语句返回当前生成的值except TypeError:yield nestedList
for num in enumList(nestedList):print(num, end=' ')

结果:

1 2 3 4 3 2 20 1 2 4 5 hello world 1 2 3 4 5

Python的类和对象相关推荐

  1. Python基础(类与对象)

    Python基础(类与对象) 一.编程的两大思想 面向过程和面向对象 面向过程 面向对象 区别 事物比较简单,可以用线性的思维去解决 事物比较复杂,使用简单的线性思维无法解决 共同点:面向对象和面向过 ...

  2. Python基础——类与对象

    Python基础--类与对象 Python基础--类与对象 类与对象 数据类型 对象 类的创建 创建语法 类的创建 对象的创建 对象调用类中的内容 类属性,类方法,静态方法 类属性 访问类属性 类方法 ...

  3. Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法

    Day09新手小白学python 第九节 Python的类和对象的介绍,定义类和对象,定义实例方法和属性以及Python中的魔法方法 目录 Day09新手小白学python 前言 一.面向对象介绍 二 ...

  4. python的类和对象_Python类与对象实验

    一.任务描述 本实验任务主要对Python类与对象进行一些基本操作,通过完成本实验任务,要求学生熟练掌握Python类与对象的关系,并对Python类与对象的基本操作进行整理并填写工作任务报告. 二. ...

  5. Python的零基础超详细讲解(第十三天)-Python的类与对象

    基础篇往期文章如下: Python的零基础超详细讲解(第一天)-Python简介以及下载 Python的零基础超详细讲解(第二天)-Python的基础语法1 Python的零基础超详细讲解(第三天)- ...

  6. Python进阶-----类、对象的相关知识

    一.声明类 class 类名: #一般类名的首字母大写 '类的文档字符串' 类体 例如创建一个中国人的类: 1 class Chinese: 2 '这是一个中国人的类' #类的文档字符串 3 name ...

  7. python的类和对象——类的静态字段番外篇

    什么是静态字段 在开始之前,先上图,解释一下什么是类的静态字段(我有的时候会叫它类的静态变量,总之说的都是它.后面大多数情况可能会简称为类变量.): 我们看上面的例子,这里的money就是静态字段,首 ...

  8. python 类-如何理解python的类与对象?

    挂一个自己的学习笔记 这个时间一长就搞错了,还经常回头来看一看,尤其是self的用法. python中一切皆为对象,所谓对象:我自己就是一个对象,我玩的电脑就是对象,坐着的椅子就是对象,家里养的小狗也 ...

  9. 给Python的类和对象动态增加属性和方法

    通常我们会将编程语言分为静态和动态.静态语言的变量是在内存中的有类型的且不可变化的,除非强制转换它的类型:动态语言的变量是指向内存中的标签或者名称,其类型在代码运行过程中会根据实际的值而定.Pytho ...

  10. 【Python】Python的类和对象(长文系列第⑤篇)

    系列最后一篇来说说Python中的类与对象,Python这门语言是无处不对象,如果你曾浅要了解过Python,你应该听过Python是一种面向对象编程的语言,所以你经常可能会看到面向"对象& ...

最新文章

  1. linux shell 错误 [: =: unary operator expected 解决办法
  2. redis中的string
  3. 使用python操作postgresql 查询
  4. css3动画应用-音乐唱片旋转播放特效
  5. 使用 gpg 加密文件 - 通过 shell 或 php
  6. navicat连接远程mysql
  7. python爬虫高级知识点_Python爬虫知识点梳理总结,殿堂级小白入门必读
  8. C#语法基础(三)----窗体设计
  9. 基于JSP的小区停车管理系统设计与实现
  10. 实时渲染技术之一-------渲染管线
  11. Kindle wifi 连接不上的问题
  12. 快速学习单反相机基础操作
  13. 本地计算机的硬件基本配置信息,Windows7系统如何查看硬件的基本配置
  14. 前端程序员应该理解的reduce方法,对你的js能力很有帮助
  15. 感知器算法(PLA)
  16. 【攻略】如何用云服务器实现云搬砖
  17. 加密扩展库+php,PHP加密扩展库—Mcrypt扩展库
  18. 新的RA Group勒索软件针对美国组织进行双重勒索攻击
  19. 考研英语作文—遣词造句
  20. [科普文] Web3 中的资产负债表

热门文章

  1. mysql schema数据混乱_MySQL之Schema与数据类型优化
  2. python socket自动重连_python之tcp自动重连
  3. 课工场新闻管理jsp修改项目_jspmvc实验室预约管理系统
  4. 报告解读下载 | 数据库的未来和“十四五”数据库发展趋势与挑战
  5. 国产数据库发展十策(三):是走MySQL路线还是PostgreSQL路线?
  6. 智能运维究竟能为DBA带来什么?听听4位专家怎么说
  7. 需求蔓延,常见但不正常,教你如何破
  8. Hudi自带工具DeltaStreamer的实时入湖最佳实践
  9. 一文为你详解Unique SQL原理和应用
  10. 【华为云技术分享】用GaussDB合理管控数据资源的几点心得