面向对象是现代语言必备的一个特性。传统的面向过程编程(模块封装都是通过函数实现的,类似于C语言),不符合人类思考的一种方式。比如人吃饭这种行为,如果使用面向过程编程,那么是首先定义一个吃饭的行为,然后再把这个人传过去。这明显是不符合人类的思考方式的,人类正常的思考方式应该是,吃饭这个行为是属于人类的,应该由人的这个对象自己去执行。这种思考方式的转变,就是面向对象。面向对象把所有属于某种物体(比如人)的属性和行为全都定义在这个物体上,比如年龄,身高,体重这些是属性,比如招手,跑步,吃饭这些是行为。以后要知道一个人的年龄,应该查看这个人的年龄属性,要让这个人奔跑,应该调用这个人的奔跑方法。这种思考方式就是面向对象。
是对某种物种的一种抽象表达。比如人类,人类是我们对人的一种抽象,他有年龄属性,身高属性,奔跑,吃饭等行为。
对象是对类的一种具体化。比如具体的某个人,他是属于人类这个类的,但他是个确确实实存在的实体。总结就是,对象是类的一种具体实现。
定义一个类的语法是使用class关键字,开发者自己定义的类,必须继承自object类,object类是Python中所有的类的基类。类中所有的方法都要以self作为第一个参数传递进去,这是规定。self代表的是当前的对象。
class Person(object):
def eat(self):
print('吃饭')
对象是对类的一个实例化,对象的创建方式如下(比如要实现一个Person的对象)
person1 = Person()
person1.eat()
构造函数是Python类在初始化对象的时候会调用的方法。一般在这个方法中给一些属性进行初始化。一般就是用来初始化实例属性的:
# 1. 定义类必须使用class关键字,然后继承自object类
# 2. 在类中定义方法,第一个参数必须是self,self代表的是当前这个对象
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__这些方法不是私有方法,是特殊变量或方法。
Python中的类也有析构函数,也即__del__方法,只要这个对象在内存中即将被消灭的时候,就会调用这个方法。
class Person(object):
def __del__(self):
print('我即将被消灭了~')
p1 = Person()
# 调用完这个代码后,就会去执行Person类中的__del__方法
del p1
Python中的对象是使用引用计数的方式实现的。也即如果没有任何对象引用到一块内存,那么Python将会把这块内存回收。看以下代码
class Person(object):
def __del__(self):
print('我即将被消灭了~')
p1 = Person()
p2 = p1
del p1
# 先会打印=====
print('======')
# 再会去执行__del__方法
继承可以使用其他类当作自己的父类,那么父类中的方法和公有属性都可以被子类使用。继承的好处是可以让子类节省代码,实现更多的功能。
class Person(object):
def eat(self):
print('在吃东西')
def run(self):
print('奔跑中')
class Student(Person):
pass
以上Student
这个类没有写任何方法,但是也能拥有父类Person
这个类的eat
和run
方法。
class Person(object):
def __init__(self,name):
self.__name = name
self._age = 12
def greet(self):
print('hello,my name is %s' % self.__name)
def __run(self):
print('base class is running')
class Student(Person):
def greet(self):
# print('hell, my name is %s' % self.__name)
print('hello my age is %d' % self._age)
self.__run()
# p1 = Person('zhiliao')
# p1.greet()
s1 = Student('zhiliao')
s1.greet()
# 本节课的重点:子类不能继承父类的私有属性和方法
有些时候,父类中的方法不一定适合子类,那么这时候可以重写父类的方法,而使用子类自己定义的方法。
class Person(object):
def eat(self):
print('在吃东西')
def run(self):
print('奔跑中')
# 1. 如果父类的方法不能满足子类的需求,那么可以重写这个方法,以后对象调用同名
# 方法的时候,就只会执行子类的这个方法。
# 2. 虽然父类的方法不能完全满足子类的需求,但是父类的方法的代码还是需要执行,
# 那么可以通过super这个函数来调用父类的方法。
# 3. super的用法:super(类名,self).方法名([参数])
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的面向对象编程中,是支持多继承的,也即一个类可以继承自多个父类。
#coding: utf-8
# class Person:
# def __init__(self):
# self.name = 'zhiliao'
# p1 = Person()
# print(type(p1))
class Ma(object):
def run(self):
print(u'马在奔跑')
def eat(self):
print(u'马在吃草')
class Lv(object):
def lamo(self):
print(u'驴在拉磨')
def eat(self):
print(u'驴在吃麦秆')
class Luozi(Ma,Lv):
def eat(self):
# 如果不想按照__mro__的顺序执行父类的方法,那么
# 可以通过以下方式执行
Lv.eat(self)
Ma.eat(self)
super(Ma, self).eat()
# super(Luozi,self).eat()
print(u'骡子在吃稻谷')
pass
lz = Luozi()
lz.eat()
# print(Luozi.__mro__)
# lz.run()
# lz.lamo()
以上骡子类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()
1.类属性:这个属性属于类的,所有对象都可以访问。
2.实例属性:这个属性是属于对象的,只有这一个对象可以访问和使用,其他对象不能使用。
3.注意事项:对象可以访问类属性,但是如果想要修改类属性,则必须通过类名进行修改!
#coding: utf-8
class Person(object):
country = 'china'
def __init__(self,name,country):
self.name = name
self.country = country
def greet(self):
# 如果对象上没有country属性,那么通过self.country和Person.country的
# 效果是一样的,都是访问Person的类属性
# 如果给对象绑定了country属性,那么通过self.country访问到的就是这个对象
# 上的属性,通过Person.country访问到的就是类属性
print(u'hell my name is %s,i am come from %s' % (self.name,Person.country,self.country))
# 实例属性:
# 绑定到对象上的属性就是实例属性
# 实例属性只在当前对象上有作用
# p1 = Person('zhiliao')
# p1.age = 18
# print(p1.name)
# p2 = Person('ketang')
# print(p2.name)
# print(p2.age)
# 类属性:
# 如何在类中定义类属性
# 类属性可以通过对象进行访问
# 如果通过对象修改类属性,那么其实不是修改类属性,而是在这个对象上面重新定义了
# 一个名字相同的实例属性
p1 = Person('zhiliao')
p1.country = 'earth'
print(p1.country)
p2 = Person('ketang')
p2.country = 'usa'
print(p2.country)
# 要正确的修改类属性,只能通过类名的方式修改
Person.country = 'abc'
print(Person.country)
类方法是属于这个类的,可以通过这个类对象调用,也可以通过这个类的实例对象调用。
静态方法是属于类的,只能通过类名字调用。静态方法中不能调用类属性,如果要调用,只能通过类名来调用。并且不需要传任何参数。
class Person(object):
country = 'china'
@classmethod
# 类方法:第一个参数必须是cls,这个cls代表的是当前这个类
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()