昨日内容回顾

绑定方法

# 绑定方法分几种:
    1. 绑定给对象的
    2. 绑定给类的

## 绑定给对象的

class Student():
    school = 'SH'
    name = 'egon'

    # 当调用类的时候自动触发的函数
    def __init__(self, name, age ,gender):     #self:谁来调就是谁
        self.name = name
        self.age = age
        self.gender = gender

    # 绑定给对象的方法, 对象来调用的时候,把对象自己当成第一个参数自动传递过来
    def func(self):
        # self 对象本身
        # self.__class__ 产生对象的类
        pass

stu = Student('egon', 18, 'male')
stu1 = Student('egon1', 18, 'male')
stu2 = Student('egon2', 18, 'male')
stu3 = Student('egon3', 18, 'male')

# 绑定给类的方法
class Student():
    school = 'SH'
    name = 'egon'

    # 当调用类的时候自动触发的函数
    def __init__(self, name, age ,gender):
        self.name = name
        self.age = age
        self.gender = gender

    # 绑定给类的方法, 类来调用的时候,把类自己当成第一个参数自动传递过来
    @classmethod #
    def func(cls):
        pass

 # 类来调用
Student.func()

非绑定方法

# 即不绑定给对象,也不绑定给类的方法
class Student():
    school = 'SH'
    name = 'egon'

    # 当调用类的时候自动触发的函数
    def __init__(self, name, age ,gender):
        self.name = name
        self.age = age
        self.gender = gender

    # 变成了静态方法,函数中不在有默认的参数, 对象和类都可以调用,但是都不会自动传递参数
    @staticmethod
    def func(name, age):
        pass
    @staticmethod
    def create_id()
        import uuid
        return uuid.uuid4()

    @staticmethod
    def make_code()
        import random

隐藏属性

# 隐藏属性的特点:
    1. 类定义阶段,会发生一次变形,  _类名__属性名
    2. 隐藏属性对外不对内
    3. 如果外部要想调用隐藏属性,在类内部开放可访问的接口, 目的是可以更好的限制外部调用者

# 如何隐藏属性?
class Student():
    __school = 'SH' # _Student__school
    name = 'egon'

    def __init__(self, name, age):
        self.__name = name  # self._Student__name
        self.age = age

    def __func(self) # def _Student__func(self)
        pass

    def get_name(self):
        return self.__school  # self._Student__school

    def set_name(self, v):
        if type(v) is not str:
            return
        self.__name = v

# 类的名称空间 {'name':'egon', '_Student__school':'SH','_Student__func':''}

 stu = Student()

stu.set_name('egon')

**隐藏属性特点**:
1. 在类定义阶段发生了变形: _类名__属性名(或者方法名)
2. 对内不对外,内部照样获取,外部拿不到

为什么要隐藏:
    对内部的属性或者方法做隐藏,可以更好的限制外部使用者, 要想让外部访问,在类内部定义对外可访问的接口。

property装饰器

# 把函数伪装成属性

class Student():
    school = 'SH'
    __name = 'egon'

    @property
    def name(self):
        # 一大堆的逻辑
        return self.__name

    @name.setter # 修改
    def name(self, v):
        self.__name = v

    @name.deleter
    def name(self):
        pass

stu = Student()
stu.get_name() #
# stu.get_name
# stu.name

stu.name = 'xx'

#####################第二种写法##################################
class Student():
    school = 'SH'
    __name = 'egon'

    def get_name(self):
        # 一大堆的逻辑
        return self.__name

    def set_name(self, v):
        self.__name = v

    def del_name(self):
        pass
    name = property(get_name,set_name,del_name)

stu = Student()
stu.get_name() #
# stu.get_name
# stu.name

stu.name = 'xx'

今日内容详细
  • 面向对象的三大特征

    封装

    继承

    多态

  • 继承的属性查找

    • 单继承下的属性查找
    • 多继承下的属性查找
  • super()和mro()

  • 多态与多态性

  • 组合

继承

# 1.什么是继承?
  继承就是新建类的一种方式,新建出来的类我们称为子类或者叫派生类,被继承的类称为父类或者基类
  # 子类可以遗传父类的属性

# 2. 为什么要用继承?
    类解决的是对象与对象之间的代码冗余问题
     继承解决类与类之间的代码冗余问题

# 3. 如何使用继承?
    新式类:继承了object类的子子孙孙类都是新式类
     经典类:不继承object类的子子孙孙类都是经典类

     # 新式类和经典类只在python2中区分
    在python3中都是新式类

"""
学会子类如何使用父类的属性
1. 指名道姓:People.__init__(self, name, age, gender)
2. super():
"""
class People():
    school = 'SH'

    def __init__(self, name, age, gender):
        # self => stu
        self.name = name
        self.age = age
        self.gender = gender

class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        self.courses = course
        # self => stu
        People.__init__(self, name, age, gender)  # 普通方法, 指名道姓的调用方法

    def choose_course(self, course):
        # stu_dic['course'].append(course)
        # stu_obj['course'].append(course)
        # stu_obj.courses.append(course)
        # self.courses.append(course)
        self.courses.append(course)
        print("%s选课成功%s" % (self.name, self.courses))

stu = Student('egon', 19, 'male')  # Student(stu, 'egon', 19, 'male')

单继承下的属性查找

# class Foo:
#     def f1(self):
#         print("Foo.f1")
#
#     def f2(self):
#         print("Foo.f2")
#         self.f1()  # self => obj
#
#
# class Bar(Foo):
#     def f1(self):
#         print("Bar.f1")
#
#
# obj = Bar()
# obj.f2()

class Foo:
    def __f1(self):  # def _Foo__f1()
        print("Foo.f1")

    def f2(self):
        print("Foo.f2")
        self.__f1()   # self._Foo__f1()

class Bar(Foo):
    def __f1(self):  # def _Bar__f1()
        print("Bar.f1")

obj = Bar()
obj.f2()

多继承下的属性查找

# 新式类中属性查找按照   广度优先查询
# 经典类中属性查找按照   深度优先查询

class G(object):
    def test(self):
        print('from G')

class F(G):
    def test(self):
        print('from F')

class C(F):
    def test(self):
        print('from C')

class D(G):
    def test(self):
        print('from D')

class E(G):
    def test(self):
        print('from E')

class B(E):
    def test(self):
        print('from B')


class A(B, C, D):
    def test(self):
        print('from A')


f1 = A()
f1.test()
f1 = A()
f1.test()

面向对象的三大特征_父类

当类是经典类时,多继承情况下,在要查询属性不存在时,会按照深度优先的方式查找下去

面向对象的三大特征_python_02

当类是新式类时,多继承情况下,在要查询属性不存在时,会按照广度优先的方式查找下去

super()和mro()

class A:
    def test(self):
        print('A---->test')
        super().aaa()

class B:
    def test(self):
        print('B---->test')

    def aaa(self):
        print('B---->aaa')

class C(A, B):
    def aaa(self):
        print('C----->aaa')

# c = C()
# c.test()  # 打印结果:
# print(C.__mro__)

a = A()
# a.test()
print(A.__mro__)
class People():
    school = 'SH'

    def __init__(self, name, age, gender):
        # self => stu
        self.name = name
        self.age = age
        self.gender = gender

class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        self.courses = course
        # self => stu
        # People.__init__(self, name, age, gender)  # 普通方法, 指名道姓的调用方法
        # super(Student, self).__init__(name, age, gender) # python2 super(Student, self) 返回的是一个特殊的对象
        super().__init__(name, age, gender) # python3 super(Student, self) 返回的是一个特殊的对象
        # 他遵从mro列表
    def choose_course(self, course):
        self.courses.append(course)
        print("%s选课成功%s" % (self.name, self.courses))

stu = Student('egon', 18, 'male')
print(stu.name)
print(stu.age)
print(stu.gender)

class Teacher(People):
    def __init__(self, name, age, gender, level):
        self.level = level
        People.__init__(self, name, age, gender)  # 普通方法, 指名道姓的调用方法

    def score(self, stu_obj, score):
        stu_obj.score = score
        print("%s给%s打了%s分" % (self.name, stu_obj.name, score))
class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B,C):
    pass

obj = D()
obj.test() # 结果为:from B

对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表,如下

>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类
所以obj.test()的查找顺序是,先从对象obj本身的属性里找方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test

ps:

1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

多态与多态性

# 多态:一种事物的多种形态
水:固态水,液态水, 气态水

动物:人,猪, 狗
# 继承, 子类使用父类的属性
多态类中的继承:不是让子类遗传父类的属性

多态带来的特性:在不考虑对象的数据类型的情况下,直接调用方法
import abc  # abstract  抽象类

# 抽象类只能被继承,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def speak(self): pass
    # def speak1(self):pass
    # def speak2(self):pass
    # def speak3(self):pass

# Animal()

# class People(Animal):
#     def speak1(self):
#         pass
#     pass
#
# class Pig(Animal):
#     def speak(self):
#         print("哼哼哼哼")
#     pass
#
#
# class Dog(Animal):
#     def speak(self):
#         print("汪汪汪")
#     pass

# obj1 = People()
# obj2 = Pig()
# obj3 = Dog()
#
# obj1.speak()
# obj2.speak()
# obj3.speak()

# 在python中不推荐上面的写法, 推荐的是下面的写法
class People():
    def speak(self):
        pass

class Pig():
    def speak(self):
        print("哼哼哼哼")

    pass

class Dog():
    def speak(self):
        print("汪汪汪")

    pass

class Txt():
    def speak(self):
        print("汪汪汪")

    pass

obj1 = People()
obj2 = Pig()
obj3 = Dog()
obj4 = Txt()

# obj1.speak()
# obj2.speak()
# obj3.speak()
# obj4.speak()
def animal(animal):
    return animal.speak()

animal(obj1)
animal(obj2)
animal(obj3)
animal(obj4)

print("abc".__len__())
print([1, 2, 3].__len__())
print({'username':"egon"}.__len__())

def len(item):
    return item.__len__()

len("abc")
len([1, 2, 3])

其他

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')

class C(A):
    def test(self):
        print('from C')

class D(B,C):
    pass

obj = D()
obj.test() # 结果为:from B

对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表
D.mro() 
# 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]