python学习之路(五)------类和面向对象
一、类和对象
1.1 什么是对象?
名人曾经说过,世间万物皆为对象,人十个对象,动物植物甚至是一张椅子,也是一个对象。可以从世间万物总结出来,对象是由属性和方法构成的。一个对象的特征称为属性,如人的皮肤,眼睛,嘴巴等等,用来描述一个对象具体表现;二一个对象的行为则称为方法,如人会编程,狗会吃屎等。那么将这些对象在代码中就可以描述为
# 人这个对象
# 对象的属性 name = 'faker' age = 22 hobby = ['lol', 'ball'] # 对象的方法 def playgame(game): print("play %s" % (game))
可以看出,对象把原本分散的数据和功能都整合到了一起,这样可以解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。这样提高了程序的可拓展性。
1.2 类和对象
类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体
- 在现实世界中,我们是先有了对象,才会产生类,因为只有我们真正看见了一个具体的对象,才能总结出它的属性和方法。
- 在编程世界中,先定义类,才会产生对象。
1.3 创建类
- 在python中调用class方法创建一个类
# 人这个对象 class human: # 对象的属性 name = 'faker' age = 22 hobby = ['lol', 'ball'] # 对象的方法 def playgame(self, game): print("play %s" % (game))
- 这些代码在定义中便会执行,因此便会产生了新的名称空间,我们可以通过__dict__的方法来查看
# 人这个对象 class human: name = 'faker' age = 22 hobby = ['lol', 'ball'] def playgame(self, game): print("play %s" % (game)) print(human.__dict__) """ {'__module__': '__main__', 'name': 'faker', 'age': 22, 'hobby': ['lol', 'ball'], 'playgame': <function human.playgame at 0x02E50DB0>, '__dict__': <attribute '__dict__' of 'human' objects>, '__weakref__': <attribute '__weakref__' of 'human' objects>, '__doc__': None} """
- 可以看到,类所有的属性都存放在这个属性字典中.我们可以通过.的方法调用这些属性方法,实际上就是在操作属性字典。
# 人这个对象 class human: name = 'faker' age = 22 hobby = ['lol', 'ball'] def playgame(self, game): print("play %s" % (game)) print(human.name) # 等同于human.__dict__['name'] human.age = 30 # human.__dict__['age'] = 30 print(human.age) print(human.hobby) human.playgame('h1','lol') # 这里传入h1是因为human中playgame方法中的self就是一个实例对象本身,所以在类条用这个方法是需要传入一个实例,否则会报错TypeError: playgame() missing 1 required positional argument: 'game' “”” faker 30 ['lol', 'ball'] play lol “””
二、面向对象编程
面向对象程序设计(Object Oriented Programming)作为一种新方法,其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。模型是用来反映现实世界中事物特征的。任何一个模型都不可能反映客观事物的一切具体特征,只能对事物特征和变化规律的一种抽象,且在它所涉及的范围内更普遍、更集中、更深刻地描述客体的特征。通过建立模型而达到的抽象是人们对客体认识的深化。
2.1 类的实例化
调用类的过程称为类的实例化,拿到的返回值就是一个对象或实例
# 人这个对象 class human: name = 'faker' age = 22 hobby = ['lol', 'ball'] def playgame(self, game): print("play %s" % (game)) h1 = human() print(h1) """ <__main__.human object at 0x02D0F050> """
拿到了这个实例,我们就可以通过点的方式调用它们的类的属性内容
# 人这个对象 class human: name = 'faker' age = 22 hobby = ['lol', 'ball'] def playgame(self, game): print("play %s" % (game)) h1 = human() print(h1.name) print(h1.age) print(h1.hobby) h1.playgame('lol') """ faker 22 ['lol', 'ball'] play lol """
2.2 __init__方法--------为实例创造独立空间
- 在没有运用__init__方法是,我们调用实例的__dict__方法,可以发现是一个空字典,证明实例是只有类的公共属性,而没有自己的独特属性,这显然是不符合实际的。
print(h1.__dict__) “”” {} “””
- 调用__init__方法,专门对实例初始化自己独立的特征,这个方法在对象创建之后便会执行。
class human: species = 'animal' def __init__(self, name, age, hobby): self.name = name self.age = age self.hobby = hobby print(‘self ’,self) def playgame(self, game): print("play %s" % (game)) h1 = human('faker', 22, ['lol', 'ball']) # 这里为什么__init__方法有四个参数,而实例化时只传递了三个参数?因为self是实例对象本身,h1就是传递给了self print(h1.__dict__) “”” self <__main__.human object at 0x02D4FB50> {'name': 'faker', 'age': 22, 'hobby': ['lol', 'ball']} “””
- 同样的实例也是通过.方法来操作属性,实例可以操作类的属性
h1 = human('faker', 22, ['lol', 'ball']) print(h1.name) h1.hobby[1] = 'sing' # 等同于h1.__dict__['hobby'][1] = 'sing' print(h1.hobby) h1.playgame('lol') “”” faker ['lol', 'sing'] play lol “””
2.3 类属性和实例属性
- 类的属性具体可以分为数据属性和函数属性,通过调用__dict__方法可以查看,通过.方法可以调用属性(实际上就是操作属性字典)。
- 实例的属性就是通过__init__方法实例化出来的特有的属性,实例属性没有函数属性,只能调用类的函数属性。
class human: species = 'animal' def __init__(self, name, age, hobby): self.name = name self.age = age self.hobby = hobby def playgame(self, game): print("play %s" % (game)) h1 = human('faker', 22, ['lol', 'ball']) h2 = human('uzi', 21, ['lol', 'bath']) print('h1.__dict__', h1.__dict__) print('h2.__dict__', h2.__dict__) print('human.__dict__', human.__dict__) “”” h1.__dict__ {'name': 'faker', 'age': 22, 'hobby': ['lol', 'ball']} h2.__dict__ {'name': 'uzi', 'age': 21, 'hobby': ['lol', 'bath']} human.__dict__ {'__module__': '__main__', 'species': 'animal', '__init__': <function human.__init__ at 0x03030DB0>, 'playgame': <function human.playgame at 0x07591CD8>, '__dict__': <attribute '__dict__' of 'human' objects>, '__weakref__': <attribute '__weakref__' of 'human' objects>, '__doc__': None} “””
用个图更好地表示
- 更多关于类属性和实例属性的知识可以看一下博客https://www.cnblogs.com/scolia/p/5582268.html
2.4 类属性和实例属性的绑定
- 在类中定义的变量(__init__之外)的变量是类的数据属性,也是实例公共的数据属性,指向同一个内存地址。
print(id(human.species)) print(id(h1.species)) print(id(h2.species)) """ 46823520 46823520 46823520 """
- 而类中定义的函数属性,是绑定给对象的,不同的对象就是不同的绑定方法,所以类的函属性内存地址不同和对象的调用的函数的内存地址不同。
- 具体而言,就是类实例化了哪个实例,就将函数属性绑定给哪个实例。实例调用函数就是将自己作为参数传给self,即 h1.playgame('lol') = human.playgame('h1','lol')
print(human.playgame) print(h1.playgame) print(h2.playgame) """ <function human.playgame at 0x077FFCD8> <bound method human.playgame of <__main__.human object at 0x078033F0>> <bound method human.playgame of <__main__.human object at 0x07803410>> """
2.5 属性查找顺序和修改规则
- 我们实例化的对象的名称空间里只存放对象特有的属性,公共属性存放于的属性字典中。对象在访问一个属性时,会先从自己的属性字典中去查找,若没找到,再会去类的属性字典中去查找。
class human: species = 'animal' name = 'human' def __init__(self, name, age, hobby): self.name = name self.age = age self.hobby = hobby def playgame(self, game): print("play %s" % (game)) h1 = human('faker', 22, ['lol', 'ball']) print(h1.name) print(h1.species) """ faker # 对象自己的属性字典就存在name属性,所以name为faker animal # 对象属性字典中没有species属性,所以去类的属性字典查找 """
- 类可以修改公共属性,而对象不能修改
class human: species = 'animal' name = 'human' def __init__(self, name, age, hobby): self.name = name self.age = age self.hobby = hobby def playgame(self, game): print("play %s" % (game)) h1 = human('faker', 22, ['lol', 'ball']) human.species = 'people' print('the first', h1.species) print('the first', h1.__dict__) h1.species = 'advanced _animal' print('the second', h1.species) print('the second', h1.__dict__) """ the first people the first {'name': 'faker', 'age': 22, 'hobby': ['lol', 'ball']} the second advanced _animal the second {'name': 'faker', 'age': 22, 'hobby': ['lol', 'ball'], 'species': 'advanced _animal'} """
可以看到,用类去修改公共属性时,属性会被修改;而用对象去修改时,会在对象的属性字典里新增一个属性。