03月21, 2019

简介

面向对象是我们经常能听到的术语,即class,类。事实上,主角是两个,一个是类,一个是类实例。人类,是一个类,我们每一个人是一个人类的实例。而类之间又有一些关系,例如,我们既是人类,也是动物,更细化来讲,我们是哺乳类动物,灵长类,类似于集合的概念,哺乳动物属于动物,而在面向对象中我们通常称哺乳动物是动物的子类。而对于动物这个类来说,会自带一些属性,例如:年龄、体重。也会有一些方法:生殖、呼吸。而不同种类的动物(即动物类的各种子类)可能会有不同的属性或方法,像胎生、卵生,像鸟类的飞行的方法和豹子奔跑的方法。

定义

用关键字class去定义一个类,如果没有指定父类,默认继承object类。

class Human(object):
    pass

这样,我们定义个了一个Human,人类。

类属性

class Human(object):
    taisheng = True

为什么要叫类属性呢,因为这个属性是和类绑定的,并不是和实例绑定的。胎生这个属性是全人类共有的,并不是某个人特殊拥有的属性。

实例属性

class Human(object):
    def __init__(self, name):
        self.name = name

human_a = Human("alan")

我们首先实例化了一个人类human_a,然后给这个人类设置了一个实例属性name,name这个属性独立于其他的人类,是和实例绑定的,所以叫实例属性。

  • 实例属性可以在实例创建后任意时间设置。
  • 一般放在构造函数里__init()__

    类方法

    class Human(object):

     def __init__(self, name):
         self.name = name
     def walk(self):
         print self.name + " is walking"
    

    human_a = Human("alan") human_a.walk() 运行结果:

    alan is walking

类的方法可以看做是一种类属性,而传入的第一个参数self,表示调用这个类方法的实例。像上面的例子,human_a调用了walk这个类方法,human_a的名字是alan,所以运行的结果就是alan is walking。

访问控制

从上面的例子来看,我们可以在外部随意更改name这个属性,如果不想让外部直接访问到,则在属性名字前加两个下划线__name,这样从外部就无法直接访问了。如果还是想访问,可以再加个get的接口。

class Human(object):
    def __init__(self, name):
        self.__name = name
    def walk(self):
        print self.name + " is walking"
    def get_name(self):
        return self.__name
human_a = Human("alan")
print human_a.get_name()
print human_a.__name

如果还是想更改__name字段,可以再加上一个set接口

class Human(object):
    def __init__(self, name):
        self.__name = name
    def walk(self):
        print self.name + " is walking"
    def get_name(self):
        return self.__name
    def set_name(self, name):
        self.__name = name
human_a = Human("alan")
print human_a.set_name("bob")

可能有人会有疑问,为何要这么“画蛇添足”呢?其不然,这样会增强代码的健壮性,直接暴露属性可能会带来意想不到的后果,通过接口的方式可以加以控制,例如,我们可以通过set接口去限定name的长度。

class Human(object):
    def __init__(self, name):
        self.__name = name
    def walk(self):
        print self.name + " is walking"
    def get_name(self):
        return self.__name
    def set_name(self, name):
        if len(name) <= 10:
            self.__name = name
human_a = Human("alan")
print human_a.set_name("bob")

这样就不会出现name过长的情况。

继承

最开始的简介里说到,哺乳动物是动物的一种,用面向对象的属于来说,哺乳动物是动物的子类,子类拥有父类的属性、方法,即继承。同时又可以拥有父类没有的属性和方法,即多态。 还是以人类为例,通常来说,人类又可以分为男人和女人(当然也有别的,23333)

class Man(Human):
    def __init__(self, name, has_wife):
        self.__name = name
        self.__has_wife = has_wife

来,我们看下这个男人,多了一个新的属性,__has_wife(是否已婚)。我们写到了Man的构造函数里。其实通常并不这么写构造函数,假如Human里有很多属性、很多初始化步骤,我们Man继承的时候难不成要复制粘贴一遍Human的构造函数?当然不是啦,通常会这么写。

class Man(Human):
    def __init__(self, name, has_wife):
        super(Man, self).__init__(name)
        self.__has_wife = has_wife

super(Man, self).__init__(name)等价于调用了父类Human的构造函数,就不用再复制粘贴一遍了。 既然有男人,那就再来个女人吧。

class Woman(Human):
    def __init__(self, name, has_husband):
        super(Woman, self).__init__(name)
        self.__has_husband = has_husband

我们都道,男人和女人是不一样的,通常男人都自带抽烟、喝酒、烫头,啊。。。并没有烫头。

 class Man(Human):
    def __init__(self, name, has_husband):
        super(Man, self).__init__(name)
        self.__has_husband = has_husband
    def smoke(self):
        print "A man maybe smoke"
    def drink(self):
        print "A man maybe drink"

当然,女人也自带逛街、化妆等天赋技能。

class Woman(Human):
    def __init__(self, name, has_husband):
        super(Woman, self).__init__(name)
        self.__has_husband = has_husband
    def shopping(self):
        print "A woman always go shopping"
    def make_up(self):
        print "A woman always make up"

好了,观众朋友们,有没有感觉到这种继承的优越性。可以很清晰地看到,男人和女人都有一些相同的属性,也有一些各自不同的方法。如果哪天人类有了别的方法、属性,直接在Human类更改,男人和女人也会自动继承。如果想再设计一个双性人这个类,那直接从Human继承就可以了,对男人和女人不会有任何影响。这就是面向对象的优越性啊!

本文链接:http://www.yuqiaochuang.com/post/类.html

-- EOF --

Comments

""