4.python中的类和对象
4.1鸭子类型和多态
鸭子类型字面意思,一个东西看上去像鸭子,那么我们就把他当做鸭子。在函数上的表现为,多个函数能够实现某一个一样的方法,我们就说他们同类。给了例子:
class Doge:
def quack(self):
print('i am doge')
class Pig:
def quack(self):
print('i am pig')
class Brid:
def quack(self):
print('i am brid')
# 首先实例化三个对象
a = Doge()
b = Pig()
c = Brid()
# 然后分别让他们运行同样的方法quack()
for i in [a,b,c]:
i.quack()
# 输出结果如下:
i am doge
i am pig
i am brid
对于多态而言,根据python语言的特性:多态,封装,继承
多态:对于不同类型的对象可以执行相同的操作
例如:
# python中+
def add(a,b):
return a+b
print(add(1,2))
print(add('a','b'))
封装:对外部隐藏有关对象工作原理的细节
继承:可基于通用类创建专用类
4.2抽象基类
使用情况:
1.我们在某些情况下希望判定某个对象的类型(需要知道抽象基类)
isinstance()
2.我们需要强制某个子类必须实现某些方法
4.3 使用instance而不是type
is用于判断对象类型是否相同,==判断两个数值是否相同。
4.4 类变量和对象变量
类变量进行修改时,通过类构建的实例的变量相应发生改变;
但是通过实例访问变量时,并对变量进行赋值时,实例变量的值发生变化,重新通过类构造的实例,类的变量并不会发生变化。
4.5 类属性和实例属性以及查找顺序
MRO算法:DFS
对于菱形继承而言,DFS不太可行,改用BFS
C3算法(python属性的查找算法)
菱形继承:
# 菱形继承
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B,C):
pass
if __name__=='__main__':
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
# 新式类
class A:
pass
class B(A):
pass
class C:
pass
class D(C):
pass
class E(B,D):
pass
if __name__=='__main__':
print(E.__mro__)
# (<class '__main__.E'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.D'>, <class '__main__.C'>, <class 'object'>)
4.6 静态方法、类方法以及对象方法以及参数
静态方法
我们在一个类中进行相应的操作时定义了一个函数,要求这个函数与实例和所在的类都无关,那么我们需要定义一个静态方法
@staticmethod
def fun():
pass
相对于静态方法,我们在调用相应的静态方法时,如果静态方法返回了某些值到类对象中,那么我们需要重新写静态的方法,这样显得十分麻烦,因此产生了类方法:
#静态方法
class Name:
def __init__(self,x):
self.x = x
@staticmethod
def fun(str):
return Name(str)
@classmethod
def fun1(cls,str):
return cls(str)
print(Name.fun('str').x)
print(Name.fun1('str2').x)
4.7 数据封装和私有属性
python中相对于java而言没有private和protected这样的类别
因此我们在python中如何实现私有属性呢。
首先我们可以定义一个类
class User:
def __init__(self, brithday):
self.__brithday = brithday
def get_age(self):
return 2018-self.__brithday
这样我们在进行访问类创建的实例时,不能直接使用user.__brithday进行访问,否则会出现以下错误:
AttributeError: 'User' object has no attribute '__brithday'
但是可以在类的构造函数中进行访问,例如get_age()方法,可以直接进行访问;当然也可以直接让直接返回私有属性
def get_brithday(self):
return self.__brithday
python对于私有属性会进行一个变形,依旧可以进行私有属性进行访问
print(user._User__brithday)
这样的方式,有一个优点,我们在进行A类继承B时,B的中的私有属性和A的私有属性分别会不同的类名前缀作为识别,从而避免重复的问题。
4.8 python对象的自省机制
python自省是通过一定的机制查询到内部的结构:
# 通过__dict__查询属性
class Person:
name = 'user'
class Student(Person):
def __init__(self, school_name):
self.school_name = school_name
if __name__ == '__main__':
user = Student('Liun')
print(user.__dict__)
print(Person.__dict__)
print(user.name)
# 依次可以查询到如下信息
# {'school_name': 'Liun'}
#{'__module__': '__main__', 'name': 'user', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
#user
# 如果你想要直接进行新的信息添加,可以使用以下方法
user.__dict__['school_addr'] = '长沙'
print(user.school_addr)
# dir可以列出对象的所有属性,相对于__dict__更加强大
dir(user)
4.9 super函数
super调用父类函数
# 在进行父类的调用时,我们可以使用
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super().__init__()
if __name__ == '__main__':
b = B()
# B
# A
# 其实super()在进行调用时并不是进行父类函数的直接调用,他是通过访问mro中的对象依次进行访问
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
super().__init__()
class C(A):
def __init__(self):
print('C')
super().__init__()
class D(B,C):
def __init__(self):
print('D')
super().__init__()
if __name__ == '__main__':
print(D.__mro__)
a = D()
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
# D B C A
4.10 python中多继承
mixin混合模式
1.Mixin功能单一
2.不和基类关联,可以和任何基类组合,基类可以不和Mixin关联就能初始化成功
3.在Mixin不要使用super函数
4.11 python的上下文管理器
python中的异常管理
try except finally
# 在try中的语句会被输出,然后由于没有捕获到keyError的错误,则会输出other err,并且finally始终会进行输出
try:
print('code started')
#raise IndexError
except KeyError as e:
print('new code')
else:
print('other err')
finally:
print('finish')
# 未知行数的python读取
while True:
try:
s = input().strip()
print(s)
except EOFError as e:
break
# python在进行上下文协议进行管理时,只要类的魔法函数中有enter和exit,我们就可以使用with语句进行上下文管理
先写到这,后面再补充