第七章 再谈抽象(类、对象)

本章讲的比较好的是廖雪峰的博客 [面向对象编程] (https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431864715651c99511036d884cf1b399e65ae0d27f7e000)
对象(类)包括属性和方法,属性即对象的特征,而方法是对象的行为或者动作,但方法和属性并不是一个完整的对象,这些定义为类(class),需要使用类来创建一个真正的对象,这个对象就叫作这个类的一个实例(Instance), 也叫实例对象(Instance Objects)。

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这种数据类型应该被视为一个对象,这个对象拥有name和score这两个属性(Property).如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象,然后,给对象发一个print_score消息,让对象自己把自己的数据打印出来。`
给对象发消息实际上就是调用对象对应的关联函数,即对象的方法

bart=Student(‘Bart Simpson’, 59)
lisa=Student(‘Lisa Simpson’, 87)
bart.print_score()
lisa.print_score()

**1. 对象创建过程详解**

` class Student(object):
        pass`
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,如果没有继承类,就使用object类。  
定义好Student类,就可以根据Student类创建Student的实例,创建实例是通过类名加()实现:

bart=Student()
bart-> <main.Student object at 0x10a67a590>
Student-> <class’main.Student’>

可见,变量bart指向的就是Student的实例,后面的0x10a67a59是内存地址,每个object的地址都不一样,而Student本身则是一个类。  
可以自由地给一个实例变量绑定属性,比如,给实例bart绑定一个name属性:  

bart.name=‘Bart Simpson’
bart.name->‘Bart Simpson’

由于类可以起到模板的作用,因此,可以创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name, score等属性绑上去:

class Student(object):
def init(self, name, score):
self.name=name
self.score=score
#特殊方法"init"前后分别有两个下划线!!

`__init__`方法的第一个参数永远是self,表示创建的实例本身,因此,在`__init__`方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。  
有了`__init__`方法,在创建实例的时候,就不能传入空的参数,必须传入与`__init__`方法匹配 的参数,但self不需要传,Python解释器自己会把实例变量传进去:     

bart=Student(‘Bart Simpson’, 59)
bart.name->‘Bart Simpson’
bart.score-> 59
#与普通函数相比,在类中定义的函数主要不同就是第一个参数永远是实例变量self,并且,调用时不用传递该参数。

2. 数据封装  
面向对象编程的一个重要的特点就是数据封装。如上面Student类中,每个实例就拥有了各自的name和score这些数据,我们除了可以通过函数访问这些数据,还可以再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’

3. 访问限制   
如果要让内部的属性不让外部访问,可在属性名称前加两个下划线___,即在实例变量中,如果以两个下划线开头,表示其变为一个私有变量,只有内部可以访问,外部不能访问:  

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))

#此时如果再外部环境之间输入bart.__name()显示报错,没有权限访问。如果又要使得外部可以访问私有变量,则可以增加get_name和get_score方法:  

class Student(object):

def get_name(self):
return self.__name

def get_score(self):
    return self._score
值得注意的是:在Python中,变量名类似__xxx__的,即以双下划线开头和结尾的,这些是特殊变量,是可以直接访问的,并不是private变量。  
4. 继承   
当定义一个class时,可以从某个现有的class继承,新的class称为子类(subclass),而被继承的class称为基类、父类或超类。  

class Animal (object):
def run(self):
print(‘Animal is running’)
当我们需要编写dog和cat类时,就可以直接从Animal类继承
class Dog (Animal):
pass

class Cat(Animal):
pass

继承可以使子类获得父类的全部功能。   
dog=Dog( )
dog.run( )->Animal is running      
但继承的子类也可以自己添加其他方法,如Dog类:   

class Dog (Animal):
def run(self):
print(‘Dog is running…’)

def eat(self):
    print('Eating meat...')
此外,Python还支持多重继承,即可同时继承多个父类的属性和方法:   
语法: class类名(父类1, 父类2, 父类3,...)

class Base1:
def foo1(self):
print(‘我是foo1,我在Base1中…’)
clase Base2:
def foo2(self):
print(‘我是foo2,我在Base2中…’)
class C(Base1, Base2):
pass

4. 多态 :当子类和父类都存在相同的run( )方法时,我们说,子类的run( )覆盖了父类的run( ),在代码运行的时候,总会调用子类的run().这样我们就获得了继承的另一个好处:多态。    
isinstance( )可以判断一个变量是否是某个类型 ,返回值为布尔值。  isinstance(a, list) ->True  
类型可以随着多次继承而传递,就如家系图谱一样   

`多态的好处就是,当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了,因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思:
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:`

5. 获取对象信息  
6. 组合机制:当使用继承不能解决的问题,可以考虑用组合更为方便:  

class Turtle:
def init(self, x):
self.num=x
class Fish:
def init(self, y):
self.num=y
class Pool:
def init(self, x, y):
self.turtle=Turtle(x)
self.fish=Fish(y)
def print_num(self):
print(‘水池里总共有乌龟%d只,小鱼%d条!’ %(self.turtle.num, self.fish.num))




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值