python07——面向对象基础(3)
1.私有化属性
类的外部无法直接调用,属性的值不能随意改变,子类无法继承
class Person(object): __age=18 ###两个下划线开头,定义一个私有化属性
##可以在类里面访问、修改 class Person( object) : __age = 18 #定义一个私有化属性,属性名宁前面加两个下划线 def get_age(self):#访问私有类属性 return Person.__age def set_age(self,age) :#修改私有类属性 Person.__age = age xiaoming = Person() print(xiaoming.get_age()) xiaoming.set_age(20) print(xiaoming.get_age())
2.私有化方法
不允许外部调用,防止子类意外重写,子类不能继承
class A(object): ##在方法前面加两个下划线,变成私有化方法 def __myname(self): print('xiaoming') def renyuan(self): self.__myname() ##内部可以调用 # 普通方法 def myname(self): print('xiaoming') a=A() a.myname() # 正常调用 a.__myname() # 调用私有化方法,报错 a.renyuan()
区别:
_xxx:property类型的变量,只允许本身和子类进行访问
__xxx__:魔法方法,python自有,避免自己创建这种类型的
xxx_:避免属性名与python冲突
__xxx:私有化方法
3.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
##定义一个类属性,实现直接访问属性的形式去访问私有的属性 age = property(get_age,set_age) #当对这个age设置值时调用set_age, #当获取值时调用get_age #注意:必须是以get, set开头的方法名,才能被调用 xiaoming = Person( ) xiaoming.age = 15 print(xiaoming.age)
方法二:
class Person(object): def __init__ (self): self._age = 18 #定义一个私有化属性 @property #使用装饰器对age进行装饰,提供一个getter方法 def age(self): #访问私有实例属性 return self._age @age.setter #使用装饰器进行装饰,提供一个setter方法 def age(self, age): #修改私有实例属性 if age<0: print('年龄不能小于0') else: self._age = age xiaoming = Person() xiaoming.age = 15 print(xiaoming.age)
4.__new__ 方法
创建并返回一个实例对象,如果__new__ 只调用了一次,就会得到一个对象。继承自object的新式类才有new这一魔法方法。
●注意:
__ new__ 是在一个对象实例化的时候所调用的第一个方法。至少必须要有一个参数cls,其他的参数是用来直接传递给__init__方法。
_ new_决定是否要使用该__init__ 方法, 因为__new__可以调用其他类的构造方法或者直接返回别的实例对象来作为本类的实例,如果__new__没有返回实例对象,则__init__不会被调用
在__new__方法中, 不能调用自己的__new__方法, 即: return cls.__new__(cls)
class A(object): def __init__(self): print("__init__执行了") def __new__(cls,*args,**kwargs): print("__new__执行了") return object.__new__(cls) #调用父类的new方法 a=A()
class A(object): def __init__(self, a, b, c, k): print(a, b, c,k) print("__init__执行了") def __new__(cls, *args, **kwargs): return object.__new__(cls) #调用父类的new方法 a = A(1, 2365, 1122, k=3)
5.单例模式
常用设计模式的一种,比如打开电脑的回收站,在系统中只能打开一个回收站,也就是说这个整个系统中只有一个实例,重复打开也是使用这个实例。即不管创建多少次对象,类返回的对象都是最初创建的,不会再新建其他对象。
class DataBaseClass(object): def __new__(cls, *args, **kwargs): #cls._instance=cls.__new__(cls) 不能使用自身的new方法 if not hasattr(cls,'_instance'): ##如果不存在就开始创建 cls._instance=super().__new__(cls,*args,**kwargs) return cls._instance db1=DataBaseClass() print(id(db1)) db2=DataBaseClass() print(id(db2))
6.错误与异常处理
try:可能出现错误的代码块
except:出错之后执行的代码块
else:没有出错的代码块
finally:不管有没有出错都执行的代码块
try .. except语句
将可能出错的代码放到try里面,except可以指定类型捕获异常。except里面的代码是捕获到异常时执行,将错误捕获,这样程序就不会因为一段代码包异常而导致整个程序崩溃。
在捕获错误异常时,只要根据具体的错误类型来捕获的
try: 1/0 #将可能会报错的代码放到try里面 except ZeroDivisionError as e: #捕获异常,ZeroDivisionError 异常类型
#对出现的问题或者错误不确定的情况下可以使用Exception print(e)
AssertionError 当assert 语句失败时引发。 AttributeError 当属性分配或引用失败时引发。 EOFError 当input()函数达到文件结束条件时引发。 FloatingPointError 当浮点运算失败时引发。 GeneratorExit 调用生成器的close()方法时引发。 ImportError 找不到导入的模块时引发。 IndexError 当序列的索引超出范围时引发。 KeyError 在字典中找不到键时引发。 KeyboardInterrupt当用 户按下中断键(Ctr1+c或delete)时引发。 MemoryError当操作耗尽内存时引发 NameError 在局部或全局范围内找不到变量时引发。 NotImp1 ementedError由抽象方法提出。 OSError当系统操作导致系统相关错误时引发。 Over flowError 当算术运算的结果太大而无法表示时引发。 ReferenceError使用弱引用代理访问垃圾收集的引用时引发。 RuntimeError 当错误不属于任何其他类别时引发。 StopIteration 函数引发,以指示迭代器不再返回任何项. SyntaxError遇到语法错误时由解析器引发。 IndentationError当缩 进不正确时引发。 TabError当缩进由不一致的制表符和空格组成时引发。 SystemError当解释器检测到内部错误时引发。 SystemExit由sys . exit( )函数引发: TypeError 将雨数或操作应用于类型不正确的对象时引发。 UnboundLocalError 当在丽数或方法中引用局部变量,但没有将值绑定到该变量时引发。 UnicodeError当 发生与unicode相关的编码或解码错误时引发 UnicodeEncodeError当编 码过程中发生与unicode相关的错误时引发。 UnicodeDecodeError当 解码过程中出现与unicode相关的错误时引发。 UnicodeTranslateError翻译 过程中发生与unicode相关的错误时引发。 ValueError当函数得到类型正确但值不正确的参数时引发。 ZeroDivisionError当除法或模运算 的第二个操作数为零时引发。
try - except - else语句
try: 1/1 except Exception as e: print(e) else: print('前面没错才执行我')
try - except - finally语句
try: 1/0 #将可能会报错的代码放到try里面 except Exception as e: #捕获异常,ZeroDivisionError 异常类型 print(e) finally: print('前面无论如何都要执行我')
自定义异常,继承Error、Exception类,使用raise关键字
#自定义一个异常类 class LeNumExcept(Exception): #自定义异常类需要继承Exception def __str__(seIf): return '[error: ]你输入的数字小于0.请出入大于0的数字' try: num = int(input('请出入一个数字: ')) if num<0: # raise 关键字抛出异常 raise LeNumExcept() except LeNumExcept as e: print(e) #捕获异常 else: print('没有异常')
7.Python动态添加属性和方法
import types ##添加方法的库 def baogao(self): print('{}年龄{}岁了,属性是{}'.format(self.name,self.age,Animal.pro)) @classmethod def classTest(cls): print('这是一个类方法') @staticmethod def staticMethodTest(): print('这是一个静态方法') class Animal(object): def __init__ (self, name,age): self.name = name self.age = age #定义了两个初始属性name和age, 但是没有颜色,我想要添加颜色又不能去修改类 cat = Animal('小白',5) #动态绑定colour属性 cat.colour ='白色' print('绑定类方法') Animal.TestMethod=classTest Animal.TestMethod() Animal.staticMethod=staticMethodTest Animal.staticMethod() print('-----类方法结束-------') print(cat.colour) ####给类对象添加属性 Animal.pro='爬行动物' print(cat.pro) cat.printInfo=types.MethodType(baogao,cat) ##动态的绑定方法 cat.printInfo() cat.TestMethod() print('-----实例对象调用 动态绑定类方法-------')
8.slots
在定义class的时候,定义一个特殊的_slots_变量,来限制该class实例能添加的属性。只有在_slots_ 变量中的属性才能被添加,没有在__slots_ 变量中的属性会添加失败。
子类未声明时,_ slots_属性子类不会继承。子类若声明了,它slots范围为自身+父类的。
class Student(object): __slots__ = ('name','age') def __str__(self): return '{} {}'.format(self.name,self.age) xw=Student() xw.name='小王' xw.age=20 #xw.score=98 ##报错,slots中没有这个属性,添加失败 print(xw) class subStudent():
#__slots__() 如果子类声明了,就会继承父类 pass xz.score=98 ##不会继承slots,可以添加不属于slots的属性 print(xz)
巩固:
1、 Python中new方法作用是什么? 创建实例对象 2、什么是单例模式?单例模式适用于什么场景? 一个类有且只有一个实例,提供全局访问点。 3、私有化方法与私有化属性在子类中能否继承? 不能 4、在Python中什么是异常? 程序在执行过程发生的错误 5、Python中 是如何处理异常的? 根据异常的类型去处理,try……except……else……finally语句 6、Python中异常处理语句的一般格式, 可以使用伪代码的形式描述。 try……except……else……finally语句 7、_ slots_ 属性的作用 限制属性的随意输入,节省内存空间 8、私有化属性的作用? 保护数据,封装性的体现 9、在类外面是否能修改私有属性? 不可以直接修改,可以通过方法来实现,还可以借助属性函数property去实现。
实操题:
1、定义一个Person类,类中要有初始化方法,方法中要有人的姓名,年龄两个私有属性。提供获取用户信息的函数。提供获取私有属性的方法。提供可以设置私有属性的方法。设置年龄的范围在(0- 120)的方法,如果不在这个范围,不能设置成功。
class Person(object): def __init__(self,n,a): self.__name=n self.__age=a pass def get_age(self): return self.__age def get_name(self): return self.__name def set_age(self,age): if age<0 or age>120: print('年龄范围0~120,设置失败') else: self.__age=age def set_name(self,name): self.__name =name def __str__(self): return '姓名:{} 年龄:{}'.format(self.__name,self.__age)
2、请写一个单例模式
3、创建一个类,并定义两个私有化属性,提供一个获取属性的方法,和设置属性的方法。利用property属
性给调用者提供属性方式的调用获取和设置私有属性方法的方式。
class Student: def __init__(self): self.__name='张三' self.__score=90 @property def name(self): return self.__name @name.setter def name(self,name): self.__name=name @property def score(self): return self.__score @score.setter def score(self,score): self.__score=score def __str__(self): return self.name def __call__(self, *args, **kwargs): print('{}的得分:{}'.format(self.__name,self.__score)) xw=Student() xw() ##调用__call__ print(xw) ##调用__str__ xw.name='yh' xw.score=99 xw()
4、创建一个Animal类,实例化一个cat对象,请给cat对象动态绑定一个run方法,给类绑定一个类属性colour,
给类绑定一个类方法打印字符串'ok’。
class Animal(): pass #给类绑定一个类方法打印字符串'ok’。 @classmethod def leifangfa(cls): print('ok') Animal.printInfo=leifangfa Animal.printInfo() ##绑定一个类属性colour, cat=Animal() cat.colour='白色' print(cat.colour) ##动态绑定run方法 cat.run=types.MethodType(run,cat) cat.run()