Day9学习记录 2021Python面向对象基础(下)(属性和方法的私有化、Property属性、__new__方法、单例模式 、异常处理、动态添加属性和方法、__slots__属性限制 )

目录

一、属性和方法的私有化

(一)、属性私有化 

(二)私有化方法

二、属性函数Property

(实现方法一)

(实现方法二)

三、__new__方法

四、单例模式

五、异常处理

(一)try----except

(二)try---except----else 没有错时执行else

(三) try---except----finally 不管有无错,都要执行finally

(四)自定义异常

六 、动态绑定属性和方法

1.动态添加实例属性

2.动态添加类属性

3.动态添加实例方法

4.动态添加类方法

5. 动态添加静态方法

七、__slots__属性限制

 1.__slots__的使用和__dict__

2.继承关系中使用 __slots__


一、属性和方法的私有化

(一)、属性私有化 

使用私有属性的场景:
1.把特定的一个属性隐藏起来 不想让类的外部进行直接调用
2.我想保护这个属性 不想让属性的值随意的改变
3.保护这个属性  不想让子类[派生类]去继承
class Person:
    __hobby='跳舞'    # 私有类属性
    def __init__(self):
        self.__name='李四'     # 加两个下划线 将此属性私有化之后 就不能在外部直接访问了
        self.age=30
        pass
    def __str__(self):
        return '{}的年龄是{},爱好是{}'.format(self.__name,self.age,Person.__hobby)
    def changeValue(self):
        Person.__hobby='唱歌'
        pass
    def printName(self):
        print(self.__name)   #调用此方法就可以间接打印self.__name
xl=Person()
# print(xl.__name)    # 是通过类对象在外部访问  不成立
print(xl)              # 李四的年龄是30,爱好是跳舞
xl.changeValue()              # 这样可以更改
print(xl)                 # 李四的年龄是30,爱好是唱歌
xl.printName()             # 李四
class Student(Person):
    def printInfo(self):
        print(self.__name)   # 在此可以访问父类私有属性吗?               不能
    pass
stu=Student()
print(stu.age)                  # 30
# print(stu.__name)   # 错误 私有属性不能继承
# print(stu.printInfo())       # 报错了 'Student' object has no attribute '_Student__name'
# print(stu.__hobby)         #报错  不能访问
# print(Person.__hobby)        #报错  不能访问

小结:
1.私有化的[实例]属性 不能再外部直接的访问 可以在类的内部随意使用
2.不能继承父类的私有化属性[只能继承父类公共的属性和行为]
3.在属性名前直接加'__',就变成私有化属性 

(二)私有化方法

私有化方法和私有化属性类似:

# 私有化方法
class Animal:
    def __eat(self):   # 私有化方法
        print('吃东西')
        pass
    def Neibudiaoyong__eat(self):
        self.__eat()  
        pass
    def run(self):
        print('飞快的跑')
        pass
class Bird(Animal):
    pass
b1=Bird()
# print(b1.__eat())    #报错 不能在外部直接调用私有方法
b1.Neibudiaoyong__eat()            # 吃东西  通过类的内部调用私有方法

二、属性函数Property

(实现方法一)

# 实现方式一
class Person(object):
    def __init__(self):
        self.__age=18    #定义一个私有化属性,属性名字前加两个下划线__
    def get_age(self):
        return self.__age
    def set_age(self,age):
        if age<0:
            print('年龄不能小于0')
        else:
            self.__age=age
            pass
        pass
    # 定义一个类属性  实现通过访问属性的形式去访问私有的属性
    age=property(get_age,set_age)
    pass

p1=Person()
print(p1.age) #   18  这样就可以访问了   通过property调用get_age
p1.age=20     # 通过property调用set_age
print(p1.age)    #20
p1.age=-1
print(p1.age)  

 运行结果:

(实现方法二)

# 实现方式二
class Person(object):
    def __init__(self):
        self.__age=18    #定义一个私有化属性,属性名字前加两个下划线__
    @property   # 用装饰器 添加属性标识  提供一个getter方法
    def age(self):
        return self.__age
    @age.setter       #提供一个setter方法
    def age(self,parms):
        if parms < 0:
            print('年龄不能小于0')
        else:
            self.__age=parms
            pass
        pass
p2=Person()
print(p2.age) #   18   相当于调用age函数
p2.age=20     # 通过装饰器 调用 第二个age函数 (age.setter)
print(p2.age)    #20

三、__new__方法

# __new__方法
class Animal:
    def __init__(self):
        self.color='红色'
        pass
    # 在python当中 如果不重写 __new__ 默认结构如下
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls,*args,**kwargs)
        # 等同于return object.__new__(cls,*args,**kwargs)\
    pass

tigger=Animal()       #实例化的过程会自动调用__new__去创建实例

在新式类中__new__才是真正的实例化的方法 为类提供外壳制造出实例框架,然后调用该框架内的构造方法__init__进行丰满操作

比喻建房子__new__ 方法负责开发地皮 打地基 并将原料存放在工地;

__init__负责从工地取材料建造出地皮开发图纸规定的大楼 细节设计、建造 最终完成

四、单例模式

简介:
1.是一种常用的软件设计模式
2.目的:确保某个类只有一个实例存在
3.如果希望在整个系统中某个类只能出现一个实例的时候,那么这个单例对象就满足要求
class DataBaseClass(object):
    def __new__(cls, *args, **kwargs):
        # cls._instance=cls.__new__(cls)   #不要使用自身的new方法
        # 容易造成一个深度递归,应该调用父类的new方法
        if not hasattr(cls,'_instance'):      #如果不存在就开始创建
            cls._instance=super().__new__(cls,*args,**kwargs)
        return cls._instance
    pass

class DataSingle(DataBaseClass):
    pass
db1=DataBaseClass()
db2=DataBaseClass()
print(id(db1))
print(id(db2))    #两者内存地址相同 即为一个实例对象
ds3=DataSingle()
print(id(ds3))            #子类实例对象内存地址也和上面两个相同 也为同一个实例对象

五、异常处理

try 遇到第一个错误就会跳出,如果没有异常发生,忽略 except 子句,try 子句执行后结束
except 在捕获错误异常时, 要根据具体的错误类型来捕获
用一个块 可以捕获多个不同类型的异常
Exception 可以捕获所有类型的错误  当错误类型不清楚时使用

(一)try----except

try:                 #捕获逻辑的代码
    li=[1,2,3,4]
    print(li[10])       # 通过下标访问列表
    pass

except Exception as msg:    #Exception 可以拿来捕获所有类型异常 也有其他类型可以去了解一下
    # 在此尽量去处理捕获到的错误
    print(msg)
    pass
print('后续代码正常进行')

运行结果:

 

 也可以在函数调用中使用:

def A(s):
    return 10/int(s)
    pass
def B(s):
    return A(s)*2
def MainError():
    try:
        B('0')
        pass
    except Exception as msg:
        print(msg)
        pass
    pass
MainError()   # 运行结果:division by zero
不需要再每个可能出现错误的地方去捕获,只要再合适的层次去捕获错误就可以了 减少try---except的麻烦
异常的抛出机制
如果在运行时发生异常 解释器会查找相应的异常捕获类型
如果在当前函数没有找到的话  它会将异常传递给上层的调用函数,看能否处理
如果在最外层没有找到的话,解释器就会退出 程序down掉

(二)try---except----else 没有错时执行else

# try---except----else
try:
    print('我没有错误')
    pass
except SyntaxError as msg:
    print('error:',msg)
    pass
except Exception as msg:
    print('error:',msg)
    pass
else:
    print('当try里面代码 没有出现异常的情况下,我else才执行')
    pass

运行结果:

(三) try---except----finally 不管有无错,都要执行finally

try:
    int('fffffff')
    pass
except Exception as msg:
    print(msg)
    pass
finally:
    print('不管有没有出错,我finally都要执行')

运行结果:

(四)自定义异常

# 直接或间接继承Error类或者Exception类
class ToolongMyException(Exception):
    def __init__(self,leng):
        '''
        :param leng:长度
        '''
        self.len=leng
        pass
    def __str__(self):
        return '您输入姓名数据长度是'+str(self.len)+'超过限制长度5了..'
    pass
def name_Test():
    name=input('请输入姓名:')
    try:
        if len(name)>5:
            raise ToolongMyException(len(name))  # raise语句用于抛出指定的异常
        else:
            print(name)
            pass
        pass
    except ToolongMyException as msg:
        print('Error:',msg)
    finally:
        print('执行完毕')

name_Test()

 运行结果:

六 、动态绑定属性和方法

写一个Student类及一个实例对象

# 动态绑定属性和方法
class Student:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    pass
    def __str__(self):
        return '{}今年{}岁了'.format(self.name,self.age)
    pass

zyh=Student('张艳华',18)

1.动态添加实例属性

zyh.weight=80        #动态添加实例属性
print(zyh)
print(zyh.weight)

运行结果 

2.动态添加类属性

#动态添加类属性
print('----------给类对象添加属性-------------')
Student.school='重庆邮电大学'
print(zyh.school)   # 可以访问 school

运行结果:

3.动态添加实例方法

# 动态添加实例方法
print('-----------动态添加实例方法-------------')
import types
def dymicMethod(self):
    print('{}的体重是{}在{}学习'.format(self.name,self.weight,Student.school))
    pass
zyh.printInfo = types.MethodType(dymicMethod,zyh)      #动态绑定实例方法
zyh.printInfo()   #张艳华的体重是80在重庆邮电大学学习  调用动态绑定的方法

运行结果:

4.动态添加类方法

# 动态添加类方法
print('-----------动态添加类方法-------------')
@classmethod
def classTest1(cls):
    print('这是一个类方法')
    pass
Student.TestMethod1=classTest1
Student.TestMethod1()       #这是一个类方法
zyh.TestMethod1()       #这是一个类方法  实例对象调用动态绑定类方法

运行结果:

5. 动态添加静态方法

# 动态添加静态方法
print('-----------动态添加静态方法-------------')
@staticmethod
def classTest2():
    print('这是一个静态方法')
    pass
Student.TestMethod2=classTest2
Student.TestMethod2()     #这是一个静态方法
zyh.TestMethod2()     #这是一个静态方法

运行结果:

七、__slots__属性限制

作用:

限制要添加的实例属性
可以节约内存空间

 1.__slots__的使用和__dict__

class Student(object):
    __slots__ = ('name','age')     # 只允许实例对象动态添加 name和age两个属性
    def __str__(self):
        return '{}今年{}岁了'.format(self.name,self.age)
    pass
xw=Student()
xw.name='小王'
xw.age=15
# xw.cuo='错误'    #添加失败 AttributeError: 'Student' object has no attribute 'cuo'
print(xw)      #运行结果:小王今年15岁了
# print(xw.__dict__)    # 没有__slots__时  所有可用属性都在这里存储   占用内存空间大 
# 注释掉__slots__后,print(xw.__dict__)  运行结果为{'name': '小王', 'age': 15}
# 在定义了slots变量之后 Student类的实例已经不能随意创建不在__slots__定义的属性了
# 同时还可以看到实例当中也不存在__dict__

2.继承关系中使用 __slots__

class sub1Student(Student):
    pass
ln=sub1Student()
ln.gender='男'
ln.pro='统计学'
print(ln.gender,ln.pro)   #男 生物信息学

class sub2Student(Student):
    __slots__ = ('sex')
    pass
dl=sub2Student()
dl.name='dl'
# dl.pro='统计学'  #报错AttributeError: 'sub2Student' object has no attribute 'pro'
dl.sex='男'
print(dl.name,dl.sex)    #dl 男

运行结果:

规律:
1.子类未声明 __slots__时,那么是不会继承父类的__slots__,此时子类是可以随意的属性赋值的

2.子类声明了 __slots__时,子类的__slots__范围 = 父类slots+子类自己声明的slots

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿左.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值