Python面向对象与类

一、面向对象概念


  1. 面向对象是一种主流的编程思想,基本单元:对象,把数据和对象封装起来,实现很好的复用性、灵活性、扩展性;

  2. 面向对象是一种抽象,抽象是指用分类的眼光看待事物的方法,需要对事物进行总结,分析共性,利用抽象能够简化解决问题的难度;

  3. 基本概念
    类:定义事物的抽象特点
    对象:类的一个实例

  4. 基本要素:
    属性:类的信息
    方法:类的功能

  5. 类的特性

  • 封装:类可以实现很多的功能,对外调用时,不需要知道具体是怎么实现的;

  • 继承:定义一个新类时,不必从头编写,可以从现有的类中继承,获得现有类的所有功能,新类只需要编写现有类缺少的功能;

  • 多态:继承于同一个父类的不同之子类,父类的方法,各个子类都有,但调用时的结果却不相同;

  • 类对象创建后,类命名空间中所有的命名都是有效属性名。

二、定义类


  1. 语法:class Class_name(object):

  2. __init__:定义类时,为类设置必要的属性,即初始化实例

  3. 示例

class Student(object):
    def __init__(self, name, sex, grade):
        self.name = name,
        self.sex = sex,
        self.grade = grade

if __name__ == '__main__':
    student = Student('larry', 'male', 5)        # 创建实例
    print('student of class:\n', student)        # 查看student类
    print('----------------------------')
    print('type of student:\n', type(student))      # 查看student的类型
    print('----------------------------')
    print('attribute of student:\n', dir(student))      # 查看student的属性

student of class:
 <__main__.Student object at 0x1063207b8>
----------------------------
type of student:
 
----------------------------
attribute of student:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', '__weakref__', 'grade', 'name', 'sex']


三、定义类的属性


  1. 方法
  • 直接在类中定义:被类的所有对象(方法)共享,其属性值都是一样的;
  • 通过构造函数:def __init__(self, [, ....]),其属性值依赖于传入的值;
  1. 访问控制
  • 实际上,Python中并没有访问控制,Python没有提供私有属性的功能;

  • 通过属性命名规范可以实现访问控制,不希望被外部访问的属性,在属性名前添加双下划线(__)即可。在实际工作中,这些命名规范全靠自觉;

  • 单下划线开头的属性,可以在子类中使用;双下划线开头的属性,不能被外部调用,也不能在子类中使用,即继承时这些私有属性和方法不会被覆盖。

  1. 示例
class Person(object):
    hobby = 'Play Computer'     # 直接在类中定义属性hobby

    def __init__(self, name, sex, age):     # 构造函数中定义初始化属性
        self.name = name,
        self._sex = sex,
        self.__age = age

    def get_age(self):
        return self.__age


if __name__ == '__main__':
    person = Person('larry', 'female', '28')        # 创建实例
    print('attribute of person:\n', dir(person))    # 查看类的属性
    print(person.__dict__)      # 查看构造函数中定义的属性
    print(person.get_age())     # 调用获取age属性的方法
    print(person._Person__age)  # 变相获取双下划线开头的age属性

attribute of person:
 ['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', 
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__',
 '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', 
'__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
'_sex', 'get_age', 'hobby', 'name']
{'name': ('larry',), '_sex': ('female',), '_Person__age': '28'}
28
28


四、定义类的方法


  1. 概念
  • 函数是直接使用函数名进行调用;

  • 方法是类的一部分,必须和对象结合在一起使用,使用类名进行调用,而不是某个对象;

  • 方法的访问限制,和属性一样,没有严格的语法控制,只是遵循一些规范;

  • 类中定义的方法,都是实例方法,可以看作是类的一个属性,第一个参数永远是self,表示创建的实例本身,

  • @classmethod:装饰的方法是类方法,类方法的第一个参数将传入类本身,通常将参数名命名为cls;

  • @property:装饰的方法,调用时,像访问属性一样(不需要带括号)。

  1. 示例
class Person(object):
    hobby = 'Play Cumputer'     # 直接在类中定义属性hobby

    def __init__(self, name, sex, age):     # 构造函数中定义初始化属性
        self.name = name,
        self._sex = sex,
        self.__age = age

    @classmethod
    def get_hobby(cls):
        return cls.hobby

    @property 
    def get_age(self):
        return self.__age 

    def self_introduction(self):
        print(f"My name is {self.name[0]}\nI am {self.__age} years old")

if __name__ == '__main__':
    person = Person('larry', 'male', 28)
    print(dir(person))
    print(Person.get_hobby())
    print(person.get_age)
    person.self_introduction()

['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
 '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_sex', 
'get_age', 'get_hobby', 'hobby', 'name', 'self_introduction']
Play Cumputer
28
My name is larry
I am 28 years old


五、类的继承


  1. 概念
  • 继承的子类:会继承父类的属性和方法,也可以自己定义,覆盖父类的属性和方法;
  • 使用supper()调用父类的方法,或者直接使用父类的名称调用;
  • isinstance():可以判断一个实例是否是指定的类;
  • issubclass():判断一个类是否是子类;
  • 类继承机制允许多重继承,派生类可以覆盖(override)基类中的任何方法或类,可以使用相同的方法名称调用基类的方法。
  1. 示例
# 类的继承

class Person(object):
    hobby = 'Play Cumputer'     # 直接在类中定义属性hobby

    def __init__(self, name, sex, age):     # 构造函数中定义初始化属性
        self.name = name,
        self._sex = sex,
        self.__age = age

    @classmethod
    def get_hobby(cls):
        return cls.hobby

    @property 
    def get_age(self):
        return self.__age 

    def self_introduction(self):
        print(f"My name is {self.name[0]}\n I am {self.__age} years old")

class Student(Person):
    def __init__(self, name, sex, age, weight):
        super(Student, self).__init__(name, sex, age)
        self.weight = weight


if __name__ == '__main__':
    student = Student('larry', 'male', 28, 62)
    print(type(student))
    print(dir(student))
    print(student.__dict__)
    print(isinstance(student, Student))     # 实例student,是否是指定的类Student
    print(issubclass(Student, Person))      # 类Student,是否是类Person的子类


['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', 
'__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', 
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', 
'__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_sex', 
'get_age', 'get_hobby', 'hobby', 'name', 'self_introduction', 'weight']
{'name': ('larry',), '_sex': ('male',), '_Person__age': 28, 'weight': 62}
True
True


六、多态


  1. 概念
  • 有了继承,才有了多态,在调用类实例方法时,尽量把变量当作父类,以便所有子类类型都可以正常接收;
  • 多态:继承于同一个父类的不同之子类,父类的方法,各个子类都有,但调用时的结果却不相同。
  1. 示例
# 类的多态

class Person(object):
    hobby = 'Play Cumputer'     # 直接在类中定义属性hobby

    def __init__(self, name, sex, age):     # 构造函数中定义初始化属性
        self.name = name,
        self._sex = sex,
        self.__age = age

    @classmethod
    def get_hobby(cls):
        return cls.hobby

    @property 
    def get_age(self):
        return self.__age 

    def self_introduction(self):
        return f"My name is {self.name[0]}\nI am {self.__age} years old"

class Student(Person):
    def __init__(self, name, sex, age, weight):
        super(Student, self).__init__(name, sex, age)
        self.weight = weight

    def self_introduction(self):
        return f"My name is {self.name[0]}\n My weight is {self.weight}"

def introduce(class_name):
    if isinstance(class_name, Person):
        return class_name.self_introduction() 


if __name__ == '__main__':
    person = Person('larry', 'male', 28)
    student = Student('larry', 'male', 28, 62)
    print(introduce(person))
    print(introduce(student))

My name is larry
I am 28 years old

My name is larry
My weight is 62


七、类的魔术方法

  1. 概念
  • 绝大多数的Python内置函数,都有对应的魔术方法,可以在类中使用;
  • 魔术方法,可以更方便自由地进行定制类,包括:对象建立、属性访问、运算符的支持、特殊语法等;
  • 面向对象中,名称前后各有2个下划线(__)的方法,都是魔术方法,是定义在类中的,不需要直接调用;
  • 类中常用的魔术方法
魔术方法 含义
__init__() 构造函数,创建实例的时候被调用
__str__() 返回适合人看的字符,print()调用的就是该方法
__repr__ 返回适合机器看的字符
__eq__ 判断是否相等,比较运算符
__add__ 相加,数字运算符
__and__ 判断条件,逻辑运算符
__dir__ 查看对象的属性
__setattr__ 设置对象的属性,注意避免循环递归,导致死循环
__getattribute__ 访问对象的属性,注意避免死循环
__len__ 获取对象参数个数
__call__ 调用对象
  1. 示例
# 类中的魔术方法

class Person(object):

    def __init__(self, name, age):      
        """
        构造函数,初始化定义属性
        """
        self.name = name,
        if isinstance(age, int):        # 确保age属性必须是数值
            self.age = age
        else:
            raise Exception ('age must be int')

    def __eq__(self, other):
        """
        判断2个对象是否相等
        """
        if isinstance(other, Person):   # 确保2个对象是同一个父类
            if self.age == other.age:
                return True
            else:
                return False
        else:
            raise Exception ('The class of object must be Person')

    def __add__(self, other):
        """
        2个对象相加
        """
        if isinstance(other, Person):   # 确保2个对象是同一个父类
            return self.age + other.age
        else:
            raise Exception ('The class of object must be Person')

    def __str__(self):
        """
        输出指定内容
        """
        return f"{self.name[0]} is {self.age} years old"

    def __dir__(self):
        """
        设置输出的属性
        """
        return self.__dict__.keys()

    def __setattr__(self, name, value):
        """
        设置对象的属性
        """
        self.__dict__[name] = value

    def __getattribute__(self, name):
        """
        访问对象的属性
        """
        return super(Person, self).__getattribute__(name)

    def __len__(self):
        """
        返回类的参数个数
        """
        return len(self.name)

    def __call__(self, friend):     # friend是调用对象时传入的参数
        """
        调用对象
        """
        return f"My name is {self.name[0]} ... My friend is {friend}"


if __name__ == '__main__':
    p1 = Person('Larry', 28)
    p2 = Person('Python', 30)
    print(p1 == p2)     # __eq__根据age属性,判断是否相等
    print(p1 + p2)      # __add__对age属性,相加
    print(p1)           # __str__返回指定的内容
    print(dir(p1))      # __dir__输出指定的属性
    print(p1.age)       # __setattar__设置对象的属性
    print(len(p1))      # __len__返回类的参数个数
    print(p1('Tom'))    # __call__调用对象

False
58
Larry is 28 years old
['age', 'name']
28
1
My name is Larry ... My friend is Tom

你可能感兴趣的:(Python面向对象与类)