Python学习记录(十五):面向对象进阶
instance
是否是实例
class Foo:
pass
f1 = Foo()
print(isinstance(f1,Foo)) # True
issubclass
是否是子类
class Foo:
pass
class Bar(Foo):
pass
print(issubclass(Bar,Foo)) # True
getattribute
无论是否存在该属性,都执行
# __getattribute__优先级更高
class Foo:
def __init__(self,x):
self.x=x
def __getattr__(self, item):
print('执行的是getattr')
def __getattribute__(self, item):
print('执行的是getattribute')
f1=Foo(10)
# 抛出异常时,才执行__getattr__
f1.xxxxxx
# 执行的是getattribute
# 模拟getattribute的默认情况
class Foo:
def __init__(self,x):
self.x=x
def __getattr__(self, item):
print('执行的是getattr')
def __getattribute__(self, item):
print('执行的是getattribute')
raise AttributeError('抛出异常了')
f1=Foo(10)
# 抛出异常时,才执行__getattr__
f1.xxxxxx
# 执行的是getattribute
# 执行的是getattr
getitem、setitem和delitem
与getattr、setattr和delattr的区别在于item系列需要对字典操作才能生效
class Foo:
def __getitem__(self, item):
print('getitem',item)
return self.__dict__[item]
def __setitem__(self, key, value):
print('setitem')
self.__dict__[key]=value
def __delitem__(self, key):
print('delitem')
self.__dict__.pop(key)
f1=Foo()
# setitem
f1['name']='bill'
f1['age']=18
# delitem
del f1['age']
# getitem
print(f1['name'])
str和repr
用于改变对象的字符串显示
str函数或print函数是执行obj.str()
repr函数或者交互式解释器Console是执行obj.repr()
# 默认情况下打印对象
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
f1=Foo('egon',18)
print(f1)
# 返回类名和内存地址
# <__main__.Foo object at 0x00000269FC43C740>
# 使用__str__修改输出字符串显示
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '名字是%s 年龄是%s' %(self.name,self.age)
f1=Foo('egon',18)
# 三种不同的调用方式
print(f1) # 名字是egon 年龄是18
x=str(f1)
print(x) # 名字是egon 年龄是18
y=f1.__str__()
print(y) # 名字是egon 年龄是18
# 使用__repr__修改输出字符串显示
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return 'str输出'
def __repr__(self):
return 'repr输出'
f1=Foo('egon',19)
# 若在交互式解释器Console里输入f1,也默认是repr
print(repr(f1)) # repr输出
print(str(f1)) # str输出
print(f1) # str输出
自定义格式化format
# 默认的字符串格式化
class Date:
def __init__(self,year,mon,day):
self.year=year
self.mon=mon
self.day=day
d1=Date(2024,7,20)
# 0表示是元组的第0个元素,即d1对象本身
x='{0.year}{0.mon}{0.day}'.format(d1)
y='{0.year}:{0.mon}:{0.day}'.format(d1)
z='{0.mon}-{0.day}-{0.year}'.format(d1)
print(x) # 2024720
print(y) # 2024:7:20
print(z) # 7-20-2024
# 自定义输出日期的格式化
# 定义三种不同的格式
format_dic={
'ymd':'{0.year}{0.mon}{0.day}',
'm-d-y':'{0.mon}-{0.day}-{0.year}',
'y:m:d':'{0.year}:{0.mon}:{0.day}'
}
class Date:
def __init__(self,year,mon,day):
self.year=year
self.mon=mon
self.day=day
# format_spec表示格式化的结构
def __format__(self, format_spec):
# 不输入格式或输入错误都按照默认格式
if not format_spec or format_spec not in format_dic:
format_spec='ymd'
fm=format_dic[format_spec]
return fm.format(self)
d1=Date(2024,7,20)
print(format(d1,'ymd')) # 2024720
print(format(d1,'y:m:d')) # 2024:7:20
print(format(d1,'m-d-y')) # 7-20-2024
# 不输入格式或输入错误都按照默认格式
print(format(d1)) # 2024720
print(format(d1,'xxxxxxx')) # 2024720
slots
__silots__是一个类变量,变量值可以是列表、元组或者可迭代对象,也可以是字符串。意味着所有实例只有一个数据属性。目的是节省内存,使得实例没有dict属性字典。假设一个类的数据属性不多,但有很多个实例,会导致生成多个dict属性字典,字典占用的内存空间大
class Foo:
__slots__=['name','age']
f1=Foo()
f1.name='bill'
f1.age=18
# 不能添加slots列表里没有的属性,也不能删除,因为没有dict字典,删除本身就是基于dict字典的操作
f1.gender='male'
del f1.age
print(f1.__dict__) # 报错:没有dict字典
print(Foo.__slots__) # ['name', 'age']
print(f1.__slots__) # ['name', 'age']
call
定义了__call__
方法的对象称为可调用对象,即该对象可以像函数一样被调用
class CallabeClass:
# 重载功能
def __call__(self):
print('CallabeObj')
CallabeObj = CallabeClass()
# 直接调用,如同调用函数一般
CallabeObj()
# CallabeObj