Python基础之面对对象

一 什么是面向对象

面向对象是现代语言必备的一个特性。传统的面向过程编程(模块封装都是通过函数实现的,类似于C语言),不符合人类思考的一种方式。比如人吃饭这种行为,如果使用面向过程编程,那么是首先定义一个吃饭的行为,然后再把这个人传过去。这明显是不符合人类的思考方式的,人类正常的思考方式应该是,吃饭这个行为是属于人类的,应该由人的这个对象自己去执行。这种思考方式的转变,就是面向对象。面向对象把所有属于某种物体(比如人)的属性和行为全都定义在这个物体上,比如年龄,身高,体重这些是属性,比如招手,跑步,吃饭这些是行为。以后要知道一个人的年龄,应该查看这个人的年龄属性,要让这个人奔跑,应该调用这个人的奔跑方法。这种思考方式就是面向对象。

二 类和对象

1.类

是对某种物种的一种抽象表达。比如人类,人类是我们对人的一种抽象,他有年龄属性,身高属性,奔跑,吃饭等行为。

2.对象

对象是对类的一种具体化。比如具体的某个人,他是属于人类这个类的,但他是个确确实实存在的实体。总结就是,对象是类的一种具体实现。

三 类和对象的使用

1.类

定义一个类的语法是使用class关键字,开发者自己定义的类,必须继承自object类,object类是Python中所有的类的基类。类中所有的方法都要以self作为第一个参数传递进去,这是规定。self代表的是当前的对象。


class Person(object):
     def eat(self):
         print('吃饭')

2.对象

对象是对类的一个实例化,对象的创建方式如下(比如要实现一个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'

五 访问限制

1.受保护的属性和方法

有时候在类中的属性或者是方法不想被外界调用,但还是可以被外界所调用,那么就叫做受保护的属性或者方法。受保护的属性或者方法,使用一个下划线开头:

 class Person(object):
     def __init__(self):
         self._age = 19

 p1 = Person()
 # 以下代码可以打印出_age,但这样做是违背开发者意愿的。
 print(p1._age)

2.私有属性和方法

有时候在类中的属性或者方向不让外界调用,那么就可以使用定义成私有属性或者私有方法。私有属性或者方法使用两个下划线开头:

 class Person(object):
     def __init__(self):
         self.__age = 19

 p1 = Person()
 # 以下代码将报错
 print(p1.__age)

3.更多

私有方法或者属性不是说100%不能访问,以上方式,可以通过_Person__age来访问,但这样做是不推荐的。
__init__这些方法不是私有方法,是特殊变量或方法。

六 析构函数和引用计数

1.析构函数

Python中的类也有析构函数,也即__del__方法,只要这个对象在内存中即将被消灭的时候,就会调用这个方法。

 class Person(object):
     def __del__(self):
         print('我即将被消灭了~')

 p1 = Person()
 # 调用完这个代码后,就会去执行Person类中的__del__方法
 del p1

2.引用计数

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这个类的eatrun方法。

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)

十三 类方法和静态方法

1.类方法

类方法是属于这个类的,可以通过这个类对象调用,也可以通过这个类的实例对象调用。

2.静态方法

静态方法是属于类的,只能通过类名字调用。静态方法中不能调用类属性,如果要调用,只能通过类名来调用。并且不需要传任何参数。

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)

十四 example

使用面向对象的方法组装一台电脑
电脑由以下几部分组成: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()

你可能感兴趣的:(Python,#,Python基础,Python,面对对象,封装,继承,多态)