Python 的私有化属性、私有化方法、Property属性、_new_方法、单例模式、错误与异常处理、动态添加属性与方法以及_slots_属性

发布于:2022-11-09 ⋅ 阅读:(463) ⋅ 点赞:(0)

Day11新手小白学python

 第十一节  Python 的私有化属性、私有化方法、Property属性、_new_方法、单例模式、错误与异常处理、动态添加属性与方法以及_slots_属性,并进行了相应练习


目录

Day11新手小白学python

前言

一、私有化属性

二、私有化方法

三、Property属性

四、__new__方法

五、单例模式

六、错误与异常处理

七、Python动态添加属性和方法

八、__slots__属性

九、练习

总结


前言

本文介绍了Python 的私有化属性、私有化方法、Property属性、_new_方法、单例模式、错误与异常处理、动态添加属性与方法以及_slots_属性,并进行了相应练习


一、私有化属性

为了更好的保存属性安全,即不能随意修改,将属性定义为私有属性,添加一个可调用的方法去访问。

私有属性的特性:私有化属性不能在类的外部访问,可以在类里面访问,修改;子类不能继承私有化属性;两个下划线开头,声明该属性为私有。

# 使用私有属性的场景
# 1.把特定的一个属性隐藏起来,不想让类的外部进行直接调用
# 2.我想保护这个属性,不想让属性的值随意的改变
# 3.保护这个属性,不想让派生类【子类】去继承
class Person:
    __hobby='跳舞'  # 类属性
    def __init__(self):
        self.__name="李四"    # 加两个下划线,将此属性私有化 私有化之后不能在外部直接访问了 当然在类的内部是可以访问的
        self.age=30
        pass
    def __str__(self):
        '''
        私有化的属性在内部可以使用 self.__name
        :return:
        '''
        return '{}的年龄是{} 爱好是{}'.format(self.__name,self.age,Person.__hobby)
    def changevalue(self):
        Person.__hobby='唱歌'     # 私有属性可以在内部修改
        pass

class Student(Person):
    def printInfo(self):
        # print(self.__name)  # 在此访问父类的私有属性可以吗  不可以 会报错 因为子类不能继承私有化属性
        print(self.age)     # 输出30
    pass

stu=Student()
# print(stu.name)   # 会报错 子类没有这个属性,有也不可以在类外部调用
stu.printInfo()

stu.changevalue()   # 修改私有属性的值
print(stu)      # 输出 李四的年龄是30 爱好是唱歌
# print(stu.__hobby)        # 实例对象访问类属性  是私有属性在不能访问
# print(Person.__hobby)     # 对于类属性和实例属性同样如此 只要定义为私有属性 则都不能在外部访问

# xl=Person()
# # print(xl.name)  # 是通过类对象在外部访问私有属性  会报错
# print(xl)    # 输出 李四的年龄是30

# 小结:
# 1 私有化的【实例】属性不能在类的外部直接访问,但可以在类的内部直接访问
# 2 子类不能继承父类的私有化属性【只能继承父类公共的属性和行为】
# 3 在属性名的前面直接加'__'就可以变成私有化属性了

在类的外面修改私有属性:可以通过定义修改属性的方法来修改,也可以利用property来修改。 

二、私有化方法

概述:私有化方法跟私有化属性概念一样,有些重要的方法,不允许外部调用,防止子类意外重写,把普通的方法设置成私有化方法。

语法:私有化方法,即在方法名前面加两个下划线。

特性:私有化方法一般是类内部调用,子类不能继承,外部不能调用。

class Animal:
    def __eat(self):
        print('吃东西')
        pass
    def run(self):
        self.__eat()        # 在此调用私有化的方法 可以正确执行
        print('飞快的跑')
        pass
class Bird(Animal):
    pass
b1=Bird()
# b1.eat()      # 私有化方法不能在类的外部使用
b1.run()

三、Property属性

在外部可以访问私有方法的办法:

 方法一:类属性,即在类中定义 值为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)   # 获取或修改age值时不用调用p1.get_age()或其他,直接调用age即可
    pass

p1=Person()
print(p1.age)   #获取age属性值时,会自动调用get age方法。输出 18 
p1.age=-1       # 修改age属性值时,会自动调用set age方法,
print(p1.age)    # 输出 年龄不能小于0
# p1.get_age()
# p1.set_age()

方法二:装饰器,即在方法上使用装饰器

# 实现方式2 通过装饰器的方式去声明
class Person(object):
    def __init__(self):
        self.__age = 18 
    @property       # 用装饰器修饰 添加属性标志 提供一个getter方法  获取值
    def age(self): 
        return self.__age
    @age.setter     # 使用装饰器进行装饰,提供一个setter方法  修改值 函数名.setter
    def age(self,parms):
        if parms < 0:
            print('年龄不能小于0')
        else:
            self.__age = parms
            pass
        pass
    pass
p1=Person()
print(p1.age)   #获取age属性值时,会自动调用@property标志的方法。输出 18
p1.age=30       # 修改age属性值时,会自动调用@age.setter标志的方法,
print(p1.age)    # 输出 30
# p1.get_age()
# p1.set_age()

四、__new__方法

_new_方法的作用是,创建并返回一个实例对象,如果__new__只调用了一次,就会得到一个对象。继承自object的新式类才有new这一魔法方法。

注意事项:

        __new__ 是在一个对象实例化的时候所调用的第一个方法

        __new__至少必须要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供 ,其他的参数是用来直接传递给 __init__ 方法

        __new__ 决定是否要使用该 __init__ 方法,因为 __new__ 可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果 __new__ 没有返回实例对象,则 __init__ 不会被调用

        在__new__ 方法中,不能调用自己的__new__ 方法,即:return cls.__new__ (cls),否则会报错(RecursionError: maximum recursion depth exceeded:超过最大递归深度)

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_负责从工地取材料建造出地皮开发图纸规定的大楼,负责细节设计、建造、最终完成

五、单例模式

单例模式:是一种软件设计模式  目的:确保某一个类只有一个实例存在。如果希望在这个系统中 某个类只能出现一个实例的时候,那么这个单例对象就满足要求。单例就比如我们打开电脑的回收站,在系统中只能打开一个回收站,也就是说这个整个系统中只有一个实例,重复打开也是使用这个实例。简单的说就是不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象。

# 单例模式:是一种软件设计模式  目的:确保某一个类只有一个实例存在
# 如果希望在这个系统中 某个类只能出现一个实例的时候,那么这个单例对象就满足要求

# 创建一个单例对象 基于_new_方法去实现的【推荐的一种】
class DataClass(object):
    _instance = None  # 保存实例对象
    def __new__(cls, *args, **kwargs):
        # cls.instance=cls.__new__(cls)     不能使用自身的new方法 容易造成一个深度递归,应该调用父类的new方法
        # 利用hasattr判断_instance是否创建
        if not hasattr(cls,'_instance'):     # 如果不存在cls._instance就创建_instance类属性 只让_instance创建一次
            cls._instance=super().__new__(cls, *args, **kwargs)
        return cls._instance
        # 利用if--else判断
        # 如果类属性 _instance 的值为None,那么新建一个对象
        # 如果类属性值不为None 返回 _instance 保存的对象
        # if not cls._instance:
        #     cls._instance = super().__new__(cls, *args, **kwargs)  # 调用父类__new__方法生成一个实例对象
        #     return cls._instance
        # else:
        #     return cls._instance
    pass

class DBoptSingle(DataClass):
    pass

db1=DBoptSingle()
print(id(db1))
db2=DBoptSingle()
print(id(db2))
db3=DBoptSingle()
print(id(db3))      # 3个id相都等,说明实例化三次对象,实际上都是同一个对象

六、错误与异常处理

有时候代码写错了,执行程序的时候,执行到错误代码的时候,程序直接终止报错,这是因为Python检测到一个错误时,解释器就无法继续执行了,出现了错误的提示,这就是"异常"

语法格式:

 try ... except 语句:将可能出错的代码放到try里面,except可以指定类型捕获异常。except里面的代码是捕获到异常时执行,将错误捕获,这样程序就不会因为一段代码包异常而导致整个程序崩溃。用一个块 可以捕获多个不同类型的异常。Exception 可以捕获所有的异常,当对出现的问题或者错误不确定的情况下,可以使用Exception

# except在捕获错误异常时 是要根据具体的错误类型来捕获的
# 用一个块 可以捕获多个不同类型的异常
# Exception 可以捕获所有的异常 当对出现的问题或者错误不确定的情况下 可以使用Exception
try:
    # print(b)        # 要捕获错误逻辑的代码
    # li=[1,2,45]
    # print(li[10])       # 通过下标去访问列表
    # a=10/0
    pass
except NameError as msg:
    # 捕获到的错误 才会在这个执行
    print(msg)
    pass
except IndexError as msg:
    print(msg)
    pass
except ZeroDivisionError as msg:
    print(msg)
    pass
# except Exception as result:     # Exception 可以捕获所有的异常
#     print(result)
#     在此尽量去处理捕获到的错误,如进行打印标识一下
#     pass
# print('初次异常处理')
# print('HAHAHAHAHA')

异常传递:如果多个函数嵌套调用,内层函数异常,异常会往外部传递,直到异常被抛出,或被处理。不需要在每个可能出错的地方去捕获,只要在合适的层次去捕获错误就可以了,这样的话就大大减少我们写try---except的麻烦

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

  try ... excep--else语句:

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

 try--except--finally语句:

try:
    int('34')
    open('aaaa.txt')
    pass
except Exception as msg:
    print('error',msg)
    pass
finally:
    print('释放文件的资源、数据库连接的资源等等')
    print('不管有没有捕获到异常,finally都是执行的')

自定义异常:都要直接或间接继承ErrorException类。由开发者主动抛出自定义异常,在python中使用raise关键字

class ToolongException(Exception):
    def __init__(self,leng):
        '''
        :param leng:长度
        '''
        self.leng=leng
        pass
    def __str__(self):
        return '您输入的姓名数据长度是'+str(self.leng)+'超过长度了...'
    pass

def name_Test():
    name=input('请输入姓名')
    try:
        if len(name)>=5:
            raise  ToolongException(len(name))
        else:
            print(name)
            pass
    except ToolongException as result:
        print(result)
        pass
    finally:
        print('执行完毕了')
        pass
    pass
name_Test()

七、Python动态添加属性和方法

动态语言:运行时可以改变其结构的语言,例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。如php,JavaScript,python都是动态语言,CC#java是静态语言。

1、动态添加实例属性:运行中给对象添加属性

class Animal(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
 # 定义了两个初始属性name和age,但是没有颜色,我想要添加颜色又不能去修改类
cat = Animal('小白',5)
# 动态绑定colour属性
cat.colour = '白色'
print(cat.colour)

2、动态添加类属性:运行中给类添加属性

class Animal(object):
    def __init__(self,name,age):
        self.name = name
        self.age = age
# 定义了两个初始属性name和age,但是没有颜色,我想要添加颜色又不能去修改类
cat = Animal('小白',5)
# 动态绑定colour属性
Animal.foot = 4 # 添加类属性
print(cat.foot )

3、动态添加实例方法需要使用types,首先要导入types模块,再定义好需要使用的方法,再绑定调用。使用方式:实例对象.需定义的实例方法名=types.MethodType(定义好的需绑定的实例方法名,实例对象)

4、动态添加类方法和静态方法:首先要先定义好类方法和静态方法再绑定调用。使用方式:类名.需定义类的方法名 = 定义好的需绑定的类方法 或 类名.需定义类的静态方法名 = 定义好的需绑定的静态方法

import types    # 添加方法的库  动态添加实例方法需要用到types模块
def dymicMethod(self):
    print('{}的体重是{},在{}读大学'.format(self.name,self.weight,Student.school)) # 类属性用类访问
    pass
@classmethod        # 定义一个类方法
def classTest(cls):
    print('这是一个类方法')
    pass
@staticmethod       # 定义一个静态方法
def staticMethodTest():
    print('这是一个静态方法')
    pass
class Student:
    def __init__(self,name,age):
        self.name=name
        self.age=age
        pass
    def __str__(self):
        return '{}今天{}岁了'.format(self.name,self.age)
    pass
# ---------------------------给类绑定类方法----------------------------------
print('绑定类方法')
Student.TestMethod=classTest        # 语法:类名.需定义类的方法名 = 定义好的需绑定的类方法
Student.TestMethod()                # 调用绑定好的类方法
print('---------绑定类方法结束-------------')

# ---------------------------给类绑定静态方法----------------------------------
print('绑定静态方法')
Student.staticMethodTest=staticMethodTest       # 语法:类名.需定义类的静态方法名 = 定义好的需绑定的静态方法
Student.staticMethodTest()                      # 调用绑定好的静态方法
print('---------绑定静态方法结束-------------')

# ---------------------------动态添加实例属性----------------------------------
lxy=Student('刘绚',20)
lxy.weight=50       # 动态添加属性 添加的是实例属性

# ---------------------------动态添加实例方法  需要使用types----------------------------------
lxy.printInfo=types.MethodType(dymicMethod,lxy) # 实例对象.需定义的实例方法名=types.MethodType(定义好的需绑定的实例方法名,实例对象)
lxy.TestMethod()        # 实例对象调用动态绑定好的类方法
print(lxy)

print('-------另一个实例对象 张明--------')
zm=Student('张明',20)
zm.weight=80
print(zm)       # 输出:张明今天20岁了
zm.printInfo=types.MethodType(dymicMethod,zm)       # 动态绑定实例方法
# ---------------------------给类对象添加属性 类属性----------------------------------
print('-------给类对象添加属性--------')
Student.school='华电'     # 动态添加 类属性
print(zm.school)

print('-------执行动态调用实例方法--------')
lxy.printInfo()     # 调用动态绑定的实例方法
zm.printInfo()

八、__slots__属性

python是动态语言,在运行的时候可以动态添加属性。如果要限制在运行的时候给类添加属性,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。

只有在__slots__变量中的属性才能被添加,没有在__slots__变量中的属性添加失败。可以防止其他人在调用类的时候胡乱添加属性或方法。

__slots__属性子类不会继承,只有在当前类中有效。若子类声明了_slots_,此时子类会继承父类的_slots_,也就是子类_slots_的范围是:其自身_slots_+父类的_slots_ ,在这两者中定义的变量可以被添加,其余都不行;子类和父类的_slots_最好不要有一样的,会占用内存空间

__slots__属性的作用:限制属性的随意输入;节省内存空间。

# __slots__作用
# 限制要添加的实例属性
# 节约内存空间
class Student(object):
    __slots__ = ('name','age')
    def __str__(self):
        return '{}.....{}'.format(self.name,self.age)
    pass
xw=Student()
xw.name='小王'
xw.age=20
# xw.score=96     # 不在solts申明的范围内,不允许添加该属性,会报错
# print(xw.__dict__)  # 输出:{'name': '小王', 'age': 20}  所有可以用的属性都在字典里面存储 不足的地方就是占用的内存空间大
# 在定义了slots变量之后,student类的实例对象已经不能随意创建不在_slots_定义的属性了
# 同时可以看到实例中也不存在__dict__,都存在_slots_中了
print(xw)

# 在继承关系当中的使用 _slots_
# 当子类未声明_slots_时,那么是不会继承父类的_slots_,此时子类是可以随意的添加属性的
# 子类声明了_slots_时,此时子类会继承父类的_slots_,也就是子类_slots_的范围是 其自身+父类的_slots_
# 子类和父类的_slots_最好不要有一样的,会占用内存空间
class subStudent(Student):
    __slots__ = ('gender','pro')
    pass
ln=subStudent()
ln.gender='男'
ln.pro='计算机'
print(ln.gender,ln.pro)

练习

1、编写一段代码以完成下面的要求:定义一个Person类,类中要有初始化方法,方法中要有人的姓名,年龄两个私有属性。提供获取用户信息的函数。提供获取私有属性的方法。提供可以设置私有属性的方法。设置年龄的范围在(0-120)的方法,如果不在这个范围,不能设置成功。

class Person(object):
    def __init__(self,name,age):
        self.__name=name
        self.__age=age
        pass
    def get_msg_name(self):
        return self.__name
    def get_msg_age(self):
        return self.__age
    def set_msg_name(self, name):
        self.__name = name
        pass
    def set_msg_age(self,age):
        if 120<age or age<0:
            print('年龄不合适')
            pass
        else:
            self.__age=age
            pass
        pass
    name=property(get_msg_name,set_msg_name)
    age=property(get_msg_age,set_msg_age)
    def __str__(self):
        return '{}的年龄是{}岁'.format(self.__name,self.__age)
    pass

def getData():
    name=input('请输入您的姓名')
    age=input('请输入您的年龄')
    return name,age

name,age=getData()
lxy=Person(name,age)
print(lxy.name)
print(lxy.age)
print(lxy)
lxy.name='xiaom'
lxy.age=-1
print(lxy)

2、请写一个单例模式

class DataClass(object):
    _instance=None
    def __new__(cls, *args, **kwargs):
        if not cls._instance:   # 如果_instance仍为空
            cls._instance=super().__new__(cls, *args, **kwargs)
            return cls._instance
        else:
            return cls._instance
        pass
    pass
db1=DataClass()
print(id(db1))
db2=DataClass()
print(id(db2))

 3、创建一个类,并定义两个私有化属性,提供一个获取属性的方法和设置属性的方法。 利用property 属性给调用者提供属性方式的调用获取和设置私有属性方法的方式。

class Student:
    def __init__(self,name,score):
        self.__name=name
        self.__score=score
        pass
    @property        # 用装饰器修饰 添加属性标志 提供一个getter方法  获取值
    def name(self):
        return self.__name
    @name.setter  # 使用装饰器进行装饰,提供一个setter方法  修改值 函数名.setter
    def name(self,name):
        self.__name=name
        pass
    @property
    def score(self):
        return self.score
    @score.setter
    def score(self,score):
        self.__score=score
        pass
    def __str__(self):
        return self.__name
    pass
    def __call__(self, *args, **kwargs):    # 将实例对象以函数的形式去调用
        print('{}的分数是{}'.format(self.__name,self.__score))
        pass
xw=Student('小王',90)
print(xw)
xw()        # 输出:小王的分数是90
xw.name='张三'
xw.score=48
xw()        # 输出:张三的分数是48

4、 创建一个Animal类,实例化一个cat对象,请给cat对象动态绑定一个run方法,给类绑定一个类属性colour,给类绑定一个类方法打印字符串'ok'。

import types
class Animal:
    pass
def run(self):      # 绑定实例方法
    print("我跑得飞快")
    pass
@classmethod        # 定义一个类方法
def printInfo(cls):
    print("ok")
    pass
Animal.color='橘色'    # 给类绑定一个类属性colour
cat=Animal()
cat.weight=20       #  动态添加实例属性
print("猫的颜色是{},重{}".format(Animal.color,cat.weight))
cat.run1=types.MethodType(run,cat)      # 给cat对象动态绑定一个run方法 实例方法
cat.run1()

Animal.printInfo1=printInfo  # 给类绑定一个类方法
cat.printInfo1()

总结

本文仅仅简单介绍了Python 的私有化属性、私有化方法、Property属性、_new_方法、单例模式、错误与异常处理、动态添加属性与方法以及_slots_属性,并进行了相应练习

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到