Python菜鸟编程第十课之面向对象
1.面向过程与面向对象编程
- 面向过程:
所谓过程,就是我们解决问题的步骤,一步步的按照流程走,有先后之分。整个设计就好比流水线,思维上比较机械。
优点:复杂问题流程化,将问题分解。
缺点:拓展性不好
- 面向对象:
对象是一个数据以及相关行为的集合,面向对象是功能上指向建模对象。面向对象是通过数据和行为方式来描述交互对象的集合。
优点:解决程序的拓展性
缺点:复杂度远高于面向过程。交互式解决问题,无法准确预测结果。
object1 Tom 特征: school=zucc name=tom age=20 sex=male 技能: eat study sleep object2 Jack 特征: school=zucc name=jack age=21 sex=male 技能: eat study sleep sing
讯享网
类就是类别、种类。对象就是特征和技能的统一体。类则是这一系列对象的特征和技能的结合。现实生活中,先有个体(对象)才有类别,但对于程序,必须先有类,才会有对象。
2.面向对象编程
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
讯享网OOP(object oriented programming)
OOP把对象作为程序的一个基本单元,一个对象就包含了数据和操作数据的函数。
在Python中,所有数据类型,都可以称之为对象,同时我们也可以自定义对象。
自定义的对象的数据类型就是面向对象中类(class)的概念。
demo1:
用面向对象编程来处理学生成绩。
class Student: def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1 = Student('Tom', 90) stu1.find_score()
讯享网运行结果: Tom : 90
用面向过程来处理学生成绩:
stu1 = {
'name': 'Tom', 'score': 90} def find_score(stu): print(stu['name'], ":", stu['score']) find_score(stu1)
讯享网运行结果: Tom : 90
demo2:
class Student: def __init__(self, name, score, school, age): self.name = name self.score = score self.school = school self.age = age def find_score(self): print(self.name, ':', self.score) def eating(self): print(self.name, '来自', self.school, ',今年', self.age, '岁,', '正在eat') def studying(self): print(self.name, '来自', self.school, ',今年', self.age, '岁,', '正在 study') stu1 = Student('Tom', 90, 'zucc', 18) stu1.find_score() stu1.eating() stu1.studying()
讯享网运行结果: Tom : 90 Tom 来自 zucc ,今年 18 岁, 正在eat Tom 来自 zucc ,今年 18 岁, 正在 study
3.类的定义和使用
3.1类的定义
类的命名,约定俗成使用大驼峰式命名。大驼峰就是变量名称的首字母大写。
语法:
class ClassName(object): '''说明文档''' def \__init__(self,para1,para2...): self.对象属性1=para1 def 方法名1(self): pass class_statement obj=ClassName(para1,para2) #类的实例化,代表具体的东西,ClassName():调用\__init__,括号内传参,无需传入self,参数一一对应,结果返回对象obj obj.对象属性1#查看对象的属性 obj.方法名#调用类的方法
类的两个作用:
- 属性引用:类名.属性
- 实例化:类名加括号就是实例化,它能够自动触发__init__函数,进而为每个实例定制自己的特征。
demo:1
定义一个简单的类。
讯享网class Student: def __init__(self, name, score, school, age): self.name = name self.score = score self.school = school self.age = age stu1 = Student('Tom', 90, 'zucc', 18)#将类实例化 print(stu1.name,stu1.score)
运行结果: Tom 90
和普通函数相比,在类中定义方法时,第一个参数必须是self。除了第一个参数外,其他的和普通函数没什么区别。
__init__方法:为对象初始化自己独有的特征。该方法中可以有任意的代码,但是一定不能有返回值。
demo2:
讯享网class Student: def test_instance(self): print(self) stu1 = Student() stu1.test_instance()
运行结果: <__main__.Student object at 0x0000025338BB82B0>
self 代表的是实例,而非类。
3.2数据封装
demo:
讯享网class Student: def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1 = Student('Tom', 90) stu1.find_score()
通过_init_()让stu1实例本身就拥有了相关数据,如果要访问这些数据,我们可以直接在student类的内部定义相关的函数来访问,以此来“封装”数据。这些封装数据的函数与Student类本身是关联起来的,称之为方法。
demo1:
class Point: pass p1 = Point() p1.x = 5 p1.y = 4 print(p1.x, p1.y)
讯享网运行结果: 5 4
通过点记法给实例化的对象赋予任何属性。
demo2:
class Point: def resect(self): self.x=0 self.y=0 p1 = Point() p1.resect() print(p1.x, p1.y) p1.x = 5 p1.y = 4 print(p1.x, p1.y)
讯享网运行结果: 0 0 5 4
demo:
import math class Point: def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0,0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x) 2 + (self.y - other_point.y) 2) p1 = Point() p1.resect() p2=Point() p2.move(3,4) print(p1.cal_distence(p2))
讯享网运行结果: 5.0
demo:
import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x) 2 + (self.y - other_point.y) 2) p3 = Point(6, 8) print(p3.x, p3.y)
讯享网运行结果: 6 8
3.3类属性的查看
- dir()
demo:
import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x) 2 + (self.y - other_point.y) 2) print(dir(Point))
讯享网运行结果: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cal_distence', 'move', 'resect']
2.类名.__dict__查看
返回字典,key为属性名,value为属性值。
demo:
import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x) 2 + (self.y - other_point.y) 2) print(Point.__dict__)
讯享网运行结果: {
'__module__': '__main__', '__init__': <function Point.__init__ at 0x0000016F891A6488>, 'move': <function Point.move at 0x0000016F8A24A950>, 'resect': <function Point.resect at 0x0000016F8A24A9D8>, 'cal_distence': <function Point.cal_distence at 0x0000016F8A24AA60>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None}
特殊的类属性:
| 函数名 | 描述 |
|---|---|
| 类名._name_ | 返回类的名字 |
| 类名._doc_ | 返回类的文档字符串 |
| 类名._base_ | 返回类的第一个父类 |
| 类名._bases_ | 返回类的所有父类构成的元组 |
| 类名._module_ | 返回类定义所以的模块 |
| 类名._class_ | 返回实例所对应的类 |
| 类名._dict_ | 返回类的字典属性 |
3.4类的交互
demo:
class Person: def __init__(self, name, aggressivity, life_value): self.name = name self.aggressivity = aggressivity self.life_value = life_value def attack(self, dog): dog.life_value -= self.aggressivity class Dog: def __init__(self, name, breed, aggressivity, life_value): self.name = name self.breed = breed # 品种 self.aggressivity = aggressivity self.life_value = life_value def bite(self, people): people.life_value -= self.aggressivity per = Person('Bob', 10, 1000) dog = Dog('Wawa', 'Husky', 20, 500) print(dog.life_value) per.attack(dog) print(dog.life_value)
讯享网运行结果: 500 490
3.5类命名空间与对象、实例的空间
创建一个类就会创建一个类的名称空间,用来存储我们定义的所有变量名,这些名字就是属性。
类的属性分为:
- 静态属性:
直接在类中定义的变量
- 动态属性:
在类中定义的方法
静态属性是共享给所有对象的,动态属性是绑定到所有对象的。
demo:
class Person: face = 'aaa' def __init__(self, name, aggressivity, life_value): self.name = name self.aggressivity = aggressivity self.life_value = life_value def attack(self, dog): dog.life_value -= self.aggressivity per = Person('Bob', 10, 1000) per1=Person('Tom',23,1000) print(id(per.face)) print(id(per1.face)) print(per.attack)#注意,这里都是没有加括号的 print(per1.attack) print(Person.attack)
讯享网运行结果: 40 40 <bound method Person.attack of <__main__.Person object at 0x00000E5940>> <bound method Person.attack of <__main__.Person object at 0x00000E5E80>> <function Person.attack at 0x00000A950>
3.6类的继承
类的三大特性:继承、多态、封装。
在面向对象编程中,当我们定义一个新的类时,可以从某个现有的类继承,新的类就被称为子类(Sub Class),而被继承的类则被称为基类,父类,超类(Base Class,Father Class ,Super Class)。
demo1:
class Animal(object): def run(self): print('Animal is runing.') class Dog(Animal): pass class Cat(Animal): pass dog=Dog() cat=Cat() print(dog.run()) print(cat.run())
讯享网运行结果: Animal is runing. None Animal is runing. None
demo2:
class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Animal2: pass class Dog(Animal): # 单继承 pass class Cat(Animal): # 单继承 pass class Huaky(Animal, Animal2): # 多继承,用逗号隔开 pass print(Dog.__bases__) print(Huaky.__bases__) print(Animal.__bases__) print(Animal2.__class__)
讯享网运行结果: (<class '__main__.Animal'>,) (<class '__main__.Animal'>, <class '__main__.Animal2'>) (<class 'object'>,) <class 'type'>
如果不指定基类,Python会默认继承object类。object是所有Python的基类,提供一些常见方法的实现。
demo3:
多态,当子类与父类存在相同的方法时,子类的方法会覆盖父类的方法。
定义一个类的时候,实际上就是定义了一种数据类型。我们自定义的数据类型和Python自带的数据类型,如str,int等什么区别。
class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') dog=Dog() print(dog.run())
讯享网运行结果:
demo4:
class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') dog=Dog() li=[] print(isinstance(li,list))#isinstance()用来判断数据类型 print(isinstance(dog,Dog)) print(isinstance(dog,Animal))
讯享网运行结果: True True True
对于一个变量,我们只需知道他的父类型,无需知道子类型,就可以放心调用相关的方法。运行时的具体方法时作用在子类型上还是父类型上,由运行对象决定。也即是说,调用时只管调用,不管细节,当我们新增一个子类时,只要保证相关的方法编写正确,就不用管原来的代码是如何调用的。
“开闭”原则:
- 对拓展开放:允许新增子类
- 对修改封闭:不需要修改依赖父类类型的函数。
demo5:
class Student: school = 'zucc' def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1=Student('Bob',98) print(stu1.score) stu1.score=50 print(stu1.score)
讯享网运行结果: 98 50
从这里可以看出,外部代码可以修改实例的属性(name,score)。如果要让内部的属性不被外部访问,可以在属性前面加两个下划线。
在Python中,实例的变量名如果以双下划线开头,就变成了一个私有变量,只有内部可以访问,外部不能访问。
demo6:
class Student: school = 'zucc' def __init__(self, name, score): self.name = name self.__score = score def find_score(self): print(self.name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.score) stu1.score = 50 print(stu1.score)
讯享网运行结果: Traceback (most recent call last): File "D:/PyCharm/BClass/PXClass/2019-7-29/daylystudy.py", line 153, in <module> print(stu1.score) AttributeError: 'Student' object has no attribute 'score'
demo7:
class Student: school = 'zucc' def __init__(self, name, score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score def find_score(self): print(self.__name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.get_score()) stu1.score = 50 print(stu1.get_score())
讯享网运行结果: 98 98
3.7类的封装
隐藏对象的属性和实现细节仅对外提供公共访问的方式。
这样做的优点在于:
- 可以将变化隔离。
- 便于使用
- 提高安全性
- 提高复用性
封装的原则:将不需要对外提供的内容隐藏起来。隐藏属性,提供公共方法对其进行访问。
demo:
class Student: school = 'zucc' def __init__(self, name, score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score def set_score(self,score): if 0<=score<=100: self.__score=score else: raise ValueError('Bad score') def find_score(self): print(self.__name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.find_score()) stu1.score=97 print(stu1.score) print(stu1.find_score()) print(stu1.set_score(97)) print(stu1.find_score()) print(stu1._Student__score)
讯享网运行结果: Bob : 98 #print(stu1.find_score()) None 97 #print(stu1.score) Bob : 98 #print(stu1.find_score()) None None #print(stu1.set_score(97)) Bob : 97 #print(stu1.find_score()) None #print(stu1._Student__score) 97
demo:
class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') class Cat(Animal): # 单继承 pass class Duck: def run(self): print('多态测试。') dog = Dog() cat = Cat() duck = Duck() dog.run() cat.run() duck.run() def run_twice(animal): animal.run() animal.run() run_twice(duck)
讯享网运行结果: Dog is Running Animal is runing. 多态测试。 多态测试。 多态测试。
鸭子类型不需要有严格的继承关系,一个对象,只要”看起来像鸭子,走路像鸭子“,也就是说,如果要编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为相似但与其没有任何关系的全新对象。
比方说,利用标准库中定义的各种“与文件类似”的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/40613.html