多态
# 当子类与父类都存在run() 函数时,子类run()覆盖了父类的run()方法,我们获得了继承的另一个好处也就是所谓的 多态 # 多态: # 什么是多态 . 一种类型的多种对象 # 例 有序数据类型 --> 多态 -->列表 字符串 元组 '''例''' class Animal: def cry(self): print('Animal') class Dog(Animal): def cry(self): print('Dog') dog = Dog() animal = Animal() print(isinstance(dog,Dog)) print(isinstance(dog,Animal)) print(isinstance(animal,Dog)) print(isinstance(animal,Animal)) # ps 子类的对象其数据类型也可以是其父类 """多态还常用来规范数据类型 ==> 类似于静态语言中的接口,但是没有强制性 """ """在动态类型叫做鸭子类型 ==> """ """ 当我们需要传入Dog、Cat、Tortoise……时,我们只需要接收Animal类型就可以了, 因为Dog、Cat、Tortoise……都是Animal类型,然后,按照Animal类型进行操作即可。 由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类, 就会自动调用实际类型的run()方法,这就是多态的意思:""" '''对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。 对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了'''
封装
# 类(class) 其实已经算是一种封装 --> 将逻辑和算法部分数据封装起来 # 深度封装 变量名前面加 __ 对变量进行封装 只能在类内部调用 .不是真正的封装而是将变量名变形 # 例 # __run() --> _foo__run() : __name --> _foo__name """ 变形在定义的时候发生""" # 封装的用处 # 1 隔离复杂度 class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() # 2 添加数据的限制 class Teacher: def __init__(self, name, age): # self.__name=name # self.__age=age self.set_info(name, age) def tell_info(self): print('姓名:%s,年龄:%s' % (self.__name, self.__age)) def set_info(self, name, age): if not isinstance(name, str): raise TypeError('姓名必须是字符串类型') if not isinstance(age, int): raise TypeError('年龄必须是整型') self.__name = name self.__age = age property ''' @property @*.setter @*.deleter 将函数封装为数据''' class School: def __init__(self): pass @property def select(self): return 'select' @select.setter def select(self): return 'select' @select.deleter def select(self): return 'select' s1 = School() print(s1.select) # 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的, # 这种特性的使用方式遵循了统一访问的原则 class Foo: def __init__(self, val): self.__NAME = val # 将属性隐藏起来 @property def name(self): return self.__NAME @name.setter def name(self, value): if not isinstance(value, str): # 在设定值之前进行类型检查 raise TypeError('%s must be str' % value) self.__NAME = value # 通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): raise PermissionError('Can not delete') f = Foo('lili') f.name f.name = 'LiLi' # 触发name.setter装饰器对应的函数name(f,’Egon') # f.name = 123 # 触发name.setter对应的的函数name(f,123),抛出异常TypeError # del f.name # 触发name.deleter对应的函数name(f),抛出异常PermissionError
类的内置函数
# 反射 ''' getattr() setattr() hasattr() delattr() ''' # 输入的字符串对对象进行操作 # 设 输入字符串为'name' # hasattr(obj,'name) 检测obj中是否存在name属性 # getattr(obj,'name) 得到obj中name属性 一般与hasattr连用 # setattr(obj,'name) 建立obj中的name属性 """练习""" class Student: def __init__(self): cmd = input('cmd') if hasattr(self, cmd): func = getattr(self, cmd) func() def name(self): print('name') stu = Student() cmd = input('cmd') if hasattr(stu, cmd): func = getattr(stu, cmd) func() setattr(stu, 'age', 18) # 内置方法 # __str__ # print() # __del__ # 回收用于回收系统资源 # __ep__ == # # __add__ +
类的数据获取
# isinstance(obj,Class)
# 判断obj是否是 Class 的子类
dir()
# 获取对象的所有属性和方法
class Cla:
def foo(self):
pass
class Gra(Cla):
def bar(self):
pass
print(Gra.__dict__)
a = Gra()
print(dir(Cla))
print(dir(a))
#
.
绑定方法未绑定方法
"""绑定方法"""
'''类一'''
# 默认绑定给对象
# self
'''类二'''
classmethod
# 调用classmethod 将方法绑定给类
class Foo:
@classmethod
def func(cls):
print('func_1')
Foo.func()
'''未绑定方法'''
staticmethod
# 调用staticmethod 使函数不绑定 类与对象都可以调用
class Foo:
@classmethod
def func(cls):
print('func_1')
@staticmethod
def f2():
print('f2')
bar = Foo()
Foo.f2()
bar.f2()