在多继承中:严格按照mro顺序来执行
super是按照mro顺序来寻找当前类的下一类
在py2中的新式类中,需要我们主动传递参数super(子类的名字,子类的对象). 函数名()
这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法
在py2的经典类中,并不支持使用super来找下一个类
class A: def func(self): print('is A') class B(A): def func(self): super().func() print('is B') class C(A): def func(self): super().func() print('is C') class D(B, C): def func(self): super().func() print('is D') d = D() print(D.mro()) d.func() # 输出 [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] is A is C is B is D
在单继承中:super就是找父类
class Foo: def func(self): print('is Foo') class Son(Foo): def func(self): super().func() # 先找父类的func方法--->打印is Foo print('is Son') # 在打印自己的is Son s = Son() s.func() # 输出 is Foo is Son
二、封装
封装:就是把属性或方法装起来
广义:把属性和方法装起来,外面不能直接调用了,要通过类的名字来调用
狭义:把属性和方法藏起来,外面不能调用,只能在内部偷偷调用
所有的私有化都是为了让用户不在外部调用类中的某个名字
如果完成私有化,那么这个类的封装度就更高了,封装度越高各种属性和方法的安全性也越高,但代码越复杂
封装的语法:
1、给一个名字前面加上了双下滑线的时候,这个名字就变成了一个私有的
2、所有私有的内容或者名字都不能在类的外部调用,只能在类的内部使用了
# 不想让你看也不想让你改 class User: def __init__(self, name, pwd): self.name = name self.__pwd = pwd # 私有的实例变量/私有的对象属性 use = User('admin', 'abc123') print(use.__pwd) # 报错 print(use.pwd) # 报错
在外部查看和修改私有对象属性:
# 可以给你看也可以给你改,但你要用我自定义的方法看,和按照我的规则改
class User: def __init__(self, name, pwd): self.name = name self.__pwd = pwd def get_pwd(self): # 表示用户不能改只能看 return self.__pwd def change_pwd(self, count): # 表示用户必须调用我们自定义的修改方式来进行变量的修改 if count.isdigit(): # 是数字我就改,不是我就不改,还是原样 self.__pwd = count return self.__pwd use = User('admin', 'abc123') print(use.get_pwd()) use.change_pwd('123456789') # 实际上是调用了对象内部的函数进行修改 print(use.get_pwd()) # 输出 abc123 123456789
1、加了双下划线的名字为啥不能从外部调用了?
class User: __Country = '中国' # 私有的静态变量 __job = '攻城狮' # 私有的静态变量 def func(self): # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形(_User__Country) print(User.__Country) # __Country已经变形成(_User__Country) print(User.__dict__) User().func() ''' 此时,变量做了一个转换所以在外部找不到了,如果外部调用转换后的变量还是可以调用的。(但不介意这样用) __Country ---> _User__Country __job ---> _User__job ''' # 输出 {..., '_User__Country': '中国', '_User__job': '攻城狮',...} 中国
2、私有的内容不能被子类使用。
class Foo: # __func:为私有的绑定方法 def __func(self): # 3、而父类Foo中的私有方法已经变形为_Foo__func了不是_Son__func方法了 print('is Foo') class Son(Foo): def __init__(self): self.__func() # 2、子类__func方法变形成了_Son__func方法了,没有会去父类Foo找 Son() # 1、实例化时,自动调用init方法 # 输出 报错 AttributeError: 'Son' object has no attribute '_Son__func'
3、在其他语言中的数据的级别都有哪些?在python中有哪些?
public 公有的 类内类外都能用,父类子类都能用 python支持
protect 保护的 类内能用,父类子类都能用,类外不能用 python不支持
private 私有的 本类的类内部能用,其他地方都不能用 python支持
三、内置的装饰器:property,setter,delter
property方法:把一个方法伪装成属性,在掉用这个方法的时候不需要加()就可以直接得到返回值。
方法一:
from math import pi class Circle: def __init__(self, r): self.r = r @property # 把area()函数伪装成属性 def area(self): print(pi * self.r ** 2) # 实例化一个半径为5的圆 y = Circle(5) y.area # 被伪装后圆的面积函数不用加() # 输出 78.53981633974483
方法二:和私有的属性合作的
class User: def __init__(self, name, pwd): self.name = name self.__pwd = pwd @property def pwd(self): print(self.__pwd) u = User('小杨', '1234') u.pwd # 输出 1234
setter方法:对伪装方法可以使用和属性一样的 = 号了
class User: def __init__(self, name, pwd): self.name = name self.__pwd = pwd @property def pwd(self): print(self.__pwd) @pwd.setter def pwd(self, count): print('我这里setter被调用了') if isinstance(count, int): # 满足条件(count是int类型)我就修改 self.__pwd = count u = User('小杨', '1234') u.pwd = 1111 # 可以使用 = 进行满足条件的赋值了,不满足原样不变 u.pwd # 输出 我这里setter被调用了 1111
delter方法:(了解)
class User: def __init__(self, name, pwd): self.name = name self.__pwd = pwd @property def pwd(self): print(self.__pwd) @pwd.deleter def pwd(self): print('我这里delter被调用了') u = User('小杨', '1234') del u.pwd # 输出 我这里delter被调用了
四、反射getatter、hasatter
反射:用字符串类型的名字来操作这个名字对应的函数、实例变量、绑定方法、各种方法
在明明知道一个变量的字符串数据类型的名字,想直接调用它,但是调不到的时候,用反射
getattr方法:
1、反射对象的:实例变量、绑定方法
class Person: def __init__(self, name , age): self.name = name self.age = age def func(self): print('is func') # 实例化一个对象 Bob = Person('鲍勃', 18) print(getattr(Bob, 'name')) # 反射对象的实例变量 getattr(Bob, 'func')() # 反射对象的绑定方法 # 输出 鲍勃 is func
2、反射类的:静态变量
class Person: attribute = '会思考' def __init__(self, name, age): self.name = name self.age = age def func(self): print('is func') print(getattr(Person, 'attribute')) # 反射类的静态变量 # 输出 会思考
3、反射模块中的所有变量
反射被导入的模块:
# 模块 my_module.py 内容 count = '模块 my_module.py 中count的内容' def func(): return '这是 my_module 模块中的 func 函数' # -------------------------------------------------------------- import my_module ret = getattr(my_module, 'count') ret2 = getattr(my_module, 'func') print(ret) print(ret2()) # 输出 模块 my_module.py 中count的内容 这是 my_module 模块中的 func 函数
4、反射当前执行的py文件 ——> 当前脚本
import sys lis = [1, 2, 3] def func(): return 'is func' ret1 = getattr(sys.modules['__main__'], 'lis') # 反射当前脚本的变量 ret2 = getattr(sys.modules['__main__'], 'func') # 反射当前脚本的函数 print(ret1) print(ret2()) # 输出 [1, 2, 3] is func
hasattr方法:
hasattr 方法其实是和 getattr 方法成对使用的,主要用来判断反射变量是否存在
class Person: def __init__(self, name, age): self.name = name self.age = age def func(self): print('is func') Bob = Person('鲍勃', 18) print(hasattr(Bob, 'name')) # name 变量名存在就返回True print(hasattr(Bob, 'sex')) # sex 变量不存在就返回False if hasattr(Bob, 'func'): # 判断 func 是否存在 # 存在,判断 func 是否可以被调佣(用 callable 判断是否是函数) if callable(getattr(Bob, 'func')): getattr(Bob, 'func')() # 是函数就加括号() getattr(Bob, 'func') # 不是就不用加括号() # 输出 True False is func
五、反射例子
反射例子一:
import sys class WeChat: def __init__(self, username): self.username = username def pay(self, money): print(f'{self.username}通过微信充值了{money}') class Alipay: def __init__(self, username): self.username = username def pay(self, money): print(f'{self.username}通过支付宝充值了{money}') # 简化归一化设计: def pay(username, money, kind): class_name = getattr(sys.modules['__main__'], kind) # 输入的类名,反射本地的类 obj = class_name(username) # 用上一步反射的类来创建实例化对象 obj.pay(money) pay('小杨', 200, 'WeChat') # 输出 小杨通过微信充值了200
反射例子二:
用户输入用户名密码性别
实例化对象
用户任意输入内容 : 不能用异常处理
如果输入的是属性名 打印属性值
如果输入的是方法名 调用方法
如果输入的什么都不是 不做操作
class User: def __init__(self, name, pwd, sex): self.name = name self.pwd = pwd self.sex = sex def eat(self): print(f'{self.name},在吃饭') def sleep(self): print(f'{self.name},在睡觉') Bob = User('鲍勃', 18, '男') count = input('需要操作的方法:') if hasattr(Bob, count): if callable(getattr(Bob, count)): getattr(Bob, count)() print(getattr(Bob, count))
反射例子三:
循环这个列表 显示 序号 用户要做的操作
用户输入序号
你通过序号找到对应的login或者register方法
先实例化
调用对应的方法,完成登录或者注册功能
class Authentic: ll = [('登录', 'login'), ('注册', 'register')] def __init__(self, username, pwd): self.username = username self.pwd = pwd def register(self): print('注册成功:') def login(self): print('登录成功:') Bob = Authentic('python', 123456) for index, func in enumerate(Authentic.ll, 1): print(index, func[0]) count = int(input('请选择需要操作的序号>>:')) if hasattr(Bob, Authentic.ll[count - 1][1]): getattr(Bob, Authentic.ll[count - 1][1])() # 输出 1 登录 2 注册 请选择需要操作的序号>>:2 注册成功: