面向对象的思想就是把一切都看成对象,而对象一般由属性和方法组成。

属性:属性属于对象静态的一面,用来描述某个对象的具体特征。比如小志身高180M,体重70KG,这里身高、体重都是属性。 

方法:方法方法属于对象动态的一面,举一个例子,小明会跑,会说话,跑、说话这些行为就是对象的方法!所以为动态的一面, 

:具有同种属性的对象称为类,是个抽象的概念。

    比如“人类”就是一类,比如小明、小红、小玲等等这些人都是一个个的对象。类就相当于一个模具,他定义了它所包含的全体对象的公共特征和功能,对象就是类的一个实例化,小明就是人的一个实例化!我们在做程序的时候,经常要将一个变量实例化,就是这个原理!

类和实例

类和实例都是面向对象最重要的概念。

在python中定义一个类:

class 类名:
    pass

不同于定义方法,类名后面可以不带括号,如果定义方法的话,必须带括号,比如:

def 方法名():
    pass

定义一个类及实例化:

class People:
    pass

laowang = People()  # laowang是People的实例化

类的三大特性

类的三大特性分别是封装,继承,多态

封装

# 封装就是把我们不想让人看到的东西隐藏起来。
# 反应到代码中就是让类中的属性和方法不被外面的访问。
# 而隐藏的方式就是用双下划线开头的方式将属性隐藏起来。
# 类中所有双下划线开头的名称如"__x"都会在类定义时自动变形成:_类名__x的形式。
# 而这种变形只有在类定义阶段发生变形。
class A:
    __N = 0  # 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N

    def __init__(self):
        self.__x = 10  # 变形为self._A__X

    def __foo(self):  # 变形为_A__foo
        print("from A")

    def bar(self):
        self.__foo()  # 只有在类内部才可以通过__foo的形式访问


a = A()
a.bar()  # from A
print(A._A__N)  # 0
a._A__foo()  # from A
print(a.__dict__)  # {'_A__x': 10}
a.__foo()  # 报错,AttributeError: 'A' object has no attribute '__foo'


# 1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,
#   然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,
#   主要用来限制外部的直接访问。
# 2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形


# 封装的真谛在于明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终
# 归是要用,外部要想用类隐藏的属性,需要我们为其开辟接口,让外部能够间接地用到我们隐藏起来的属性,那这么
# 做的意义何在???
# 先给出一个简单但是经典的例子。
class Teacher:
    def __init__(self, name, age):
        # self.__name=name
        # self.__age=age
        self.set_info(name, age)

    def tell_info(self):
        print('姓名:%s,年龄:%s' % (self.__name, self.__age))

    def set_info(self, name, age):
        if not isinstance(name, str):
            raise TypeError('姓名必须是字符串类型')
        if not isinstance(age, int):
            raise TypeError('年龄必须是整型')
        self.__name = name
        self.__age = age


t = Teacher('老王', 18)
t.tell_info()

t.set_info('老李', 19)
t.tell_info()

# 1:封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上
#    对该数据操作的限制,以此完成对数据属性操作的严格控制。
# 2:封装方法:目的是隔离复杂度,在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称
#    为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。比如说取款是功能,这个功能有很多功
#    能组成:插卡、密码认证、输入金额、打印账单、取钱对使用者来说,只需要知道取款这个功能即可,其余功能我们
#    都可以隐藏起来,很明显这么做隔离了复杂度,同时也提升了安全性
# 3:python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果你非要不遵守,那也没法,只能来个最终的
#    办法。python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__,详见面向
#    对象进阶

# 封装的好处
# 封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接
# 口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只
# 要接口这个基础约定不变,则代码改变不足为虑。
# 例子:
# 类的设计者
class Room:
    def __init__(self, name, owner, width, length, high):
        self.name = name
        self.owner = owner
        self.__width = width
        self.__length = length
        self.__high = high

    def tell_area(self):  # 对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
        return self.__width * self.__length


# 使用者
r1 = Room('卧室', 'egon', 20, 20, 20)
print(r1.tell_area())  # 400, 使用者调用接口tell_area


# 类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
    def __init__(self, name, owner, width, length, high):
        self.name = name
        self.owner = owner
        self.__width = width
        self.__length = length
        self.__high = high

    def tell_area(self):  # 对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
        return self.__width * self.__length * self.__high


# 对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
r1 = Room('卧室', 'egon', 20, 20, 20)
print(r1.tell_area())  # 8000
封装

继承

继承同时具有两种含义

  1. 继承基类的方法,并且做出自己的改变或者拓展(常用于代码重用)
  2. 声明某个子类兼容于某基类,定义一个接口类,子类继承接口类。并实现接口中定义的方法。
# ------------------------继承由来及单继承和多继承----------------------------------------
# 例子说明继承的由来
# 猫:喵喵叫  吃 喝 睡
# 狗:汪汪叫  吃 喝 睡
# 可以看到猫和狗除了有自己特殊的能力,还有大量重复的部分,反应到代码中,这些就是重复的冗余代码。类的继承就是用来解决这个问题的。
# 我们可以把猫和狗的共有属性提取成一个动物类,
# 动物类:吃 喝 睡
# 猫和狗只要继承这个动物类,就可以拥有继承的基类中的所有类属性,然后再实现自己特殊的属性就可以了。这个时候动物类可以称为是父类,猫和狗可以称为子类。
# 一个类可以继承一个或者多个类,父类又可称为基类或者超类,子类又称为派生类。
# 在提取基类找出共性的时候,我们可以称之为是抽象,
# 例子:
class Animal:
    def eat(self):
        print("%s 吃 " % self.name)

    def drink(self):
        print("%s 喝 " % self.name)

    def shit(self):
        print("%s 睡 " % self.name)


class Cat(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = ''

    def cry(self):
        print('喵喵叫')


class Dog(Animal):
    def __init__(self, name):
        self.name = name
        self.breed = ''

    def cry(self):
        print('汪汪叫')


c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()


# -------------------------单继承与多继承-----------------------------------------
class p1:
    pass


class p2:
    pass


class p3(p1):
    pass


class p4(p1, p2):
    pass


print(p3.__bases__)  # (<class '__main__.p1'>,)
print((p4.__bases__))  # (<class '__main__.p1'>, <class '__main__.p2'>)


# 一例看继承
class Foo:
    def f1(self):
        print('Foo.f1')

    def f2(self):
        print('Foo.f2')
        self.f1()


class Bar(Foo):
    def f1(self):
        print('Bar.f1')


b = Bar()
b.f2()
# 调用一个实例化对象的方法,它会先到自己的所属类中找,找不到再到父类的。
# 也就是说,当子类定义了自己的属性且与父类重名时,调用的时候以自己为准,所以不要认为是子类覆盖了父类的类属性。

# -------------------------经典类和新式类-----------------------------------------
# 关于这个继承又要引出一个概念,就是经典类和新式类
# 1.只有在python2中才分新式类和经典类,python3中统一都是新式类
# 2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
# 3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
# 3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
# 4.object是所有python类的基类,它实现了一些常见方法(如之前说明的类内置的特殊属性等。
继承

 继承顺序:如果自己与继承有相同的属性,用自己的,如果没有则用继承的

多态

# 在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),
# 不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。
# 所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
# 比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
# 那么多态的好处是什么呢?
# 1.增加了程序的灵活性
#   以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
# 2.增加了程序的可拓展性
#   通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用  
# 多态的例子如下:
import abc


class Animal(metaclass=abc.ABCMeta):  # 同一类事物:动物
    @abc.abstractmethod
    def talk(self):
        pass


class People(Animal):  # 动物的形态之一:人
    def talk(self):
        print('say hello')


class Dog(Animal):  # 动物的形态之二:狗
    def talk(self):
        print('say wangwang')


class Pig(Animal):  # 动物的形态之三:猪
    def talk(self):
        print('say aoao')


def func(animal):
    animal.talk()


laowang = People()
wangcai = Dog()
peiqi = Pig()

func(laowang)  # say hello
func(wangcai)  # say wangwang
func(peiqi)  # say aoao

# 常见的使用:
# str,list,tuple都是序列类型
s = str('hello')
l = list([1, 2, 3])
t = tuple((4, 5, 6))

# 我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

print(len(s))
print(len(l))
print(len(t))
多态

 

posted on 2021-12-14 19:55  今晚不吃饭  阅读(28)  评论(0编辑  收藏  举报