面向对象(下)
1.私有化属性
2.私有化方法
3.Property属性
4.__new__方法
5.单例模式
6.错误与异常处理
7.Python动态添加属性和方法
8.__slots__属性
私有化属性
作用:
①防止他人随意修改或意外修改
②把特定的一个属性隐藏起来,不想让类的外部进行直接调用
③不想让派生类【子类】去继承
语法
定义一个私有化属性,属性名字前面加两个下划线
class Person(object):
__age=18 #定义一个私有化属性,属性名字前面加两个下划线
例子——外部无法访问
class Person:
def __init__(self):
self.__name='李四' #将两个下划线 将属性私有化
self.__age=30
pass
pass
x1=Person()
print(x1.name) #通过类对象 在外部访问
>>>Traceback (most recent call last):
>>> File "E:/python/python_study/Day9/私有化属性.py", line 9, in <module>
>>> print(x1.name)
>>>AttributeError: 'Person' object has no attribute 'name'
类的内部访问例子
class Person:
def __init__(self):
self.__name='李四' #将两个下划线 将属性私有化
self.__age=30
pass
def __str__(self):
return '{}的年龄是{}'.format(self.__name,self.__age) #内部访问
pass
x1=Person()
print(x1)
总结
私有化的【实例】属性,不能再外部直接的访问,可以再类的内部随意的使用。
==ps.==类内部可以修改私有化属性
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
x1=Person()
print(x1)
print('-------------修改后---------------')
x1.changeValue()
print(x1)
>>>李四的年龄是30 爱好是跳舞
>>>------------修改后---------------
>>>李四的年龄是30 爱好是张三
私有化方法
作用
私有化方法一般是类内部调用,子类不能继承,外部不能调用
区分:左单边下划线,双边下划线,右单边下划线
①_xxx: 私有化(保护)
②_xxx_ :魔术方法,python的内置方法
③xxx_: 避免属性名与python冲突,不具备特殊特点
语法
定义一个私有化方法,属性名字前面加两个下划线
class Person(object):
__def eat(self):
print('吃东西')
pass
类的内部可以调用方法
例子
class Animal:
def __eat(self):
print('吃东西')
pass
def run(self):
self.__eat()
print('飞快的跑')
pass
pass
class Bird(Animal):
pass
b1=Bird()
b1.run()
>>>吃东西
>>>飞快的跑
Property
作用:访问私有化的属性或方法
①property方法设置
语法
class 类:
def ...
property(可调用的方法)
实例
class Person(object):
def __init__(self):
self.__age=18
pass
def get_age(self): #访问私有实例属性
return self.__age
def set_age(self,age): #修改实例属性
if age<0:
print('年龄不能小于0')
pass
else:
self.__age=age
pass
pass
# 定义一个类属性 实现通过直接访问属性的形式去访问私有属性
age=property(get_age,set_age) #注意:必须是以get,set开头的方法名,才能被调用
pass
p1=Person()
print(p1.age)
print('-----------修改后------------')
p1.age=25
print(p1.age)
# p1.get_age()
>>>18
>>>-----------修改后------------
>>>25
ps. age=property(get_age,set_age)
中的age只是一个赋值句,可以用其他XXX代替,但是对应的调用时也要用对用的XXX
②用装饰器
语法
class 类():
def __init__(self):
....
@property #添加装饰器
def xxx
@xxx.setter #设置修改
class Person(object):
def __init__(self):
self.__age=18
pass
@property
def age(self):
return self.__age
@age.setter #提供参数设置的方法
def age(self,parms):
if parms < 0:
print('年龄不能小于0')
pass
else:
self.__age=parms
pass
pass
pass
p1=Person()
print(p1.age)
print('-------------修改--------------')
p1.age=30
print(p1.age)
__new__方法
__new__是新式类中出现,是一种静态方法。
语法
def __new__(cls,*args,**kwargs):
return object.__new__(cls,*args,**kwargs)
pass
1.__new__
同__init__
区别
__new__
和__init__
的主要区别在于:__new__
是用来创造一个类的实例的(constructor),而__init__
是用来初始化一个实例的(initializer)。
2.__new__
和__init__
参数的不同
__new__
所接收的第一个参数是cls,而__init__
所接收的第一个参数是self。这是因为当我们调用__new__
的时候,该类的实例还并不存在(也就是self所引用的对象还不存在),所以需要接收一个类作为参数,从而产生一个实例。而当我们调用__init__
的时候,实例已经存在,因此__init__
接受self作为第一个参数并对该实例进行必要的初始化操作。这也意味着__init__
是在__new__
之后被调用的。
3.__init__
不可返回
如果我们在__init__
中加上return语句,将会导致TypeError: __init__() should return None
的错误。
class oldStyleClass:
def __init__(self):
return 29
oldStyleClass()
>>>TypeError: __init__() should return None
4.__new__
的调用
①这里需要注意的是,如果__new__
函数返回一个已经存在的实例(不论是哪个类的),__init__
不会被调用。
②如果我们在__new__
函数中不返回任何对象,则__init__
函数也不会被调用
③只有在__new__
返回一个新创建属于该类的实例时当前类的__init__
才会被调用。
ps.
① __new__是一个对象实例化时候所调用的第一个方法
②__new__必须要有一个参数cls,代表实例化的类,此参数在实例化时由Python解释器自动提供,其他蚕食时用来直接传递给__init__方法
③__new__决定是否使用__init__方法,因为__new__可以调用其他类的构造方法或者直接返回别的实例对象作为本类的实例,如果__new__没有返回实例对象,则__init__不会被调用
④在__new__方法中,不能调用自己的__new__方法,即:return cls._new_(cls),否则会报错(RecursionError: maximum recursion depthn exceeded: 超过最大递归深度)
单例模式
常用的软件设计模式,能确保一个类只有一个实例存在,并且提供了一个全局的访问点,类似于window上的回收站。
class DataBaseClass(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls,'_instance'):
cls._instance=super().__new__(cls,*args,**kwargs)
return cls._instance
#切忌不能使用自身的new方法,如cls.__instance=cls.__new__(cls)
pass
db1=DataBaseClass()
print(id(db1))
db2=DataBaseClass()
print(id(db2))
db3=DataBaseClass()
print(id(db3))
Python错误处理
try——except
作用
①捕获指定的错误类型,并反馈,但不会影响后续代码的执行——示例1
②一个try可以跟着多个except
③exception 可以捕获所有异常(当对错误异常不确定时)——示例2
示例1
try:
print(b)
pass
except NameError as msg:
print(msg)
pass
print('1111111111')
>>>name 'b' is not defined
>>>1111111111
示例2
try:
print(b)
pass
except Exception as result: #捕获所有错误并返回信息
print(result)
pass
print('1111111111')
>>>name 'b' is not defined
>>>1111111111
try—except—else
else:
下的语句在没有错误时运行
try-except-finally
finally:
不管有没有出错都执行的代码块。
自定义异常
通过直接或间接继承Error或Exception类,并与raise组合
多训练代码
动态添加属性
1.通过实例添加属性,但是只有对应实例才能访问
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
pass
cat = Student('小明',30)
#动态添加color属性——通过实例
cat.color = '白色'
print(cat.color)
2.通过类对象添加属性,任何实例对象都可以访问
class Student:
def __init__(self,name,age):
self.name=name
self.age=age
pass
pass
cat = Student('小明',30)
#动态添加color属性——通过实例
Student.color = '白色'
print(cat.color)
动态添加方法
1.绑定实例
方法
利用import types #添加方法的库——仅针对实例方法
def dymicMethod:
return ...
xxx.printinfo=types.MethodType(dymicMethod,xxx)
xxx.printinfo()
2.绑定类
方法
@classmethod
@classmethod
def classTest(cls):
print('这是一个类方法')
pass
Student.TestMethod=classTest
3.绑定静态
方法
@staticmethod
@staticmethod
def staticMethodTest():
print('这是一个静态方法')
pass
Student.staticMethodTest=staticMethodTest
__slots__
属性限制
作用:限制该class的实例能添加的属性
①只有在__slots__
变量中的属性才能被添加,没有在__slots__
变量中的属性会添加失败。可以防止其他人在调用类的时候胡乱添加属性或方法。
==ps.==在未定义__slots__
后,类的实例不再存储在__dict__
,而是存储在__slots__
中,可以节省内存空间
语法
class A(object):
__slots__=('属性1','属性2')
在设定了__slots__
后无法添加__slots__
之外的属性,比如gender,如下例所示:
class Student(object):
__slots__ = ('name','age')
def __str__(self):
return '姓名{} 年龄{} 性别{}'.format(self.name,self.age,self.gender)
pass
xw=Student()
xw.name='小王'
xw.age=30
xw.gender='男'
print(xw)
结果
Traceback (most recent call last):
File "E:/python/python_study/Day9/__slots__.py", line 10, in <module>
xw.gender='男'
AttributeError: 'Student' object has no attribute 'gender'
②__slots__
属性子类不会继承,只能在当前类中生效。如果子类中也添加__slots__
,不用声明具体的属性,可以继承父类限制的属性**(如果在子类的__slots__
中重复声明父类中的属性,则会占用多余的内存空间,时没有必要的)**,但同样的,如果子类中的__slots__
声明了新的属性,则在子类中可以添加新的属性
class Student(object):
__slots__ = ('name','age')
def __str__(self):
return '姓名{} 年龄{}'.format(self.name,self.age)
pass
class subStudent(Student):
__slots__ = ('pro')
def __str__(self):
print('{}...{}...'.format(self.name,self.pro))
pass
pass
ln=subStudent()
ln.name='临安'
ln.pro='环境科学'
print(ln.name,ln.pro)
课后作业
1.Python中new方法作用是什么?
用来创建实例对象,只有以objec为基类 才能有这个方法
2.什么是单例模式?
要求一个类有且只有一个实例,并且提供一个全局的访问点
3.私有化方法与私有化属性在子类中能否继承?
不能继承
4.在Python中什么是异常?
程序在执行的过程中发生的错误
5.Python如何处理异常?
根据类型设定异常捕获分类。
6.Python 中异常处理语句的一般格式。
try:
…
except:
…
else:
…
finally:
7.__slots__
属性的作用
①限制属性的随意输入
②节省内存空间
8.私有化属性的作用
保护数据
9.在类外面是否能修改私有属性
不可以直接修改,要通过方法去实现,还可以借助属性函数property去实现
10.如果一个类中,只有指定的属性或这方法能被外部修改,那么如何限制外部修改
通过设定