Python基础--面向对象

本篇博客主要写类、面向对象定义,三大特性:封装、继承、多态,也会简单的介绍魔法(后面将写一篇博文概述)。

面向对象

  目前面向对象还没有统一的定义,面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。简单一点来概述,面向对象就是使用对象进行程序设计。

(1)面向对象与面向过程的区别

  • 面向过程,是根据业务逻辑所需要的步骤,使用函数将这些步骤一步一步实现,使用的时候一个一个依次调用即可。
  • 面向对象,将业务逻辑抽象成多个对象,然而在对象中用属性和行为(方法)的定义来描述业务逻辑。

(2)面向对象和面向过程的优缺点

  • 面向过程

  优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。    
  缺点:没有面向对象易维护、易复用、易扩展

  • 面向对象

  优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护   
  缺点:性能比面向过程低

(3)面向对象最重要的两个基本概念

  类:类由属性(一些特征数据)和方法(行为)组成,拥有相同或者相近属性、行为的事物可以抽象成为一个类。类往往是抽象的、没有实体。  

  对象:根据所属模板创造出来的实实在在的事物。在程序中我将这个实实在在的事物称之为实例,我们为它的属性赋上特定的值。  

#定义类
class Student(object):
    #初始化属性值
    def __init__(self,name,stuId,age):
        self.name = name
        self.stuId = stuId
        self.age = age
    #print输出对象时被调用
    def __str__(self):
        introduce = "我是: " + self.name + ",学号: " + str(self.stuId)  + ",年龄: " + str(self.age) + ""
        return introduce

    def study(self):
        print("我会学习")
#创建对象
Ming = Student("小明",123545,18)
print(Ming)
Ming.study()

输出:
    我是: 小明,学号: 123545,年龄: 18岁
    我会学习
  

注:定义类对象时一定要传入一个参数self可以为其他字符,便于可读性约定俗成为self,self相当于Java、C++中的this。由于类方法与对象实例相关,Python语言在定义类方法时必须传入一个self,否则报错:study() takes 0 positional arguments but 1 was given。

封装

当我们要修改对象属性时,通常有两种方法:

  1. 对象名.属性名 =  数据  (直接修改)
  2. 对象名.方法名()    (间接修改)

由于直接修改的修改可能导致属性数据不合理,为了更好的保存属性安全性,即不可随意修改,我们有如下的处理方式:

  1. 定义私有属性。不像其他语言有private 、public等关键字修饰,Python直接用双下划线“__”表示私有属性,可以修饰属性和方法。
  2. 对外提供访问的接口。通常使用getXXX()、setXXX()实现,不过Python中还可以使用property属性来实现。
class Money(object):

    def __init__(self,money):
        self.__money = money
    
    def getMoney(self):
        return self.__money

    def setMoney(self,value):
        if isinstance(value,int): #内建函数判断输入类型
            self.__money = value
        else:
            print("error:不是整数,%s"%type(value))
    #通过property提供外部访问
    money = property(getMoney,setMoney)
ming = Money(100)
print("-1-",ming.getMoney())
ming.setMoney(200)
print("-2-",ming.getMoney())
print("="*30)
print("property获取属性值:money=%d"%ming.money)
ming.money = 555
print("property修改属性值:money=%d"%ming.money)

输出:
-1- 100
-2- 200
==============================
property获取属性值:money=200
property修改属性值:money=555

  启动python解释器,输入dir(__builtins__), 可以看到很多python解释器启动后默认加载的属性和函数,这些函数称之为内建函数, 这些函数因为在编程时使用较多,cpython解释器用c语言实现了这些函数,启动解释器时默认加载,可以直接调用。

继承

  Python语言支持多继承,在定义类时小括号()里面的即为父类名字,子类可以继承父类的属性、方法,但是私有属性、方法都是不对外公开的,所以不可被继承和访问。

class Animal(object):

    def __init__(self,name):
        self.name = name

    def eat(self):
        print("Animal----eat()")
    def run(self):
        print("Animal----不能飞,只能奔跑。。。")

class Cat(Animal):

   def eat(self):
        print("cat----重写父类----eat()")
   def sleep(self):
        print("cat----我的爱好是睡觉")

miao = Cat("哆啦A梦")
print("我是:%s"%miao.name)
miao.eat()
miao.run()
miao.sleep()

输出:
    我是:哆啦A梦
    cat----重写父类----eat()
    Animal----不能飞,只能奔跑。。。
    cat----我的爱好是睡觉

多态

  不同子对象调用相同的父类方法,在运行时产生不同的结果。多态以继承和重写父类方法为前提,增加了代码的灵活性,是调用方法的技巧,不会影响到类的内部设计。

class Dog(object):
    def __init__(self,name):
        self.name = name
    def game(self):
        print("%s 很开心的玩耍。。。"%self.name)

class XiaoTianQuan(Dog):
    def game(self):
        print("%s 飞到天上玩..."%self.name)

class Person(object):
    def __init__(self,name):
        self.name = name
    def gameWithDog(self,dog):
        print("%s 和 %s玩的停不下来"%(self.name,dog.name))
        dog.game()

xiaoHuaGou = Dog("小花狗")
Jack = Person("杰克")
Jack.gameWithDog(xiaoHuaGou)
xtq = XiaoTianQuan("哮天犬")
Jack.gameWithDog(xtq)

输出:
    杰克 和 小花狗玩的停不下来
    小花狗 很开心的玩耍。。。
    杰克 和 哮天犬玩的停不下来
    哮天犬 飞到天上玩...

类属性、实例属性

前面几个类在__init__中的属性就是实例属性,Python中所谓的类属性相当于java、C++中的类静态成员变量,即类属性就是类对象所拥有的属性,它被所有类对象的实例对象共有,在内存中只存在一个副本。对于公有类属性在类外可以通过类对象和实例对象访问,私有就无法访问了。

class Person(object):
    address = "上海"   #类属性

    def __init__(self,name,age):
        self.name = name #实例属性
        self.age = age
person = Person("华仔","18")
print("实例属性:",person.name,person.age)
print("类属性:",Person.address)
#下面报错:AttributeError: type object 'Person' has no attribute 'name'
#print(Person.name)  

print("通过实例对象修改类属性address:")
print("---修改前---")
print("类属性:",Person.address)
print("实例属性:",person.address)
person.address = "武汉"
print("---修改后---")
print("类属性:",Person.address)
print("实例属性:",person.address)  #实例属性会屏蔽同名类属性
del person.address     #删除实例对象属性
print("---实例属性:",person.address)

输出:
实例属性: 华仔 18
类属性: 上海
通过实例对象修改类属性address:
---修改前---
类属性: 上海
实例属性: 上海
---修改后---
类属性: 上海
实例属性: 武汉
---实例属性: 上海

  如果需要在类外去修改类属性,必须通过类对象引用去修改;如果使用实例对象引用去修改,实际上产生的是一个同名的实例属性,这种方式修改的是实例属性,并不会改变类属性的值(这一点可以类似理解为全局变量和局部变量)。之后如果通过实例对象去引用该名称的实例属性,实例属性将屏蔽类属性,即此时引用的是实例属性,除非删除这个实例属性。

类方法、静态方法

  • 类方法是类对象拥有的方法,需要用修饰器@classmethod标识的方法,对于类方法第一参数必须是类对象,一般使用cls作为第一个参数(可以用其他字符,约定俗成用cls),可以使用实例对象和类对象引用去访问。类方法有一个重要作用是可以修改类属性。
class People(object):
    city = "北京"

    @classmethod
    def getCity(cls):
        return cls.city

    @classmethod
    def setCity(cls,city):
        cls.city = city

people = People()
#可以通过实例对象引用类方法
print(people.getCity())
#通过类对象引用类方法
print(People.getCity())
#修改类属性
people.setCity("上海")
print(people.getCity())
print(People.getCity())

输出:
北京
北京
上海
上海

当类方法修改类属性之后,实例对象、类对象访问的类属性都将发生变化。

  • 静态方法,使用修饰器@staticmethod来修饰,静态方法没有必须参数;类方法第一参数必须是cls、通过cls引用的一定是类对象的属性和方法;实例方法第一参数是self,通过self引用的可能是类属性、也可能实例属性,当self引用出现类属性和实例属性名称一样时,实例属性高于类属性。静态方法如果要引用类属性,必须同过类对象来引用。
class People(object):
    country = "china"

    @staticmethod
    def getCountry():
        return People.country
print(People.getCountry())
people = People()
print(people.getCountry())

输出:
    china
    china

 

posted @ 2018-11-30 00:17  今生遇见前世  阅读(214)  评论(0编辑  收藏  举报