Python基础-面向对象(1)
一、什么是面向对象:
面向对象是现代语言必备的一个特性。传统的面向过程编程(模块封装都是通过函数实现的,类似于C语言),不符合人类思考的一种方式。比如人吃饭这种行为,如果使用面向过程编程,那么是首先定义一个吃饭的行为,然后再把这个人传过去。这明显是不符合人类的思考方式的,人类正常的思考方式应该是,吃饭这个行为是属于人类的,应该由人的这个对象自己去执行。这种思考方式的转变,就是面向对象。面向对象把所有属于某种物体(比如人)的属性和行为全都定义在这个物体上,比如年龄,身高,体重这些是属性,比如招手,跑步,吃饭这些是行为。以后要知道一个人的年龄,应该查看这个人的年龄属性,要让这个人奔跑,应该调用这个人的奔跑方法。这种思考方式就是面向对象。
二、类和对象:
- 类:是对某种物种的一种抽象表达。比如人类,人类是我们对人的一种抽象,他有年龄属性,身高属性,奔跑,吃饭等行为。
- 对象:对象是对类的一种具体化。比如具体的某个人,他是属于人类这个类的,但他是个确确实实存在的实体。总结就是,对象是类的一种具体实现。
三、类和对象的使用:
- 类:定义一个类的语法是使用
class
关键字,开发者自己定义的类,必须继承自object
类,object
类是Python
中所有的类的基类。类中所有的方法都要以self
作为第一个参数传递进去,这是规定。self
代表的是当前的对象。class Person(object): def eat(self): print('吃饭')
- 对象:对象是对类的一个实例化,对象的创建方式如下(比如要实现一个Person的对象):
person1 = Person() person1.eat()
四、构造函数和实例属性:
构造函数是Python类在初始化对象的时候会调用的方法。一般在这个方法中给一些属性进行初始化。一般就是用来初始化实例属性的:
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
person1 = Person('zhiliao',18)
print(person1)
给对象添加实例属性非常简单,以上是通过self.name
的方式实现的,其实也可以通过以下方式实现,原理都是一样的。
class Person(object):
pass
person1 = Person()
# 给person1这个对象绑定name属性
person1.name = 'zhiliao'
五、访问限制:
-
受保护的属性和方法:有时候在类中的属性或者是方法不想被外界调用,但还是可以被外界所调用,那么就叫做受保护的属性或者方法。受保护的属性或者方法,使用一个下划线开头:
class Person(object): def __init__(self): self._age = 19 p1 = Person() # 以下代码可以打印出_age,但这样做是违背开发者意愿的。 print(p1._age)
-
私有属性和方法:有时候在类中的属性或者方向不让外界调用,那么就可以使用定义成私有属性或者私有方法。私有属性或者方法使用两个下划线开头:
class Person(object): def __init__(self): self.__age = 19 p1 = Person() # 以下代码将报错 print(p1.__age)
-
更多:
- 私有方法或者属性不是说100%不能访问,以上方式,可以通过
_Person__age
来访问,但这样做是不推荐的。 __init__
这些方法不是私有方法,是特殊变量或方法。
- 私有方法或者属性不是说100%不能访问,以上方式,可以通过
六、继承:
继承可以使用其他类当作自己的父类,那么父类中的方法和公有属性都可以被子类使用。继承的好处是可以让子类节省代码,实现更多的功能。
class Person(object):
def eat(self):
print('在吃东西')
def run(self):
print('奔跑中')
class Student(Person):
pass
以上Student
这个类没有写任何方法,但是也能拥有父类Person
这个类的eat
和run
方法。
七、重写父类的方法:
有些时候,父类中的方法不一定适合子类,那么这时候可以重写父类的方法,而使用子类自己定义的方法。
class Person(object):
def eat(self):
print('在吃东西')
def run(self):
print('奔跑中')
class Student(Person):
def eat(self):
print('吃食堂大锅菜')
有时候想使用父类的方法,但是父类中的方法不完全满足我们的需求,那么就可以在子类的同名方法中使用super
关键字调用父类的方法,然后再在子类中实现自己的需求:
class Person(object):
def eat(self):
print('在吃东西')
class Student(Person):
def eat(self):
super(Student,self).eat()
print('这是学生的吃饭方法')
以上在Student
中的eat
方法中,首先会调用父类Person
的eat
方法,然后再执行子类自己的代码。
八、私有属性和方法在子类中的使用:
在类继承中,私有属性和方法是不能被子类继承的:
class Person(object):
def __greet(self):
print('helo')
class Student(Person):
def greet(self):
self.__greet()
s1 = Student()
# 以下代码将报错,因为子类不能继承父类的方法
s1.greet()
九、多继承及其注意事项:
在Python
的面向对象编程中,是支持多继承的,也即一个类可以继承自多个父类。
class Ma(object):
def qima(self):
print('骑马')
class Lv(object):
def lamo(self):
print('拉磨')
class Luozi(Ma,Lv):
pass
以上骡子类Luozi
没有写任何方法,但是可以继承qima
和lamo
两种操作。但是在多继承中也有需要注意的地方,就是会出现另行的情况,比如以下类:
class Animal(object):
def eat(self):
print('动物吃东西')
class Ma(Animal):
def qima(self):
print('骑马')
def eat(self):
print('马吃草')
super(Ma,self).eat()
print('马吃完了草')
class Lv(Animal):
def lamo(self):
print('驴拉磨')
def eat(self):
print('驴吃麦子皮')
super(Lv,self).eat()
print('驴吃完了麦子皮')
class Luozi(Ma,Lv):
def eat(self):
super(Luozi,self).eat()
print('骡子既吃草又吃麦子皮')
luozi = Luozi()
luozi.eat()
print(Luozi.__mro__)
在多继承中,采用的C3算法
,使用的是广度优先的算法,打印Class.__mro__
可以看到基类执行的顺序。
十、多态:
面向对象有三大特性,分别为:封装/继承/多态。多态的意思是,不同的对象,都实现了同一个接口,因此我们可以不管这个对象是什么,直接调用这个方法旧可以了。
比如王者荣耀中的英雄,每个人都有三个技能,但每个英雄的具体实现是不一样的。如果用代码来表示,那么可以用以下方式表示:
class Hero(object):
def stroke(self):
pass
class Chengyaojin(Hero):
def stroke(self):
print('回血加攻击速度和攻击力')
class Xiangyu(Hero):
def stroke(self):
print('推人')
hero_index = input('请输入英雄:')
hero = None
if hero_index == '1':
hero = Chengyaojin()
elif hero_index == '2':
hero = Xiangyu()
else:
hero = Hero()
skill_index = input('请输入技能:')
if skill_index == '3':
hero.stroke()
十一、类属性和实例属性:
- 类属性:这个属性属于类的,所有对象都可以访问。
- 实例属性:这个属性是属于对象的,只有这一个对象可以访问和使用,其他对象不能使用。
- 注意事项:对象可以访问类属性,但是如果想要修改类属性,则必须通过类名进行修改!
十二、类方法和静态方法:
-
类方法:类方法是属于这个类的,可以通过这个类对象调用,也可以通过这个类的实例对象调用。
-
静态方法:静态方法是属于类的,只能通过类名字调用。静态方法中不能调用类属性,如果要调用,只能通过类名来调用。并且不需要传任何参数。
class Person(object): country = 'china' @classmethod def show(cls): print('i am from %s' % cls.country) @staticmethod def show(): print('i am from %s' % Person.country)
十三、使用面向对象的方法组装一台电脑:
电脑由以下几部分组成:CPU、内存条、硬盘等。每个部分都定义成一个类,最后组装成一台电脑,让他跑起来。示例代码如下:
class CPU(object):
def __init__(self,brand,core,ghz,interface):
self.brand = brand
self.core = core
self.ghz = ghz
self.interface = interface
def run(self):
print('{}牌子,核心数为{}跑起来了'.format(self.brand,self.core))
class RAM(object):
def __init__(self,brand,size):
self.brand = brand
self.size = size
def run(self):
print('{}牌子,尺寸为{}的内存跑起来了'.format(self.brand,self.size))
class Disk(object):
def __init__(self,brand,size):
self.brand = brand
self.size = size
def run(self):
print("{}牌子,大小为{}的硬盘跑起来了".format(self.brand,self.size))
class Computer(object):
def __init__(self,cpu_interface,max_ram,max_disk):
self.cpu_interface = cpu_interface
self.max_ram = max_ram
self.max_disk = max_disk
self.cpu = None
self.rams = []
self.disks = []
def add_cpu(self,cpu):
if self.cpu:
print('该主板已经有CPU了!')
return False
if cpu.interface != self.cpu_interface:
print('该主板的CPU接口与此CPU接口不一致!')
return False
self.cpu = cpu
def add_ram(self,ram):
if len(self.rams) == self.max_ram:
print('该主板能容纳内存条已达到上限,不能再添加!')
return
self.rams.append(ram)
def add_disk(self,disk):
if len(self.disks) == self.max_disk:
print('该主板能容纳硬盘数量已达上线,不能在添加!')
def run(self):
print('通电了...')
# 1. cpu先跑起来
if self.cpu:
self.cpu.run()
else:
print('没有CPU,不能跑起来')
return
# 2. 内存跑起来
if len(self.rams) > 0:
for ram in self.rams:
ram.run()
else:
print('没有内存条,不能跑起来')
return
# 3. 硬盘爬起来
if len(self.disks) == 0:
for disk in self.disks:
disk.run()
else:
print('没有硬盘,电脑不能跑起来')
return
print('电脑跑起来了,你可以上知了课堂学习Python了!')
def main():
cpu = CPU(brand='intel',ghz=2.7,core=4,interface='11211')
ram1 = RAM(brand='金士顿',size=4)
ram2 = RAM(brand='金士顿',size=4)
disk = Disk(brand='tongchi',size=256)
computer = Computer(cpu_interface='11211',max_ram=2,max_disk=2)
computer.add_cpu(cpu)
computer.add_ram(ram1)
computer.add_ram(ram2)
computer.add_disk(disk)
computer.run()
if __name__ = '__main__':
main()