(一)面向对象的重要术语

1、多态(polymorphism):一个函数有多种表现形式,调用一个方法有多种形式,但是表现出的方法是不一样的。
2、继承(inheritance)子项继承父项的某些功能,在程序中表现某种联系
3、封装(encapsulation)把需要重用的函数或者功能封装,方便其他程序直接调用
4、类:对具有相同数据或者方法的一组对象的集合
5、对象:对象是一个类的具体实例
6、实例化:是一个对象实例化的实现
7、标识:每个对象的事例都需要一个可以唯一标识这个事例的标记
8、实例属性:一个对象就是一组属性的集合
9、实例方法:所有存取或者更新对象某个实例一条或者多条属性函数的集合。
10、类属性:属于一个类中所有对象的属性,
11、类方法:那些无须特定的对性实例就能够工作的从属于类的函数。

(二)面向对象的各种方法

  1. 类方法
  2. 使用@classmethod修饰
  3. 不需要实例化就可以调用,但是它无法调用实例方法,它可以调用其他的类方法和类变量。
  4. 实例方法可以随意的调用类方法。
  5. 静态方法
  6. 使用@staticmethod修饰
  7. 不需要实例化就可以调用,但是它无法调用实例方法、类方法、类变量。
  8. 1、如果你这个函数,没有调用其他的方法,也没有使用其他的属性(类、实例),那么你就把他定义成一个staticmethod
  9. 2、如果你这个函数,只用到了类属性,或者要调用类方法,那么就把他定义成一个类方法。
  10. 属性方法
  11. 使用@property修饰
  12. 看起来像变量的一个函数
  13. 这个函数不能有入参,但是必须有返回值
  14. 实例方法

1、类方法 (用这个装饰器来表示 @classmethod)

类方法只能访问类变量,不能访问实例变量

  1. # 错误演示
  2. class Person(object):
  3. def __init__(self, name):
  4. self.name = name
  5. @classmethod # 把eat方法变为类方法
  6. def eat(self):
  7. print("%s is eating" % self.name)
  8. d = Person("sara")
  9. d.eat()
  10. 结果:
  11. AttributeError: type object 'Person' has no attribute 'name'

因为self.name这个变量是实例化这个类传进去的,类方法是不能访问实例变量的,只能访问类里面定义的变量

  1. class Person(object):
  2. name = "lilY"
  3. def __init__(self, name):
  4. self.name = name
  5. @classmethod # 把eat方法变为类方法
  6. def eat(self):
  7. print("%s is eating" % self.name)
  8. d = Person("sara")
  9. d.eat()

2、静态方法 (用这个装饰器来表示 @staticmethod )

  1. # 错误示例
  2. class Person(object):
  3. def __init__(self, name):
  4. self.name = name
  5. @staticmethod # 把eat方法变为静态方法
  6. def eat(self):
  7. print("%s is eating" % self.name)
  8. d = Person("xiaoming")
  9. d.eat()
  10. 结果:
  11. TypeError: eat() missing 1 required positional argument: 'self'

因为用静态方法把eat这个方法与Person这个类截断了,eat方法就没有了类的属性了,所以获取不到self.name这个变量。

  1. # 正确方法
  2. class Person(object):
  3. def __init__(self, name):
  4. self.name = name
  5. @staticmethod # 把eat方法变为静态方法
  6. def eat(x):
  7. print("%s is eating" % x)
  8. d = Person("xiaoming")
  9. d.eat("jack")
  10. #就把eat方法当作一个独立的函数给他传参就行了

3、属性方法 (用这个装饰器表示 @property)

把一个方法变成一个静态属性,属性就不用加小括号那样的去调用了

  1. # 错误示例
  2. class Person(object):
  3. def __init__(self, name):
  4. self.name = name
  5. @property # 把eat方法变为属性方法
  6. def eat(self):
  7. print("%s is eating" % self.name)
  8. d = Person("xiaoming")
  9. d.eat()
  10. ##########
  11. 结果:
  12. TypeError: 'NoneType' object is not callable

因为eat此时已经变成一个属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

  1. class Person(object):
  2. def __init__(self, name):
  3. self.name = name
  4. @property # 把eat方法变为属性方法
  5. def eat(self):
  6. print("%s is eating" % self.name)
  7. d = Person("xiaoming")
  8. d.eat

4、继承

经常在类的继承当中使用super(), 来调用父类中的方法

  1. class A:
  2. def func(self):
  3. print('A class')
  4. class B(A):
  5. def func(self):
  6. super().func()
  7. print('B class')
  8. A().func()
  9. B().func()

如果不使用super的话,想得到相同的输出截个,还可以这样写B的类:

  1. class B(A):
  2. def func(self):
  3. A.func(self)
  4. print('B class')

这样能实现相同的效果,只不过传了一个self参数。那为什么还要使用super()呢?

  1. class Base:
  2. def __init__(self):
  3. print('Base.__init__')
  4. class A(Base):
  5. def __init__(self):
  6. Base.__init__(self)
  7. print('A.__init__')
  8. class B(Base):
  9. def __init__(self):
  10. Base.__init__(self)
  11. print('B.__init__')
  12. class C(A, B):
  13. def __init__(self):
  14. A.__init__(self)
  15. B.__init__(self)
  16. print('C.__init__')
  17. C()

输出的结果是:
Base.init
A.init
Base.init
B.init
C.init
每个子类都调用父类的init方法,想把所有的初始化操作都做一遍,但是出现了一个问题,Base类的init方法被调用了两次,这是多余的操作,也是不合理的。
那我们改写成使用super()的写法:

  1. class A(Base):
  2. def __init__(self):
  3. super().__init__()
  4. print('A.__init__')
  5. class B(Base):
  6. def __init__(self):
  7. super().__init__()
  8. print('B.__init__')
  9. class C(A, B):
  10. def __init__(self):
  11. super().__init__()
  12. print('C.__init__')
  13. C()

输出的结果是:
Base.init
B.init
A.init
C.init
那是因为我们每定义一个类的时候,Python都会创建一个MRO列表,用来管理类的继承顺序。

  1. print(C.mro())
  2. # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

Python通过这个列表从左到右,查找继承的信息。Python3中的类都是新式类,都有这个mro属性,能看出来是广度优先的查找原则。经典类就没有mro属性,但它的查找原则是深度优先。

文章引用:https://www.cnblogs.com/szy13037-5/articles/9562639.html