一篇面对对象编程很不错的文章
https://blog.csdn.net/weixin_42134789/article/details/80194788#commentBox
关于继承的好文章,单继承,多继承
https://www.cnblogs.com/shouke/p/10157802.html
python中的 下划线
(1)_xxx
"单下划线 " 开始的成员变量相当于私有变量,也叫做保护变量,意思是只有类实例和子类实例能访问到这些变量,需通过类提供的接口进行访问(可以定义有点像java中的getter、setter方法,借助方法访问,而不是直接对变量动刀子);不能用’from module import *'导入。其实,Python并没有真正的私有化支持,用下划线得到的是伪私有,也就是说如果你强行要用也是可以的,但不符合python的规范。我们应该尽量避免重新定义以下划线开头的变量。
单个下划线是一个Python命名约定,表示这个名称是供内部使用的。 它通常不由Python解释器强制执行,仅仅作为一种对程序员的提示。
(2)__xxx
双下划线:类中的私有变量/方法名 (Python的函数也是对象,所以成员方法称为成员变量也行得通)。" 双下划线 " 开始的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
(3)xxx
系统定义名字,前后均有一个“双下划线” 代表python里特殊方法专用的标识,如 init()代表类的构造函数。类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如一个模块的__author__,__name__就是特殊变量,模块定义的文档注释(就是模块开头的字符串)也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名。
__int__与self
(1)、__init__方法的第一参数永远是self,表示创建的类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。(2)、有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去。self指实例地址(牢记),定义类函数加self形参。名字可以不要self,可以换为其它。
类变量(class variables)与实例变量(instance variables)
假设我们需要在Student类里增加一个计数器number,每当一个新的学生对象(Object)被创建时,这个计数器就自动加1。由于这个计数器不属于某个具体学生,而属于Student类的,所以被称为类变量(class variables)。而姓名和分数属于每个学生对象的,所以属于实例变量(instance variables),也被称为对象变量(object variables)。
# 创建一个学生类
class Student:
# number属于类变量,定义在方法外,不属于具体实例
number = 0
# 定义学生属性,初始化方法
# name和score属于实例变量,定义在方法里
def __init__(self, name, score):
self.name = name
self.score = score
# 此处有错误
number = number + 1
# 定义打印学生信息的方法
def show(self):
print("Name: {}. Score: {}".format(self.name, self.score))
-
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。访问或调用类变量的正确方式是类名.变量名或者self.class.变量名。self.__class__自动返回每个对象的类名。
-
实例变量:定义在方法中的变量,属于某个具体的对象。访问或调用实例变量的正确方式是对象名.变量名或者self.变量名.
类方法(Class method)
正如同有些变量只属于类,有些方法也只属于类,不属于具体的对象。你有没有注意到属于对象的方法里面都有一个self参数, 比如__init__(self), show(self)? self是指对象本身。属于类的方法不使用self参数, 而使用参数cls,代表类本身。另外习惯上对类方法我们会加上@classmethod的修饰符做说明。
class Student:
# number属于类变量,不属于某个具体的学生实例
number = 0
# 定义学生属性,初始化方法
# name和score属于实例变量
def __init__(self, name, score):
self.name = name
self.score = score
Student.number = Student.number + 1
# 定义打印学生信息的方法
def show(self):
print("Name: {}. Score: {}".format(self.name, self.score))
# 定义类方法,打印学生的数量
@classmethod
def total(cls):
print("Total: {0}".format(cls.number))
继承和多态
刚才我们提到了,可以在已有类的基础上创建新类,这其中的一种做法就是让一个类从另一个类那里将属性和方法直接继承下来,从而减少重复代码的编写。提供继承信息的我们称之为父类,也叫超类或基类;得到继承信息的我们称之为子类,也叫派生类或衍生类。子类除了继承父类提供的属性和方法,还可以定义自己特有的属性和方法,所以子类比父类拥有的更多的能力,在实际开发中,我们经常会用子类对象去替换掉一个父类对象,这是面向对象编程中一个常见的行为,对应的原则称之为里氏替换原则。
子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)。
**1、单继承
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
A.__init__(self) # 在子类中调用父类的方法:父类名.方法名称(参数)
print("This is B")
if __name__=='__main__':
b=B()
- 缺点:当一个子类的父类发生变化时(如类SubClassB的父类由FatherA变为FatherD时),必须遍历整个类定义,把子类中所有的父类类名全部替换过来
- 在子类中调用父类的方法:super().方法名称(参数)
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
super().__init__()
print("This is B")
if __name__=='__main__':
b=B()
super().init() 效果等同 super(B, self). init()
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
super(B,self).__init__()
print("This is B")
if __name__=='__main__':
b=B()
- 在子类中调用父类的方法:super(type, obj).方法名称(参数)
- python中的super( test, self).init()
- 对继承自父类的属性进行初始化调用一遍父类的方法
- 首先找到test的父类(比如是类A),然后把类test的对象self转换为类A的对象,然后“被转换”的类A对象调用自己的__init__函数
2、多层继承
super( test, self).init()的运用
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
super(B,self).__init__()
print("This is B")
class C(B):
def __init__(self):
super(C,self).__init__()
print("This is C")
if __name__=='__main__':
c=C()
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
super(B,self).__init__()
print("This is B")
class C(B):
def __init__(self):
super(B,self).__init__()
print("This is C")
if __name__=='__main__':
c=C()
class A:
def __init__(self):
print("This is A")
class B(A):
def __init__(self):
super().__init__()
print("This is B")
class C(B):
def __init__(self):
super().__init__()
print("This is C")
if __name__=='__main__':
c=C()
多重继承
class A:
def __init__(self):
print('This is A')
class B:
def __init__(self):
print('This is B')
class C(A,B):
def __init__(self):
super().__init__()
print('This is C')
if __name__ == '__main__':
c = C()
class A:
def __init__(self):
print('This is A')
class B:
def __init__(self):
print('This is B')
class C(B,A):
def __init__(self):
super().__init__()
print('This is C')
if __name__ == '__main__':
c = C()
按继承顺序,选择第一个父类中的方法
不同类,同名的方法
class A:
def __init__(self):
print('This is A')
class B:
def __init__(self):
print('This is B')
class C(B,A):
def __init__(self):
A.__init__(self)
B.__init__(self)
print('This is C')
if __name__ == '__main__':
c = C()