面向对象(二)记忆部分
一、新式类和经典类
区别:继承了python内置类的时候,才是新式类。其他的都是经典类
经典类 :通过type查看到的实例类型都叫做instance
类和实例之间只能够通过__class__属性进行关联
新式类 :通过type查看到的实例类型就是类名
[root@wh ~]# python2
Python 2.7.5 (default, Nov 16 2020, 22:23:17
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on l
Type "help", "copyright", "credits" or "lice
>>> class A:pass
...
>>> a = A()
>>> type(a)
<type 'instance'>
>>> a.__class__
<class __main__.A at 0x7fa8732ee258>
---------------------------------------------
[root@wh ~]# python3
Python 3.6.8 (default, Nov 16 2020, 16:55:22)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class '__main__.A'>
多重继承顺序的区别
经典类:深度优先算法,从左至右,一条路走到底
新式类:c3算法
class A:
def test(self):
print("from A")
class B(A):
def test(self):
print("from B")
class C(A):
def test(self):
print("from C")
class D(B):
def test(self):
print("from D")
class E(C):
def test(self):
print("from E")
class F(D,E):
# def test(self):
# print("from F")
pass
f = F()
f.test()
#逐个注释进行验证
#经典类:F--> D --> B --> A --> E --> C
#新式类:F--> D --> B --> E --> C --> A
#c3算法:
# 首先将自身类加入到本序列,然后对继承序列的元素依次判断
# 若某元素不在其他序列或者它是所有继承序列的第一个,那么就把这个元素提取到本序列
二、实例方法、静态方法和类方法
属性:对象的描述信息
静态属性 – 类属性
普通属性 – 实例属性方法:对象的行为
实例方法
静态方法
类方法
class A():
name = "changsha" #静态属性
def __init__(self):
self.country = "china" #普通属性
#普通(实例)方法
#接收的第一个参数,就代表实例本身
def normal_method(self,name):
print("nomal:")
print(self.name,name)
#使用classmethod修饰的方法,称为类方法
#接收的第一个参数是类
@classmethod
def class_method(cls,name):
print("class_method:".center(30,'*'))
print(type(cls), cls)
print(cls.name, name)
#使用staticmethod修饰的方法,称为静态方法
#可以接受参数也可以不接受参数,参数不代表实例也不代表类
@staticmethod
def static_method(name):
print("static_method:")
print(A.name, name)
a = A()
#通过实例调用类方法,静态方法,实例方法 都可以
a.normal_method("nomalmethod")
a.class_method("classmethod")
a.static_method("staticmethod")
#通过类去调用类方法、静态方法、实例方法
#通过类调用实例方法的时候,一定要传一个实例进去
A.normal_method(a,"normal_method")
A.class_method("classmethod")
A.static_method("staticmethos")
三、 python的下划线
class Parent:
'''
this is parent
class
'''
tmp = "tmp" #普通成员
_min = 1 #保护成员
__max = 10 #私有成员
def __init__(self):
self.name = "sc"
self._age = 4
self.__desc = "it" #--> self._Parent__desc
def __make(self):
print("这是一个私有方法")
print(self.__desc) #--> self._Parent__desc
def _protectmake(self):
print("这是一个保护方法")
def show(self):
print(self.__max, self.__desc)
print("这是一个普通方法")
class Child(Parent):
def show(self):
print(self.__max)
#Parent
#类属性 tmp, _min, __max
#实例属性 name, _age, __desc
#方法 __make, _protectmake, show
p = Parent()
c1 = Child()
# 访问普通成员和保护成员
print(p.tmp, c1.tmp)
print(p._min, c1._age, c1._min)
p._protectmake()
c1._protectmake()
#访问私有成员 __max __desc __make
# print(p.__max)
#AttributeError: 'Parent' object has no attribute '__max'
# print(p.desc)
#'Parent' object has no attribute 'desc'
p.show() #是可以访问到的,类的内部会将self.__max 解释成 self._Parent__max
# c1.show()
#'Child' object has no attribute '_Child__max'
#查看实例空间有哪些属性
print(p.__dict__)
#{'name': 'sc', '_age': 4, '_Parent__desc': 'it'}
# print(p.__max)
#AttributeError: 'Parent' object has no attribute '__max'
print(p._Parent__max) #python中的私有其实是一种伪私有,就是将双下划线开头的标识符改了一个名字--》_类名__标识名
#10
p.__make()
# 这是一个私有方法
# it
p = Parent()
c1 = Child()
-----------------------
#python中常用的下划线
#查看对象的属性和方法
print(dir(p))
print(p.__dir__())
#文档注释
print(Parent.__doc__)
#print(help(Parent))
# 查看对象和类空间
print(p.__dict__)
print(Parent.__dict__)
#查看对象属于哪个类
print(p.__class__)
#<class '__main__.Parent'>
#类名
print(Parent.__name__)
#Parent
#查看父类
print(Child.__bases__)
#(<class '__main__.Parent'>,)
#对象的hash值
print(c1.__hash__())
#3500883
四、 常用的魔术方法
什么是魔术方法?
在python中,所有以双下划线__包起来的方法,统称为 Magic Method(魔术方法)
它是一种特殊的方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行魔术方法在类或对象的某些事件触发后会自动执行,让类具有神奇的"魔力"
如果希望根据自己的程序定制自己特殊功能的类,那么就需要对这些方法进行重写Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的
4.1 new、init、del、__call__方法的使用
# 构造函数(__new__/__init__)
__new__:创建实例
__init__:初始化实例
# 析构函数(__del__)
在实例释放、销毁的时候自动执行的,通常用于做一些收尾工作,如关闭数据库连接,关闭打开的临时文件
# 调用方法(__call__)
把类实例化后的对象当做函数来调用的时候自动被调用
class ATM:
def __del__(self):
print("执行del")
def __call__(self, name, age):
print(f"my name id {name}, my age is {age}")
#a = ATM()
#执行del
#程序执行完了,会释放内存,删除实例a,并执行__del__
a = ATM() #程序没有执行完,不会执行__del__
del a #删除实例a,然后执行__del__
print("删除a")
# 执行del
# 删除a
# __call__
a = ATM()
a("sc",4) #有__call__方法,实例可以像函数一样进行调用
4.2 str 、__repr__方法的使用
# __str__ __repr__
# 返回对象的描述信息
# __str__ 默认调用的就是__repr__
# __str__ 给用户看的
# __repr__ 更加官方的说明,给程序员看的(交互式环境)
>>> class A:
... def __str__(self):
... return "str...A"
... def __repr__(self):
... return "repr...A"
...
>>> a = A()
>>> print(a)
str...A
>>>
>>> result = str(a)
>>> print(result)
str...A
>>> a
repr...A
>>> class A:
... def __repr__(self):
... return "repr...A"
...
>>> a = A()
>>> print(a)
repr...A
>>> a
repr...A
应用:
try:
a = []
print(a[1])
except IndexError as e:
print(e)
#list index out of range
#自定义异常类
class error(Exception):
def __str__(self):
return "list内元素长度超过10个"
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
try:
if len(lst) > 10:
raise error
except error as e:
print(e)
#方法二
class error(Exception):
def __str__(self):
return "list内元素长度超过10个"
e = error()
try:
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
if len(lst) > 10:
raise IndexError
except IndexError:
print(e)
----------------------
class error2(Exception):
def __str__(self):
return "消息长度小于8"
message_str = input("请输入消息:")
try:
if len(message_str) < 8:
raise error2
except error2 as a:
print(a)
------------------------
import time
class Tst(object):
def __init__(self, n):
self.n = n
self._created_time = time.time()
def __str__(self) -> str:
# 以友好的方法输出对象
return f"Tst:{self.n}"
def __repr__(self) -> str:
# 正式输出 => 以友好的方法输出对象
return f"<Tst:{self.n}>"
# def __lt__(self, other):
# return self._created_time < other._created_time
t1 = Tst(1)
time.sleep(1)
t2 = Tst(2)
time.sleep(1)
t3 = Tst(3)
time.sleep(1)
print(t1)
# <__main__.Tst object at 0x0000000001DC8430>
# => __str__ => Tst:1
mylist = [t3, t1, t2]
print(mylist)
# 定义了__repr__ => [<Tst:3>, <Tst:1>, <Tst:2>]
# 请按创建时间给mylist排序:mylist排序结果 =》 [t1, t2, t3]
mylist = sorted(mylist, key=lambda x: x._created_time)
# mylist = sorted(mylist) # 本质元素和元素之间 <
# 给类添加一个__lt__方法
print(mylist) # => [<Tst:1>, <Tst:2>, <Tst:3>]
4.3 getitem、setitem、__delitem__方法的使用
让对象以字典的形式去设置或者获取参数
用在设置或者配置属性的时候使用
class A:
def __init__(self):
self.data = {}
def __getitem__(self, key):
print("get data:")
return self.data.get(key,0) #获取value值,如果没有,默认值为0
def __setitem__(self, key, value):
print("set data:")
self.data[key] = value
def __delitem__(self, key):
print("delete data:")
del(self.data[key])
a = A()
a["key"] = "value" #调用__setitem__
#set data:
print(a["key"]) #调用__getitem__
# get data:
# value
a["k1"] = "v1"
#set data:
a["k2"] = "v2"
#set data:
print(a["k3"])
#get data:
#0
print(a.data)
#{'key': 'value', 'k1': 'v1', 'k2': 'v2'}
del a["key"] #调用__delitem__
print(a.data)
# delete data:
# {'k1': 'v1', 'k2': 'v2'}
4.4 add、__gt__方法的使用
# 定义对象的加号行为
import time
class A:
def __init__(self, num):
self.time = time.time()
self.num = num
def __add__(self, x):
print("this is add")
return self.num + x
def __gt__(self, other):
print("this is gt")
return self.time > other.time #比较创建实例的时间和其他实例的创建时间
a1 = A(5)
b = a1 + 6 #调用__add__
#this is add
print(b)
#11
time.sleep(1)
a2 = A(4)
print(a1 > a2) #调用__gt__
# this is gt
# False
五、python自省
hasattr、setattr、getattr、delattr
#python自省
print(hasattr(math, "xx")) #判断math有没有xx属性
print(setattr(math, "xx", 1))#设置math的xx属性为1
print(getattr(math, "xx")) #获取math的xx属性
print(delattr(math, "xx")) #删除math的xx属性
练习:根据choose的值,调用不同的函数,按‘q’退出
class A:
name = "sc"
def func1(self):
print("i am func1")
def func2(self):
print("i am func2")
a = A()
# print(dir(a.func1()))
# print(dir(a.name))
while 1:
choose = input("please input function:")
if choose == 'q':
break
elif hasattr(a,choose):
result = getattr(a,choose)
if hasattr(result, "__call__"):
result()
else:
print(result)
else:
print("没有这个函数")
六、python元类
创建类的类,称之为元类,type是最上层的元类
# type:创建类
class A:
pass
a = A()
print(type(a))
# <class '__main__.A'>
print(type(A))
# <class 'type'>
用type手动创建类
# 普通定义类
class Animal:
def __init__(self, name):
self.name = name
def eat(self):
print("i am eating...")
# 用type创建类
# 第一个参数:类名 字符串
# 第二个参数:继承关系 元组
# 第三个参数:方法和属性 字典
def init(self, name):
self.name = name
def eat(self):
print("i am eating...")
Animal = type("Animal",(object,),{"__init__":init, "eat":eat})
a1 = Animal("sc1")
print(a1.name)
#sc1
元类的使用
拦截类的创建,实现自定义类
class MyMate(type):
def __new__(cls, name, bases, attrs):
if "ufo" not in attrs:
raise TypeError("必须设置ufo属性")
return type.__new__(cls, name, bases, attrs)
class A(metaclass = MyMate):
ufo = "sc"
print(A)
type object
面向对象里面有两种关系
1.继承关系 object是所有类的父类,是最顶层的类
2.创建关系 实例与类的关系 type是最顶层的类
print(type(object))
# <class 'type'>
print(type(type))
# <class 'type'>
print(object.__bases__)
# ()
print(type.__bases__)
# (<class 'object'>,)
object = type(object)
#相当于一种鸡生蛋,蛋生鸡的关系 先有鸡还是先有蛋
七、抽象基类
定义了接口规范,子类必须实现抽象基类父类里的抽象方法(@abstractmethod),不是抽象方法可以不用实现
抽象基类不能实例化
from abc import ABC, abstractmethod
class Animal(ABC):
#定义抽象方法
@abstractmethod
def eat(self):
pass
def drink(self):
pass
class Dog(Animal): #子类必须实现父类里的抽象方法
#pass #会报错,子类里面没有实现抽象方法eat
def eat(self):
print("dog is eating...")
dog = Dog()
#a = Animal()
#抽象基类不能进行实例化