python基础 day26 面向对象-super方法、封装、property装饰器、反射

一、super 方法

class A:
    def func(self):
        print('A')
class B(A):
    def func(self):
        super().func()
        print('B')
class C(A):
    def func(self):
        super().func()
        print('C')
class D(B,C):
    def func(self):
        super().func()
        print('D')
print(D.mro())
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
D().func()
'''
A
C
B
D
'''
  • super 是按照mro顺序来寻找当前类的下一个类的
  • 在python3中不需要传参数,自动就帮我们寻找当前类的mro顺序的下一个类中的同名方法
  • 在python2中的新式类中,需要我们主动传递参数super(子类的名字, 子类的对象).函数名(),这样才能够帮我们调用到这个子类的mro顺序的下一个类中的方法。
  • 在python2的经典类中,并不支持使用super来找下一个类。

即上面代码在D类中找super的func,可以写super().func(),也可写成super(D, self).func(),但是在python2中必须写成super(D, self).func()

在单继承的程序中,super就是找父类。

class User:
    def __init__(self, name):
        self.name = name

class VIPUser(User):
    def __init__(self, name, level, start_time, end_time):
        super().__init__(name)
        self.level = level
        self.start_time = start_time
        self.end_time = end_time

jason = VIPUser('jason', 10, '05-03', '06-03')
print(jason.__dict__)
# {'name': 'jason', 'level': 10, 'start_time': '05-03', 'end_time': '06-03'}

二、封装

封装:把属性和方法装起来

广义:把属性和方法装起来,外部不能直接调用,要通过类的名字调用

狭义:把属性和方法藏起来,外部不能调用,只能在内部偷偷调用

  • 给一个名字前面加上双下划线的时候,这个名字就变成了一个私有的
    所有的私有的内容或名字都不能在类的外部直接调用,只能在类的内部使用
class User:
    def __init__(self, username, password):
        self.usr = username
        self.__pwd = password  # 私有的实例变量/私有的对象属性

jason = User('jason', '123456')
print(jason.usr)  # jason
print(jason.__pwd)  # 此时会报错
  • 如果想要查看或者修改私有的实例变量只能在类中定义函数来查看
class User:
    def __init__(self, username, password):
        self.usr = username
        self.__pwd = password  # 私有的实例变量/私有的对象属性
    def get_pwd(self):
        return self.__pwd
    def change_pwd(self):
        old_pwd = input('enter old password:')
        if old_pwd == self.__pwd:
            new_pwd1 = input('enter new password:')
            new_pwd2 = input('enter new password again:')
            if new_pwd1 == new_pwd2:
                self.__pwd = new_pwd2
jason = User('jason', '123456')
print(jason.usr)  # jason
print(jason.get_pwd())  # 123456
jason.change_pwd()
print(jason.get_pwd())

同理,也可以有私有的静态变量

class Map:
    country = 'china'
    __language = 'chinese'
    def get(self):
        return Map.__language

a = Map()
print(a.country)  # china
print(a.__language)  # 报错
print(a.get())  # chinese

同理,也可以有私有的方法

import hashlib
class User:
    def __init__(self,name,password):
        self.usr = name
        self.__pwd = password  # 私有的实例变量
    def __md5_pwd(self):  # 私有的方法
        ret = hashlib.md5()
        ret.update(self.__pwd.encode('utf-8'))
        return ret.hexdigest()
    def get_pwd(self):
        return self.__md5_pwd()

jason = User('jason', 'abcd')
print(jason.get_pwd())

所有的私有化都是为了让用户不在外部调用类中的某个名字
如果完成私有化,那么这个类的封装度就更高了,封装度越高各种属性和方法的安全性也越高 ,但是代码越复杂

私有的内容能不能被子类使用? 不能

class Foo:
    def __init__(self):
        self.func()
    def func(self):
        print("in Foo")
class Son(Foo):
    def func(self):
        print("in Son")

Son()  # in Son
class Foo:
    def __init__(self):
        self.__func()
    def __func(self):
        print("in Foo")
class Son(Foo):
    def __func(self):
        print("in Son")

Son()  # in Foo
class Foo:
    def __func(self):
        print("in Foo")
class Son(Foo):
    def __init__(self):
        self.__func()
Son()  # 报错

三、类中的装饰器

  • property

property 应用场景一:把一个方法伪装成属性,在调用这个方法时不需要加()就可以直接得到返回值

import time
class Person:
    def __init__(self, name, birth):
        self.name = name
        self.birth = birth
    @property
    def age(self):  # 装饰的这个方法,不能有参数
        return time.localtime().tm_year - self.birth

jason = Person('jason', 1996)
print(jason.age)

property 应用场景二:和私有属性合作

class User:
    def __init__(self,username,password):
        self.usr = username
        self.__pwd = password
    @property
    def pwd(self):
        return self.__pwd

jason = User('jason', 1234)
print(jason.pwd)

property 进阶

class Goods:
    discount = 0.8
    def __init__(self,name,origin_price):
        self.name = name
        self.__price = origin_price
    @property
    def price(self):
        return self.__price * self.discount
    @price.setter
    def price(self,new_value):
        if isinstance(new_value,int):
            self.__price = new_value

apple = Goods('apple', 10)
print(apple.price)  # 调用的是被@property装饰的price
apple.price = 20  # 调用的是被setter装饰的price
print(apple.price)

三、反射

反射使用场景
1.反射对象的实例变量
2.反射类的静态变量/绑定方法/其他方法
3.模块中的所有变量:导入的模块/当前.py文件

语法

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def func(self):
        print('aloha')

j = Person('jason', 24)
d = Person('dog', 5)
ret = getattr(j, 'name')
print(ret)
ret = getattr(d, 'func')
ret()

使用反射实现归一化

import sys
class Wechat:
    def __init__(self, name):
        self.name = name
    def pay(self, money):
        print(f'{self.name}通过微信支付了{money}元。')
class Alipay:
    def __init__(self, name):
        self.name = name
    def pay(self, money):
        print(f'{self.name}通过支付宝支付了{money}元。')


def pay(name, price, type):
    class_name = getattr(sys.modules['__main__'], type)
    obj = class_name(name)
    obj.pay(price)

pay('jason', 400, 'Wechat')

反射的另一个函数 hasattr

class A:
    def __init__(self):
        self.name = 'jason'
        self.age = 24
    def func(self):
        return 666
j = A()
if hasattr(j,'name'):
    print(getattr(j,'name'))
if hasattr(j,'age'):
    print(getattr(j,'age'))
if hasattr(j,'sex'):
    print(getattr(j,'sex'))
posted @ 2020-05-23 15:27  Jason857  阅读(170)  评论(0编辑  收藏  举报