Python基础学习13--面向对象

面向对象

面向对象概述:

类和对象的概念:

  •   类 : 抽象名词,用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

  •   对象 : 具体的事物,通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

  •   类跟对象的关系:

    -> 一个是抽象,代表一大类事物------比如:人类,动物,花,等等。。

    ->一个是具象,代表了一类事物中具体的的某一个个体------比如:人类中的张三、李四、王五等。。

类的内容:

  •   表明事物的特征,称为属性(变量)

  •   表明事物功能或动作,称为成员方法(函数)

类的定义:

  •   必须使用class关键字------函数使用的是def

  •   class后面跟 类的名称

  •   类是由属性和方法构成

  •   成员的属性定义可以直接使用变量赋值,如果没有值,可使用None

类的命名:

  •   遵守变量命名规范:https://www.cnblogs.com/wilson-5133/p/9842843.html

  •   大驼峰:由一个或多个单词构成,每个单词的首字母大写,单词跟单词之间直接相连

  •   可以通过默认内置变量检查类和对象的所有成员

    1. 对象所有成员检查

      # dict前后各有两个下划线

      obj.__dict__

    2. 类所有成员检查

      class_name.__dict__

代码实例如下:

# 定以一个学生类,用来形容学生
# 定义一个空的类
class Student():
    # 一个空类,pass代表直接跳过
    # 此处pass必须有
    pass

# 实例化类
# 变量 = 类名()
Tom = Student()

# 在定义一个类,用来描述学习Python的学生
class PythonStudent():

    # 用None给不确定的值赋值
    name = None
    age = 18
    course = "Python"

    # 需要注意
    # 1. def doHomework的缩进层级
    # 2. 系统默认有一个self参数
    def doHomework(self):
        print("我在做作业")
        # 推荐在函数末尾使用return语句
        return None

# 实例化一个叫wilson的学生,是一个具体的人
wilson = PythonStudent()

# 访问对象成员
print('wilson.name:',wilson.name)
print('wilson.age :',wilson.age)

# 注意成员函数的调用没有传递进入参数
wilson.doHomework()

print('wilson.__dict__:',wilson.__dict__)
print('PythonStudent.__dict__:',PythonStudent.__dict__)

wilson.name = 'Null'
wilson.age = 16

print('wilson.__dict__:',wilson.__dict__)
print('PythonStudent.__dict__:',PythonStudent.__dict__)

输出结果如下:

wilson.name: None
wilson.age : 18
我在做作业

wilson.__dict__: {}
PythonStudent.__dict__: {'__module__': '__main__', 'name': None, 'age': 18, 'course': 'Python', 'doHomework': <function PythonStudent.doHomework at 0x02B114F8>, '__dict__': <attribute '__dict__' of 'PythonStudent' objects>, '__weakref__': <attribute '__weakref__' of 'PythonStudent' objects>, '__doc__': None}

wilson.__dict__: {'name': 'Null', 'age': 16}
PythonStudent.__dict__: {'__module__': '__main__', 'name': None, 'age': 18, 'course': 'Python', 'doHomework': <function PythonStudent.doHomework at 0x02B114F8>, '__dict__': <attribute '__dict__' of 'PythonStudent' objects>, '__weakref__': <attribute '__weakref__' of 'PythonStudent' objects>, '__doc__': None}

关于self

  •   self在对象的方法中表示当前对象本身,如果通过对象调用一个方法,那么该对象会自动传入到当前方法 的第一个参数中

  •   self并不是关键字,只是一个用于接收对象的普通参数,理论上可以用任何一个普通变量名代替

  •    方法中有self形参的方法称为非绑定类的方法,可以通过对象访问, 没有self的是绑定类的方法, 只能通过类访问

  •    使用类访问绑定类的方法时, 如果类方法中需要访问当前类的成员,可以通过 __class__成员名来访问

代码实例如下: 

class Teacher():
    name = "Jack"
    age = 33

    def Math(self):
        self.name = "Tony"
        self.age = 31
        print("My name is {0}".format(self.name))

        # 调用类的成员变量需要用 __class__
        print("My age is {0}".format(__class__.age))

    def English():
        print(__class__.name)
        print(__class__.age)
        print("Are u ok?")

t = Teacher()
t.Math()

# 调用绑定类函数使用类名
Teacher.English()

输出结果如下: 

My name is Tony
My age is 33

Jack
33
Are u ok?

 面向对象的三大特性

  •   封装
  •   集成
  •   多态

封装

  封装就是对对象的成员进行访问限制

  封装的的3个级别:

    1. 公开、公共:Public
      • 公共的封装实际对成员没有任何操作,任何地方都可以访问
    2. 受保护的:Protected
      • 受保护的封装是将对象成员进行一定级别的封装,在类实例或者子类实例都可以进行访问,但是外部不可以访问
      • 封装方法:在成员前加1个下划线即可
    3. 私有的:Private
      • 私有成员是最高级别的封装,只能在当前类或对象中访问,在类的外部无法直接进行访问,包括子类
      • 在成员前面添加2个下划线即可

代码实例如下:

class Person():
    # name是共有的成员
    name = "Chinese"
    # sex是受保护的
    _sex = 'male'
    # __age就是私有变量
    __age = 18

    def Old(self):
        print('{} years old'.format(self.__age))

p = Person()
# name是公有变量
print('p.name:',p.name)

# sex是受保护的,可以在实例中调用
print('p._sex:',p._sex)

# 当前类或对象中可访问
p.Old()

# __age是私有变量,只能在当前的类或对象中访问,实例不能访问私有变量
print(p.__age)

输出结果如下:

p.name: Chinese

p._sex: male

18 years old    # 只能通过当前类或对象访问

AttributeError: 'Person' object has no attribute '__language'    # 不能直接访问私有变量

继承

  继承就是一个类可以获得另外一个类中的成员属性和成员方法

  作用:减少代码,增加代码的复用功能,同时可以设置类与类直接的关系

 

   继承与被继承的关系

    • 被继承的类称为父类,也叫基类、超类
    • 用于继承的类,称为子类,也叫派上类
    • 继承与被继承一定存在一个 is-a 的关系 

  继承的特征:

    • 所有的类都继承自object类,即所有的类都是object类的子类
    • 子类一旦继承父类,则可以使用父类中除私有成员外所有的内容
    • 子类继承父类后并没有将父类成员完全赋值到子类中,而是通过引用关系访问调用
    • 子类可以定义独有的成员属性和方法
    • 子类中定义的成员如果和父类的成员相同,则优先使用子类成员
    • 子类如果想扩充父类的方法,可以在定义新方法的同时访问父类成员来进行代码重用,可以使用 [父类名.父类成员] 的格式来调用父类成员,也可以使用 super().父类成员 的格式调用

代码实例如下:

# 子类和父类定义同一个变量名称,则优先使用子类本身
# 人有工作的函数, 老师也有工作的函数,但老师的工作需要讲课
class Person():
    name = "NoName"
    age = 18
    __score = 0  # 考试成绩是秘密,只要自己知道
    _petname = "sec"  # 小名,是保护的,子类可以用,但不能公用

    def sleep(self):
        print("Sleeping ... ...")

    def work(self):
        print("show me the money")

# 父类写在括号内
class Teacher(Person):
    teacher_id = "9527"
    name = "Tony"

    def teach(self):
        print("Lecture to students")

    def work(self):
        # 扩充父类的功能只需要调用父类相应的函数
        # Person.work(self)
        # 扩充父类的另一种方法
        # super代表得到父类
        super().work()
        self.teach()

t = Teacher()
# 子类和父类定义同一个变量名称,则优先使用子类本身
print('t.name:',t.name)
# 扩充后,会调用父类和子类的方法
t.work()

输出结果如下:

t.name: Tony

# t.work()
show me the money     # 继承自父类Person的work()
Lecture to students    # 子类Teacher扩充的work()

  

  继承变量函数的查找顺序问题:

    • 优先查找自身的变量
    • 如果没有,则查找父类
    • 构造函数如果子类中没有定义,则自动调用父类的构造函数
    • 如果子类有定义,则不向上查找

   构造函数

    • 是一类特殊的函数,在类进行实例化之前进行调用
    • 如果定义了构造函数,则实例化的时候使用自身的构造函数,不会查找父类的构造函数
    • 如果没有定义,会自动查找父类的构造函数
    • 如果子类没有定义,父类的构造函数带参数,则构造对象时的参数应该按照父类参数传参

代码实例如下:

# 例1:实例会直接调用构造函数
class Animal:
    pass

class Reptiles(Animal):     # Reptiles:爬行动物
    # __init__就是构造函数/构造方法
    # 每次实例化的时候,第一个被自动调用
    def __init__(self):
        print('这是Reptiles-Animal的子类')
# 实例化的时候,自动调用Reptiles的构造函数
R1 = Reptiles()

# 例2:如果子类中存在构造函数,则不会再向上查找
class Tortoise(Reptiles):   # Tortoise:乌龟
    def __init__(self,name):
        print('这是Tortoise-Reptiles的子类:{}'.format(name))
# 实例化的时候,自动调用Tortoise的构造函数
T1 = Tortoise('turtle')

class Snake(Reptiles):
    pass
# 实例化的时候,如果子类没有构造函数,所以会向上查找,即其父类-Reptiles
S1 = Snake()

class Terrapin(Tortoise):   # Terrapin:水龟
    pass

# 此时,由于Terrapin没有构造函数,则向上查找
# 因为Tortoise的构造函数需要2个参数,实例化的时候给了1个,报错
T2 = Terrapin()

输出结果如下:

# 实例化的时候,自动调用Reptiles的构造函数
# R1 = Reptiles()
这是Reptiles-Animal的子类

# 实例化的时候,自动调用Tortoise的构造函数
# T1 = Tortoise('turtle')
这是Tortoise-Reptiles的子类:turtle

# 实例化的时候,如果子类没有构造函数,所以会向上查找,即其父类-Reptiles
# S1 = Snake()
这是Reptiles-Animal的子类

# 子类没有构造函数,父类的构造函数需要2个参数,如果只传1个,会报错!
TypeError: __init__() missing 1 required positional argument: 'name'

 

  单继承和多继承

    • 单继承:每个类只能继承一个类
    • 多继承:每个类允许继承多个类

  单继承和多继承的优缺点

    • 单继承:
      • 优点:传承有序,逻辑清晰,语法简单,隐患少
      • 缺点:功能不饿能无限扩展,只能在当前唯一的继承链中扩展
    • 多继承:
      • 优点:类的功能扩展方便
      • 缺点:继承关系混乱

代码实例如下:

# 子类可以直接拥有父类的属性和方法,私有属性和方法除外
class Fish():
    def __init__(self, name):
        self.name = name

    def swim(self):
        print("我会游泳...")

class Bird():
    def __init__(self, name):
        self.name = name

    def fly(self):
        print("我会飞...")

class Person():
    def __init__(self, name):
        self.name = name

    def work(self):
        print("Show me the money...")

# 单继承的例子
class Student(Person):
    def __init__(self, name):
        self.name = name

stu = Student("stu")
print(stu.name)
stu.work()

# 多继承的例子
class SuperMan(Person, Bird, Fish):     # 继承3个父类:Person, Bird, Fish
    def __init__(self, name):
        self.name = name

class SwimMan(Person, Fish):            # 继承2个父类:Person, Fish
    def __init__(self, name):
        self.name = name

Kent = SuperMan("Clark")

print(Kent.name)
Kent.fly()
Kent.swim()
Kent.work()

输出结果如下:

# stu继承自Person
stu
Show me the money...

# Clark继承自Person, Bird, Fish
Clark
我会飞...
我会游泳...
Show me the money...

 

多态

  • 多态就是同一个对象在不同情况下有不同的状态出现

  • 多态不是语法,而是一种设计思想

  • 多态性:一种调用方式,不同的执行效果

  • 多态:同一事物的多种形态,如:动物分为人类,鸟类,爬行类,鱼类......

  • 多态和多态性

  • Mixin设计模式:Mix-in  混入的意思

    • 主要采用多继承方式对类的功能进行扩展
    • Mixin的概念
    • Mixin模式
    • 从某种程度上来说,继承强调 I am,Mixin 强调 I can
  • 使用Mixin实现多继承的时候非常小心

    • 首先它必须表示某一单一功能,而不是某个物品
    • 指责必须单一,如果由多个功能,则写多个Mixin
    • Mixin不能依赖于子类的实现
    • 子类即使没有继承这个Mixin类,也能照样工作,只是缺少了某个功能
  • 优点

    • 使用Mixin可以在不对类进行任何修改的情况下,扩充功能
    • 可以方便地组织和维护不同功能组件的划分
    • 可以根据需要任意调整功能类的组合
    • 可以避免创建很多新的类,导致类的继承混乱

代码实例如下:

class Vehicle(object):      # Vehicle:交通工具
    pass

class PlaneMixin(object): 
    def fly(self):
        print('I am flying')

# 多继承,父类为:Vehicle, PlaneMixin
class Airplane(Vehicle, PlaneMixin):
    pass

# 第二个父类为 PlaneMixin 而非 Plane
# 不影响功能,但会告诉读代码的人,Airplane 只是 Vehicle,不是 Plane
# 换言之,Airplane 属于 Vehicle类,但是他又具备 Plane 的 fly 功能
# Mixin,表示混入(mix-in),它告诉别人,这个类(PlaneMixin)是作为功能添加到子类中,而不是作为父类

类的相关函数

1、issubclass(A, B)

    判断 A 类是否是 B 类的子类

class A():
    pass

class B(A):
    pass

class C():
    pass

print(issubclass(B, A))         # 判断 B 是否为 A 的子类
print(issubclass(C, A))         # 判断 C 是否为 A 的子类
print(issubclass(B, object))    # 判断 B 是否为 object 的子类
# B 是 A 的子类,所以为 True
True

# C 不是 A 的子类,所以为 False
False

# 所有类都是 object 的子类,所以为True
True

2、isinstance(obj, A)

    判断 obj 对象是否是 A 类的实例对象

class A():
    pass

a = A()

print(isinstance(a, A))     # 判断 a 是否是 A 的实例对象
print(isinstance(A, A))     # 判断 A 是否是 A 的实例对象
# a 是 A 的实例对象,所以为True
True

# A 不是 A 的实例对象,所以为False
False

3、hasattr(obj, name)

    判断 obj 对象是否存在成员 name

class A():
    name = "NoName"

a = A()
print(hasattr(a, "name"))       # 判断 实例对象 a 中是否包含 name 属性
print(hasattr(a, "age"))        # 判断 实例对象 a 中是否包含 age 属性
# 判断 实例对象 a 中包含 name 属性
True

# 判断 实例对象 a 中不包含 age 属性
False

4、getattr(object, name[, default])

    返回一个对象属性值

class A(object):
    bar = 1

a = A()

print(getattr(a, 'bar'))        # 属性 bar 存在,则获取属性 bar 值

print(getattr(a, 'bar2', 3))    # 属性 bar2 不存在,但设置了默认值 3 ,会返回 3

print(getattr(a, 'bar2'))       # 属性 bar2 不存在,会触发异常报错
# 属性 bar 存在,则获取属性 bar 值 1
1

# 属性 bar2 不存在,但设置了默认值 3 ,会返回 3
3

# 属性 bar2 不存在,又没有设置默认值,会触发异常报错
AttributeError: 'A' object has no attribute 'bar2'

5、setattr(object, name, value)

    用于设置属性值,该属性不一定是存在的

class A(object):
    bar = 1

a = A()

# 属性 bar 存在
print(getattr(a, 'bar'))        # 获取属性 bar 值

setattr(a, 'bar', 5)            # 设置属性 bar 值为 5
print(a.bar)                    # 查看设置后 bar 的值

# 属性 obj 不存在
setattr(a, "name", 'wilson')    # 如果属性不存在,会创建一个新的属性,并对属性赋值
print(a.name)                   # 查看 name 属性的值
# 使用 getattr 查看 bar 的属性值
1

# 使用 setattr 更改 bar 的属性值后,再次查看
5

# 使用 setattr 创建新的属性并赋值后,查看
wilson

6、delattr(object, name)

    用于删除属性

class A(object):
    bar = 1

a = A()

# 查看属性值
print(a.bar)

delattr(A, 'bar')       # 通过 delattr 删除 A 类中的 bar 属性

print(a.bar)
# 执行delattr(A, 'bar')操作前,查看 a.bar 的值
1

# 执行delattr(A, 'bar')操作后,查看 a.bar 的值
AttributeError: 'A' object has no attribute 'bar'

 

推荐歌曲:生僻字(计算机版)(Cover:陈柯宇)

posted @ 2019-04-10 16:17  落晨  阅读(258)  评论(0编辑  收藏  举报