【Python】面向对象编程

2018-6-6

面向对象编程——Object Oriented Programming,简称OOP。
程序的基本单元:对象
对象:包含了数据和操作数据的函数
在Python中,万物皆为对象。(程序员后宫佳丽三千哟)
所有的数据类型都可视为对象,
对象也可以是自己创造的。
自己创造—自定义的对象数据类型就是类(class)。

Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student。
面向对象的设计思想是抽象出Class,根据Class创建Instance。


类和实例

class Student(object):
    pass

class后面跟的是类名——Student,注意,类名通常是大写开头的单词。
后面的(object),表示这个类是从哪个类继承下来的。如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。【想想树枝】
类定义以后就可以创建其实例:

bart = Student()

变量bart指向的就是一个Student的实例。

可以给实例变量bart绑定一个属性name

bart.name = 'Bart Simpson'

啊,类就像女娲捏泥人儿的模子,女娲捏人儿(创建实例)的时候,就得把一些个她认为必须绑定的属性强制填写进去。那她就用了__init__方法:

class Student(object):

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

应当注意,
注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。


数据封装
一个实例本身是拥有一些属性的数据的,可以通过函数来访问。
但是可以通过Student类的内部定义访问数据的函数,这样子,就相当于把数据给装到黑匣子了嘛~并且这些封装数据的函数是和Student类是关联的,人们给了它一个名字——类的方法。这是数据封装的第一个好处。

class Student(object):

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

    def print_score(self):
        print('%s: %s' % (self.name, self.score))

数据封装的第二个好处是:
可以给Student类增加新的方法,比如get_grade

class Student(object):
    ...

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

2018-6-7
访问限制
在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

    def print_score(self):
        print('%s: %s' % (self.__name, self.__score))

啊,这样的话连访问都不可以了,如果需要访问的话需要给Student类增加get_nameget_score这样的方法。

class Student(object):
    ...

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

这时候脑子抽了又想允许外部代码修改score了(事儿多得很),这时候可以增加set_score方法。

class Student(object):
    ...

    def set_score(self, score):
        self.__score = score

继承和多态
在OOP中,我们可以通过一个现有的class继承来定义一个class,这个新的class就称为子类——subclass,现有的被继承的class称为基类、父类或者超类——Base class、Super class。

class Animal(object):
    def run(self):
        print('Animal is running...')

class Dog(Animal):
    pass

class Cat(Animal):
    pass

上面的例子中,Animal是父类,DogCat就是子类。
这样做的目的是,子类拥有了父类全部的功能——在本例中实现了run()方法。


2018-6-9
北京,雨
多态的好处:
对于一个变量,我们只需要知道它是什么父类型,而无需知道它的子类型,就可以使用其方法——调用方只需要调用,而不需要知道细节。在增加一种子类时,只需要保证方法正确,不用管原来的代码是如何调用的。也就是“开闭原则”:

对扩展开放:允许新增Animal子类;
对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

从具体理解上看,继承就像是树一样:

这里写图片描述

静态语言 vs 动态语言

对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

class Timer(object):
    def run(self):
        print('Start...')

获取对象信息
type()
判断对象是哪种基本数据类型,还是函数

>>> type(123)==int
True

>>> import types
>>> def fn():
...     pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True

isinstance()
原文称:对于class的继承关系来说,使用type()不方便。
为什么呢?
Python type() 函数中谈及isinstance()type()区别:

  • type() 不会认为子类是一种父类类型,不考虑继承关系。
  • isinstance() 会认为子类是一种父类类型,考虑继承关系。
    如果要判断两个类型是否相同推荐使用 isinstance()。

dir()
可以获取一个对象的所有属性和方法。

>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

配合getattr()setattr()以及hasattr(),可以直接操作一个对象的状态。
getattr():用于返回一个对象的属性值——getattr(object, name[, default])
setattr():用于设置属性值,该属性必须存在——setattr(object, name, value)
hasattr():用于判断对象是否包含对应的属性——hasattr(object, name)


实例属性和类属性

实例属性属于各个实例所有,互不干扰;
类属性属于类所有,所有实例共享一个属性;
不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。

为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加:

class Student(object):
    count = 0
    def __init__(self, name):
        self.name = name
        Student.count += 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值