(一)面向对象的重要术语
1、多态(polymorphism):一个函数有多种表现形式,调用一个方法有多种形式,但是表现出的方法是不一样的。
2、继承(inheritance)子项继承父项的某些功能,在程序中表现某种联系
3、封装(encapsulation)把需要重用的函数或者功能封装,方便其他程序直接调用
4、类:对具有相同数据或者方法的一组对象的集合
5、对象:对象是一个类的具体实例
6、实例化:是一个对象实例化的实现
7、标识:每个对象的事例都需要一个可以唯一标识这个事例的标记
8、实例属性:一个对象就是一组属性的集合
9、实例方法:所有存取或者更新对象某个实例一条或者多条属性函数的集合。
10、类属性:属于一个类中所有对象的属性,
11、类方法:那些无须特定的对性实例就能够工作的从属于类的函数。
(二)面向对象的各种方法
类方法
使用@classmethod修饰
不需要实例化就可以调用,但是它无法调用实例方法,它可以调用其他的类方法和类变量。
实例方法可以随意的调用类方法。
静态方法
使用@staticmethod修饰
不需要实例化就可以调用,但是它无法调用实例方法、类方法、类变量。
1、如果你这个函数,没有调用其他的方法,也没有使用其他的属性(类、实例),那么你就把他定义成一个staticmethod
2、如果你这个函数,只用到了类属性,或者要调用类方法,那么就把他定义成一个类方法。
属性方法
使用@property修饰
看起来像变量的一个函数
这个函数不能有入参,但是必须有返回值
实例方法
1、类方法 (用这个装饰器来表示 @classmethod)
类方法只能访问类变量,不能访问实例变量
# 错误演示
class Person(object):
def __init__(self, name):
self.name = name
@classmethod # 把eat方法变为类方法
def eat(self):
print("%s is eating" % self.name)
d = Person("sara")
d.eat()
结果:
AttributeError: type object 'Person' has no attribute 'name'
因为self.name这个变量是实例化这个类传进去的,类方法是不能访问实例变量的,只能访问类里面定义的变量
class Person(object):
name = "lilY"
def __init__(self, name):
self.name = name
@classmethod # 把eat方法变为类方法
def eat(self):
print("%s is eating" % self.name)
d = Person("sara")
d.eat()
2、静态方法 (用这个装饰器来表示 @staticmethod )
# 错误示例
class Person(object):
def __init__(self, name):
self.name = name
@staticmethod # 把eat方法变为静态方法
def eat(self):
print("%s is eating" % self.name)
d = Person("xiaoming")
d.eat()
结果:
TypeError: eat() missing 1 required positional argument: 'self'
因为用静态方法把eat这个方法与Person这个类截断了,eat方法就没有了类的属性了,所以获取不到self.name这个变量。
# 正确方法
class Person(object):
def __init__(self, name):
self.name = name
@staticmethod # 把eat方法变为静态方法
def eat(x):
print("%s is eating" % x)
d = Person("xiaoming")
d.eat("jack")
#就把eat方法当作一个独立的函数给他传参就行了
3、属性方法 (用这个装饰器表示 @property)
把一个方法变成一个静态属性,属性就不用加小括号那样的去调用了
# 错误示例
class Person(object):
def __init__(self, name):
self.name = name
@property # 把eat方法变为属性方法
def eat(self):
print("%s is eating" % self.name)
d = Person("xiaoming")
d.eat()
##########
结果:
TypeError: 'NoneType' object is not callable
因为eat此时已经变成一个属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
class Person(object):
def __init__(self, name):
self.name = name
@property # 把eat方法变为属性方法
def eat(self):
print("%s is eating" % self.name)
d = Person("xiaoming")
d.eat
4、继承
经常在类的继承当中使用super(), 来调用父类中的方法
class A:
def func(self):
print('A class')
class B(A):
def func(self):
super().func()
print('B class')
A().func()
B().func()
如果不使用super的话,想得到相同的输出截个,还可以这样写B的类:
class B(A):
def func(self):
A.func(self)
print('B class')
这样能实现相同的效果,只不过传了一个self参数。那为什么还要使用super()呢?
class Base:
def __init__(self):
print('Base.__init__')
class A(Base):
def __init__(self):
Base.__init__(self)
print('A.__init__')
class B(Base):
def __init__(self):
Base.__init__(self)
print('B.__init__')
class C(A, B):
def __init__(self):
A.__init__(self)
B.__init__(self)
print('C.__init__')
C()
输出的结果是:
Base.init
A.init
Base.init
B.init
C.init
每个子类都调用父类的init方法,想把所有的初始化操作都做一遍,但是出现了一个问题,Base类的init方法被调用了两次,这是多余的操作,也是不合理的。
那我们改写成使用super()的写法:
class A(Base):
def __init__(self):
super().__init__()
print('A.__init__')
class B(Base):
def __init__(self):
super().__init__()
print('B.__init__')
class C(A, B):
def __init__(self):
super().__init__()
print('C.__init__')
C()
输出的结果是:
Base.init
B.init
A.init
C.init
那是因为我们每定义一个类的时候,Python都会创建一个MRO列表,用来管理类的继承顺序。
print(C.mro())
# [<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