18,类的三大特征(封装)

1,封装


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

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

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

私有化:所有的私有化都是为了让用户不在外部调用类中的某个名字
如果完全私有化 那么这个类的封装度就更高了 封装度越高各种属性和方法的安全性也更高 但是代码越复杂。
使用私有类的三种方情况:
    1、不能看也不能改
    2、可以看不能改
    3、可以看也可以改 但是要按照我的要求改
封装的语句:
    1、私有的静态变量
    2、私有的实例变量
    3,、私有的绑定方法
私有的特点:
    1、能不能在类的内部使用?
    2、能不能在类的外部使用?
    3、能不能在类的子类中使用?
原理:
    1、如何变形?
    2、在哪里定义的时候变形?
类中变量的级别,哪些是python支持的,哪些是python不支持的:
    1、公有的
    2、保护的
    3、私有的

广义例子

class A:
    a = 1
    b = 2
print(A.b)  # 通过类名封装,广义封装

狭义封装(私有化)

class User:
    def __init__(self, name, password):
        self.user = name
        self.__pwd = password      # 给一个名字前面加上一双下划线的时候,这个名字就变成了一个私有的

    def pwd(self):      # 通过对象名调用该方法可以查看私有的属性 ,用户只能看不能改
        return self.__pwd

    def change_pwd(self):pass  # 表示用户必须用我们自定义的修改方式来进行变量的修改  私有+change()方法实现

alex = User('alex','123456')
# print(alex.__pwd)       # 报错
print(alex.pwd())       # 123456
给一个变量名字前面加上了下划线的时候,这个名字就变成了一个私有的
所有的私有的内容或则名字都不能在类的外部调用,只能在类的内部使用

例;

class User:
    __Country = 'China'  # 私有的静态变量
    def func(self):     # 在类的内部可以调用
        return self.__Country

print(User.Country)     # 报错  在类的外部不能调用
print(User.__Country)     # 报错
user = User()
print(user.func())


# 方法私有化
import hashlib


class User:
    def __init__(self, name, pwd):
        self.user = name
        self.__pwd = pwd  # 私有的实例变量

    def __get_md5(self):  # 私有的方法
        md5 = hashlib.md5(self.user.encode('utf-8'))
        md5.update(self.__pwd.encode('utf-8'))
        return md5.hexdigest()

    def getpwd(self):
        return self.__get_md5()


alex = User('alex', '123456')
print(alex.getpwd())
# 94e4ccf5e2749b0bfe0428603738c0f9
# 526996078c7a54cf8bbc10a17cf11844

边缘知识

1、加了下划线的名字为什么不能从类的外部调用?
2、私有的内容能不能被子类使用?
3、在其他语言中的数据的级别都由哪些?在python中有哪些?
# 1、加了下划线的名字为什么不能从类的外部调用?
class User:
    __Country = 'China'     # 私有的静态变量
    def func(self):
        print(self.__Country)       # 在类的内部使用的时候,自动的把当前这句话所在的类的名字拼在私有变量前完成变形
    def country(self):
        return self.__Country
print(User.__dict__)
print(User().country())         # 正常情况的找
print(User._User__Country)      # 硬找

# # 只是把 '__Country' ---->  '_User__Country'
# User.__aaa = 'bbb'      # 在外部根本不能定义私有的概念

# 2、私有的内容能不能被子类继承使用? 不能。
class Foo(object):
    def __init__(self):
        self.func()

    def func(self):
        print('in Foo')


class Son(Foo):
    def func(self):
        print('in Son')


Son()     # in Son   结果分析见图封装-边缘知识-2(01).png
#
#
class Foo(object):
    def __init__(self):
        self.__func()

    def __func(self):
        print('in Foo')


class Son(Foo):
    def __func(self):
        print('in Son')


Son()     # in Foo    结果分析见图封装-边缘知识-2(02).png

# 3、在其他语言中的数据的级别都由哪些?在python中有哪些?
'''
public  公有的 类内类外都能使用,父类子类都能用        python支持
protect  保护的 类内使用,父类子类都能用,类外不能使用        python不支持
private  私有类 本类的类内部都能使用,其他地方都不能使用       python支持
'''

2,property装饰器

property装饰器(内置函数)
做了什么?
    setter
    delter

property的第一个应用场景

将一个方法伪装成一个属性 print(c1.area)就不需要用括号调用了
from math import pi


class Circle:
    def __init__(self, r):
        self.r = r

    @property  # 将一个方法伪装成一个属性 print(c1.area)就不需要用括号调用了
    def area(self):
        return pi * self.r ** 2


c1 = Circle(5)
print(c1.r)
print(c1.area)
变量的属性和方法?
    # 属性:圆形的半径/圆形的面积
    # 方法:登录/注册  一个动作
import time

class Person:
    def __init__(self, name):
        self.name = name
        self.birth_year = 1999
        self.birth_mon = 1

    @property
    def age(self):      # 装饰的这个方法 不能有参数
        age = time.localtime().tm_year - self.birth_year
        month = time.localtime().tm_mon - self.birth_mon
        return (f'{self.name}已经出生{age}年零{month}月')


taibai = Person('taibai')
print(taibai.age)

property的第二个应用场景

一般和私有的属性合作的,将一个方法伪装成一个属性只能看不能改
class User:
    def __init__(self,user,pwd):
        self.user = user
        self.__pwd = pwd

    @property
    def pwd(self):
        return self.__pwd

alex = User('alex', '123456')
print(alex.pwd)


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

apple = Goods('apple', 5)
print(apple.price)

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 type(new_value) is int:      # isinstance(new_price,int) 也可以
            self.__price = new_value

    @price.deleter
    def price(self):
        print('执行我了')       # del self.__price 这个是真的删除的语句

apple = Goods('apple', 5)
print(apple.price)      # 4.0  调用的是被@property装饰的price
apple.price = 10        # 调用的是被setting装饰的price,此时可以修改苹果的价格
print(apple.price)      # 8.0
del apple.price         # 并不能真的删除什么,只是调用了对应的被@price.deleter装饰的方法而已

3,反射

用字符串数据类型的名字 来操作这个名字对应的函数\实例变量\绑定方法\各种方法
需要的场景:
有些时候你明明知道一个变量的字符串数据类型的名字,你想直接调用它,但是调不到
这个时候需要用到反射

        比如:

1,反射对象的实例变量/绑定方法

2,反射类的静态变量/其他方法

3,模块中的所有变量

         1,被导入的模块

         2,当前执行的py文件--脚本

反射的基本内容
    1,hasattr
    2,getattr
    3,几种情况
        反射模块中的内容
        反射脚本中的内容
        反射对象的属性或者绑定方法
        反射类的静态变量
    4,callable()
    实际的例子 --- 归一化设计
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def qqxing(self):
        print('qqxing')


alex = Person('alex', 50)
wusir = Person('wusir', 30)
ret = getattr(alex, 'age')
print(ret)  # 50
ret = getattr(wusir, 'age')
print(ret)  # 30
ret = getattr(wusir, 'qqxing')      # 相当于这个ret得到的是qqxing的内存地址
ret()       # qqxing
import a

print(a.Wechat)
print(a.Alipay)
# 对象名.属性名 ==> getattr(对象名,'属性名')
# a.Alipay ==> getattr(a,'Alipay')
print(getattr(a, 'Alipay'))
print(getattr(a, 'Wechat'))


class WeChat: pass


class Alipay: pass

反射模块里的内容

# 反射模块里的内容
import a
import sys

print(sys.modules['a'].Alipay)
print(a.Alipay)
print(getattr(a, 'Alipay'))
print(getattr(sys.modules['a'], 'Alipay'))

反射本文件的内容

wahaha = 'hahahaha'
print(sys.modules)  # 获取到本文件的键值
print(getattr(sys.modules['__main__'], 'wahaha'))  # 根据键值进行反射

实例用法

class Payment:  # 就是一个规范类,主动抛出异常,告诉程序员哪里不对
    def pay(self, money):
        raise NotADirectoryError('请在子类中重写同名pay方法')  # 主动抛出异常


class Alipay(Payment):
    def __init__(self, name):
        self.name = name

    def pay(self, money):
        dic = {'username': self.name, 'price': money}
        print(f'{self.name}支付宝支付{money}元,成功')


class WeChat(Payment):
    def __init__(self, name):
        self.name = name

    def pay(self, money):
        dic = {'username': self.name, 'money': money}
        print(f'{self.name}微信支付{money}元,成功')


class Applepay(Payment):
    def __init__(self, name):
        self.name = name

    def fuqian(self, money):
        dic = {'username': self.name, 'money': money}
        print(f'{self.name}苹果支付{money}元,成功')


# 原来的使用方法
aw = Alipay('alex')
aw.pay(200)

bw = WeChat('wusir')
bw.pay(300)



# 使用反射
import sys
def pay(name, price, kind):
    class_name = getattr(sys.modules['__main__'], kind)
    obj = class_name(name)
    obj.pay(price)


    # if kind == 'WeChat':
    #     obj = WeChat(name)
    # elif kind == 'Alipay':
    #     obj = Alipay(name)
    # elif kind == 'Applepay':
    #     obj = Applepay(name)
    # obj.pay(price)


pay('alex', 200, 'Alipay')
pay('alex', 200, 'WeChat')
pay('alex', 200, 'Alipay')


以下是需要记忆的
class A:
    Role = '治疗'
    def __init__(self):
        self.name = 'alex'
        self.age = 84

    def func(self):
        print('wahaha')
        return 666

a = A()
print(getattr(a, 'name'))       # alex   反射对象的实例化变量
# # 反射对象的绑定方法
print(getattr(a, 'func')())      # <bound method A.func of <__main__.A object at 0x0000021DAAD502C8>>  获得func的地址
getattr(a, 'func')()        # wahaha
print(getattr(A, 'Role'))       # 反射类的静态变量



# 反射本模块中的内容
import sys
cat = '小a'
dog = '小b'
def pig():
    print('小p')
print(getattr(sys.modules['__main__'], 'cat'))      # 反射本模块中的实例变量
print(getattr(sys.modules['__main__'], 'dog'))      # 反射本模块中的实例变量
getattr(sys.modules['__main__'], 'pig')()      # 反射本模块中的方法

4,反射的另一种方法

hasattr

class A:
    Role = '治疗'

    def __init__(self):
        self.name = 'alex'
        self.age = 84

    def func(self):
        print('wahaha')
        return 666


a = A()
print(getattr(a, 'name'))
# print(getattr(a, 'sex'))        # 会报错

print(hasattr(a, 'name'))       # True
print(hasattr(a, 'age'))       # True
print(hasattr(a, 'sex'))       # False

hasattr可以进行判断属性存不存在


class A:
    Role = '治疗'

    def __init__(self):
        self.name = 'alex'
        self.age = 84

    def func(self):
        print('wahaha')
        return 666

if hasattr(a, 'name'):
    print(getattr(a, 'name'))

callable()

判断括号内的是不是可调用的 来确定是否加()
class A:
    Role = '治疗'

    def __init__(self):
        self.name = 'alex'
        self.age = 84

    def func(self):
        print('wahaha')
        return 666

a = A()

if hasattr(a, 'name'):
    if callable(getattr(a, 'name')):
        getattr(a, 'name')()

if hasattr(a, 'func'):
    if callable(getattr(a, 'func')):
        getattr(a, 'func')()

5,反射的例子

文件的操作
'''
显示所有可以做的操作
1,读文件
2,写文件
3,删除文件
4,文件重命名
5,复制文件
'''
class File:
    lst = [('读文件', 'read'), ('写文件', 'writer'), ('删除文件', 'remove'),
           ('文件重命名', 'rename'), ('复制文件', 'copy'), ('移动', 'move')]

    def writer(self):
        print('in writer func')
    def read(self):
        print('in read func')
    def remove(self):
        print('in remove func')
    def rename(self):
        print('in rename func')
    def copy(self):
        print('in copy func')
    def move(self):
        print('in move func')
f = File()
while True:
    for index, opt in enumerate(File.lst, 1):
        print(index, opt[0])
    num = int(input('请输入您要操作的序号>>>'))
    if num <= len(File.lst):
        if hasattr(f, File.lst[num-1][1]):
            getattr(f, File.lst[num-1][1])()
    else:
        print(f'请输入1-{len(File.lst)}的数字!')

6,练习题目

# 1
class Authentic:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def register(self):
        pass

    def login(self):
        pass


l = [('登录', 'login'), ('注册', 'register')]
'''
需求;
    1,循环这个列表
    2,显示序号用户要做的操作
    3,用户输入序号
    4,你通过序号找到对应的login或者register方法
    5,进行实例化
    6,调用对应的方法,完成注册和登录功能
'''



# 2
class User:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        pass

    def sleep(self):
        pass

'''
需求:
    1,用户输入用户名,密码和性别
    2,实例化对象
    3,用户任意输入以下内容:
        1,如果输入的是用属性名,打印属性值
        2,如果输入的是方法名,调用方法
        3,如果输入的什么都不是 不做任何操作

'''



# 3
'''
自定义一个模块,里面有自己实现的mypickle和myjson,只需要传递一个参数'mypickle'还是'myjson'
'''

 

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

更多内容可以查看自己学python的过程,简单笔记。-CSDN博客

  • 12
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值