前言时刻:学习了面向对象的基本概念,其实也没多少东西,主要是一些规范之类的

1、类

我们都知道 Python 是面向对象的一门语言,所以类是非常重要的一个概念,

  1. 每个定义的类都有一个空间,存储是定义在class中所有属性名称

  2. 每个实例化的对象都拥有自己的存储空间,通过对象名.__dict__,就可以获得这个对象的属性值。

  3. 对象的属性值有增删改查等方式,设有一个对象

    • 增:s.name="pyton"

    • 删除:del s.name

    • 查看:s.name或者s.__dict__['name']

  4. 不要将要计算的代码放到 __init__函数中执行。

2、类的基本概念

1)初始化类:

通过使用__init__函数,初始化对象的属性。

  1. # 1、初始化类
  2. class A:
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. def add(self):
  7. self.age = self.age + 1
  8. return self.age
  9. a = A("python", 16)
  10. a.add() # 17

2)类的静态变量:

这个静态变量就有点佛系了,它不放在 __init__函数中初始化,而是和函数的位置一样,放在外面定义。可以通过类名访问或者对象名访问

  1. class A:
  2. job = "data"
  3. def __init__(self, name, age):
  4. self.name = name
  5. self.age = age
  6. def add(self):
  7. self.age = self.age + 1
  8. return self.age
  9. a = A("python", 16)
  10. a.job # data 通过对象访问
  11. A.job # data 通过类名访问

1)类的静态变量的用处:

  • 类被初始化后,其实例化的所有对象共享同一静态变量

2)静态变量的修改:

通过类.变量,修改变量值,如果是通过对象名.变量是修改对象的变量值。

  1. class A:
  2. name = "Python"
  3. def __init__(self):
  4. self.name = "Java"
  5. self.job = 'data'
  6. print("初始化class A")
  7. def func(self):
  8. print('A func is called')
  9. # 1、调用类的静态变量
  10. a1 = A()
  11. print(a1.name) # Java
  12. print(A.name) # Python
  13. # 修改类的静态变量
  14. A.name = "C++"
  15. print(A.name) # C++
  16. # 2、对象的属性添加变量
  17. a1.ability = "99" # 99
  18. print(a1.ability) # 99
  19. # 3、类添加静态变量
  20. A.is_active = True
  21. print(A.is_active) # True

3、命名空间:

当创建一个类的时候,会初始化一个类空间,里面存放着各个类属性的地址,如果类中有私有

  • Python中一切皆是对象,对象的类型即使类,函数也是类对象
  • 当使用对象名.属性的时候,会优先调用对象的属性,如果没有的话就找类的静态变量。

1)类的组合使用:

类的组合使用有利于解决类之间的绑定问题,将两个类绑定在一起,方便之间的调用。举个例子:今天老板让你写一个功能,在一个课程类中可以调用讲课的老师的姓名、年龄?

你会怎么办,这里可以使用类的组合功能。

  1. class Teacher:
  2. def __init__(self, *args):
  3. self.name = args[0]
  4. class Course:
  5. def __init__(self, *args):
  6. self.teacher = args[0]
  7. self.name = args[1]
  8. def get_teacher_name(self):
  9. return self.teacher.name
  10. teacher1 = Teacher('zi', 18)
  11. python_course = Course(teacher1, 'python')
  12. python_course.get_teacher_name() # zi

4、封装

其实就是Python的开放封闭原则,开放:指的是可以对该类进行扩展功能,而封闭:是可以控制一些属性不被外部访问

4.1 私有属性和方法:

具体的私有(private)用法是:

  • 双下划线+变量,是类的私有变量,只可以在本类中调用,且外部不能调用和修改。
  • 双下划线+方法,是类的私有方法,同样也是只可在本类中调用,外部不可调用。注意:其子类不可调用父类的私有变量和私有方法

公共(public)方法是:不加双下划线默认就是公共方法。

  • 父子均可调用,
  • 并且类外也可调用

使用私有方法,可以防止有些敏感数据被外部修改(其实也可修改,下面有提),提高安全性,复用性。

例子:

  1. # 私有变量
  2. class Person:
  3. def __init__(self, name, age, *args, **kwargs):
  4. self.name = name
  5. self.__age = age
  6. pass
  7. def __get_age(self):
  8. return self.__age + 600
  9. def get_msg2(self):
  10. return self.name, self.__get_age()
  11. class Worker(Person):
  12. def __intit__(self, name, age, *args, **kwargs):
  13. self.w_age = age
  14. Super(Worker, self).__init__(name, age)
  15. def get_msg1(self):
  16. return self.get_msg2

1、私有属性 类外不可访问:

  1. p = Person('jingdong', 18, 'python')
  2. # p.age # AttributeError: 'Person' object has no attribute 'age'
  3. # p.get_age() # AttributeError: 'Person' object has no attribute 'get_age'
  4. # 想访问就需要通过类的成员函数 间接访问
  5. p.get_msg2() # ('jingdong', 618)

2、子类 也不可访问 父类的私有属性:

  1. w = Worker('jingdong', 18, 'python')
  2. # w.get_age() # AttributeError: 'Worker' object has no attribute 'get_age'
  3. w.get_msg2() # ('jingdong', 618)

3、类外也可访问和修改私有属性:

我们打印下 p 对象的属性,发现原设置的__age变量变成了_Person__age

  1. p.__dict__ # {'name': 'jingdong', '_Person__age': 18}
  2. # 取类的私有变量
  3. p._Person__age # 18
  4. # 修改类的私有变量
  5. p._Person__age = 17
  6. p._Person__age # 17

4.2 property

这个方法挺好玩的的,它把一个函数看似变成了属性调用,比如self.func()变成了self.func,返回的结果一样。

使用 property 有啥优点呢?

  • 隐藏函数形式,
  • 缺点:不可以直接传参数,
  1. # property装饰器
  2. class Person:
  3. def __init__(self, name, age, *args, **kwargs):
  4. self.name = name
  5. self.age = age
  6. @property
  7. def get_name(self):
  8. return self.name
  9. @get_name.setter
  10. def get_name(self, te):
  11. if isinstance(te, str):
  12. self.name += te
  13. else:
  14. raise TpyeError(f"{te} must be str")
  15. def get_age(self):
  16. return self.age
  17. p = Person('jingdong', 618, 'python')
  18. print(p.get_name, p.get_age(), sep=' : ') # jingdong : 618
  19. # 可以看出,本来是函数,却用调用属性的方式进行调用。

修改属性:

  1. p.get_name = '(666)'
  2. print(p.get_name) # jingdong(666)

5、继承

继承主要为了解决代码冗余问题,子类可以调用父类的全部功能。在 Python3 中,所有的类都是默认继承于新式类 object 。

继承的称为子类或者派生类,被继承的称为父类或者父类。

继承可分为:

  • 单继承
  • 多继承:按照 C3 算法找父类的函数

另外还有新式类(Python3中的类都是新式类)和经典类(Python2中的)之分。

5.1 初始化父类

类中使用__init__函数进行类的属性构造,类似于 C++ 中的构造函数。

  1. # 初始化父类
  2. class A:
  3. def __init__(self, *args):
  4. self.age = args[0]
  5. self.name = 'java'
  6. pass
  7. def func(self):
  8. print('A', self.name, sep=' : ')
  9. class B(A):
  10. def __init__(self, *args):
  11. # A.__init__(self, *args) # 初始化父类 经典类的方法
  12. # super(B, self).__init__(*args)
  13. # super().__init__(*args) # 新式类的初始化父类方法,和上一行等同。
  14. self.name = args[1]
  15. def func(self):
  16. print('B', self.name, sep=' : ')
  17. B(17, 'python').func() # B : python

5.3 调用同名函数/变量

  1. class A:
  2. def __init__(self, *args):
  3. self.age = args[0]
  4. self.name = 'java'
  5. def func(self):
  6. print('A', self.name, sep=' : ')
  7. class B(A):
  8. name = 'B name'
  9. def __init__(self, *args):
  10. super().__init__(*args) # 初始化父类
  11. self.name = args[1]
  12. def func2(self):
  13. print('B', self.name, sep=' : ')
  14. b_class = B(17, 'python')
  15. b_class.func() # A : python
  16. b_class.name # python
  17. # 寻找name属性顺序:python->java->B name
  • 调用属性时,找属性的顺序:优先该类中->父类中->该类中的静态变量
  • 调用函数时:优先该类中->父类中

5.3 多继承

新式类中多继承的查找顺序规则是:MRO(module resolution order),其定义了调用父类属性的顺序问题,有点类似广度优先,但还是不一样。而在经典类中则采用深度优先的规则,来查找父类的属性。

多继承有两种方式,一种是使用super方法,另外一种是使用类名.__init__,那是一种系统的方法,

  1. # 3、多继承
  2. class Animal:
  3. def __init__(self, name, age, *args):
  4. print("初始化 Animal 类")
  5. self.age = age
  6. self.name2 = name
  7. def func1(self):
  8. print('Animal called', self.name2, sep=' : ')
  9. class Single:
  10. def __init__(self, name, age, feature, *args):
  11. print("初始化 Single 类")
  12. self.feature = feature
  13. def func(self):
  14. print("Single called", self.name, self.feature)
  15. class Dog(Single, Animal):
  16. name = 'Dog static'
  17. def __init__(self, name, age, feature, *args):
  18. Animal.__init__(self, '狗仔', 18) # 初始化Animal类
  19. Single.__init__(self, name, age, feature) # 初始化个体类
  20. self.name = name
  21. def func2(self):
  22. print('Dog', self.name, sep=' : ')
  23. dog = Dog('旺财', 2, '柯基犬')
  24. print(Dog.__mro__) # (<class '__main__.Dog'>, <class '__main__.Single'>, <class '__main__.Animal'>, <class 'object'>)
  25. dog.func1()
  26. dog.name2 # 狗仔
  27. """
  28. 初始化 Animal 类
  29. 初始化 Single 类
  30. (<class '__main__.Dog'>, <class '__main__.Single'>, <class '__main__.Animal'>, <class 'object'>)
  31. Animal called : 狗仔
  32. '狗仔'
  33. """

使用类名.__mro__打印出当前类的继承所有类的顺序。

2)使用super方法初始化父类:

这个需要重点掌握,因为很绕,

  1. # 3、多继承
  2. class Animal:
  3. def __init__(self, name, age, *args):
  4. print("初始化 Animal 类")
  5. self.age = age
  6. self.name2 = name
  7. def func1(self):
  8. print('Animal called', self.name2, sep=' : ')
  9. class Single:
  10. def __init__(self, name, age, feature, *args):
  11. print("初始化 Single 类")
  12. self.feature = feature
  13. def func(self):
  14. print("Single called", self.name, self.feature)
  15. class Dog(Single, Animal):
  16. name = 'Dog static'
  17. def __init__(self, name, age, feature, *args):
  18. super().__init__(name, age, feature) # 初始化Single类
  19. super(Single, self).__init__('狗仔', 18, feature) # 初始化Animal类
  20. self.name = name
  21. def func2(self):
  22. print('Dog', self.name, sep=' : ')
  23. dog = Dog('旺财', 2, '柯基犬')
  24. print(Dog.__mro__)
  25. dog.func1()
  26. dog.name2 # 狗仔
  27. """
  28. 初始化 Single 类
  29. 初始化 Animal 类
  30. (<class '__main__.Dog'>, <class '__main__.Single'>, <class '__main__.Animal'>, <class 'object'>)
  31. Animal called : 狗仔
  32. '狗仔'
  33. """

3)mor算法介绍:

6、多态

其实前面已经用到了多态的概念,就是在继承中。在c++中,多态指的是:通过传入不同的参数类型和数量实现不同的功能。在 Python 中也是类似的,子类继承于父类,在子类中写一个和父类的同名函数。调用函数的时候,就可有不同用法。

多态有啥优点:

  • 不破坏父类的结构,可添加自定义功能
  • 可定义同名函数,覆盖父类的函数功能
  1. class Person:
  2. def __intit__(self):
  3. pass
  4. def func(self, name):
  5. print(f"Person {name}")
  6. def get_name(self):
  7. print("func get_name")
  8. class Boy(Person):
  9. def __init__(self):
  10. super().__init__()
  11. pass
  12. def func(self, name):
  13. print(f"Boy {name}")
  14. xm = Boy()
  15. # 多态
  16. xm.func('小明') # Boy 小明
  17. # 继承
  18. xm.get_name() # func get_name

6.1 多态的用处

多态可以用来做项目架构,事先定义一个父类,等到后面只需要定义一些子类,重写一些函数即可,高效而简洁。

  1. # 多态的用处
  2. import abc
  3. class Person(metaclass=abc.ABCMeta):
  4. @abc.abstractmethod
  5. def get_name(self):
  6. pass
  7. class Boy(Person):
  8. def get_name2(self):
  9. print('Boy')
  10. xm = Boy()
  11. xm.get_name()
  12. # TypeError: Can't instantiate abstract class Boy with abstract methods get_name

如果子类不定义一个同名函数,直接就报错。

7、classmethod用法

从字面上的意思就是:类方法,官方的解释就是在不实例化对象的时候,可以通过类名或者对象调用被装饰的函数。用法很简单直接给函数添加一个装饰器:@classmethod,被装饰器的函数的第一个参数必须是cls

  1. class A(object):
  2. __age = 17 # 类静态变量
  3. __age2 = 17
  4. @classmethod
  5. def get_age(cls, age):
  6. cls.__age += age
  7. return cls.__age
  8. def get_age2(self, age):
  9. self.__age += age
  10. return self.__age
  11. # 直接就可通过类名访问类方法
  12. A.get_age(1) # 18
  13. # 通过实例化的对象调用
  14. a = A()
  15. a.get_age2(1) # 19

2)思考🤔:这个classmethod有啥用?

个人觉的最大的好处就是不用实例化类就可调用成员函数,并且默认给函数传进取了一个cls,其实就是 self,可以初始化一个对象并返回,可以看下面:

  1. class A(object):
  2. def __init__(self, age):
  3. self.age = age
  4. @classmethod
  5. def get_obj(cls, age):
  6. return cls(age)
  7. # 直接就可通过
  8. a = A.get_obj(666)
  9. print(a) # <__main__.A object at 0x7f8f1ab4b670>
  10. a.age # 666

8、staticmethod方法

他是放在类中的一个普通函数,不带有self参数,想当时与专属于这个类的一个局部函数。

  1. # staticmethod方法
  2. class A(object):
  3. @staticmethod
  4. def get_age(age):
  5. print("我就是一个普通的函数,只不过在类中")
  6. return age
  7. # 1. 通过类名访问
  8. A.get_age(1) # 1
  9. # 2. 通过对象名访问
  10. a = A()
  11. a.get_age(2) # 2

总结

面向对象的东西很多很杂,还是那句话,多看多练多总结!

参考链接:

http://www.langzi.fun/Python面向对象编程.html

多继承:

https://blog.csdn.net/JackZhao/article/details/82840901

https://blog.csdn.net/RSstudent/article/details/108809921

https://www.cnblogs.com/wongbingming/p/10934356.html