面向对象设计中最基础的3个概念:数据封装、继承和多态
使用_ slots _
_ slots _的作用:限制实例的属性
为了达到限制的目的,在定义class时,定义一个_ slots _特殊变量,来限制该class实例添加的属性:
注意:
1、_ slots _仅对当前类实例起作用,对继承的子类是不起作用的
2、如果子类中也定义_ slots ,那么子类实例允许添加的属性就是自身的 slots 加上父类的 slots _
3、使用_ slots _添加属性时,一定要给属性加上引号
方法:为了给各个实例都绑定方法,可以给class绑定方法
通常情况下,添加方法可直接定义在类中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
class Student(object):
__slots__=('name','age') #用tuple定义允许绑定的属性名称
s=Student() #创建一个实例
s.name='Maria'
s.age=23
# s.score=99 由于在类Student中限制了属性,所以添加score就会报错
print("s.name:",s.name)
print("s.age:",s.age)
print("给s实例添加score属性后,报错类型为:")
try:
s.score=99
except AttributeError as e:
print("AttributeError:",e)
print(' ')
print("下面定义了子类:")
class Graduate(Student): #继承了Student类,那么也继承了Student类的_ _slots_ _
__slots__=('score') #这在子类中也定义了_ _slots_ _
#看出下面g.name和g.age都正常,说明子类继承了Student类的_ _slots_ _
g=Graduate()
g.score=99
g.name='shirley'
g.age=34
print("g.name,g.age:",g.name,g.age)
print("g.score:",g.score)
image.png
@property
class Student(object):
@property
def score(self):
return self._score #是self._score,不是self.score,中间的下划线不能省略
@score.setter
def score(self,value): #都是raise ValueError, V和E要大写,先判断输入的数是不是Int,再判断是否在100以内
if not isinstance(value,int):
raise ValueError("please input an integer")
elif value<0 or value>100:
raise ValueError("请输入0到100之间的数!!!")
else:
self._score=value
s=Student()
s.score=99
print("s.score:",s.score)
print(" ")
s1=Student()
s1.score=999
print("s1.score的分数:",s1.score)
image.png
class Screen(object):
__width = 0
def get_width(self):
return self.__width
@property
def width2(self):
return self.__width
s = Screen()
print("type(s.get_width)类型为:",type(s.get_width)) # <class 'method'>
print("type(s.width2)类型为:",type(s.width2)) # <class 'int'>
image.png
实战:请利用@property给一个Screen对象加上width和height属性,以及一个只读属性resolution:
class Screen(object):
@property
def width(self):
return self._width
@width.setter
def width(self,value):
self._width =value
@property
def height(self):
return self._height
@height.setter
def height(self,value):
self._height=value
@property
def resolution(self): #此处将resolution定义为只读属性
return self.width*self.height
s = Screen()
s.width = 1024
s.height = 768
print('resolution =', s.resolution)
if s.resolution == 786432:
print('测试通过!')
else:
print('测试失败!')
运行结果:
image.png
多重继承
参考:https://kevinguo.me/2018/01/19/python-topological-sorting/
多重:多个, 多重继承:即同时继承多个对象
通过多重继承,一个子类就可以同时获得多个父类的所有功能
MixIn
在设计类的继承关系时,通常,主线都是单一继承下来的,但是,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为MixIn.
python允许使用多重继承,因此,MixIn就是一种常见的设计
只允许单一继承的语言(如JAVA),不能使用MixIn设计
目的:MixIn主要解决对同一对象用不同标准来分类的问题。从性别划分,你是男人;从国家划分,你是中国人;从职业划分,你是程序员; mixin可以轻松定义具备跟你一样特征的人:中国男程序员(天朝屌丝逗比程序员)
定制类
_ str _
将__str__方法理解成,规范化输出格式,输出用户能看懂的格式
_ repr _
1、直接显示变量调用的不是str( ),而是repr( ),两者的区别:
__str__( )返回用户看到的字符串
__repr__( )返回程序开发者看到的字符串,__repr__( )是为调试服务的
2、通常情况下,repr( )和 str( )的代码相同,所以偷懒时可以写成这种形式:repr=str ,类似赋值,把str 里的代码赋给repr
class Student(object):
def __init__(self,name):
self.name=name
s = Student("Michael")
print(s)
运行结果:
image.png下面使用了str方法后:
class Student(object):
def __init__(self,name):
self.name=name
def __str__(self):
return 'Student Object (name :%s) ' % self.name #返回的内容,自己可以修改
s=Student("Michael")
print(s)
运行结果:
image.png
str方法 return 后面的语句可以自己修改
class Student(object):
def __init__(self,name):
self.name=name
def __str__(self):
return "Hello, My name is %s" % self.name
s=Student("Michael")
print(s)
运行结果:
image.png
_ iter _
如果一个类想被用于for ……in 循环,类似list、tuple那样,就必须使用一个iter( )方法, 该方法返回一个迭代对象
举例:以斐波那契数列为例,写一个Fib类,可以作用于for循环:
#下面是__iter__方法
class fib(object):
def __init__(self):
self.a,self.b=0,1
def __iter__(self): #__iter__方法,返回一个迭代对象
return self
def __next__(self):
self.a,self.b=self.b,self.a+self.b
if self.a>100:
raise StopIteration
return self.a
for n in fib():
print(n)
image.png
_ getitem _
取下标
__getitem__( self, item)方法
item看作是“下标”, getitem( )传入的参数可能是一个int,也可能是一个切片对象slice
与 __getitem__对应的是__setitem__( )方法,__delitem__( )方法
class fib(object):
def __init__(self):
self.a,self.b=0,1
def __iter__(self): #__iter__方法,返回一个迭代对象
return self
def __next__(self):
self.a,self.b=self.b,self.a+self.b
if self.a>100:
raise StopIteration
return self.a
def __getitem__(self,n): #__getitem__方法
a,b=1,1
for x in range(n):
a,b = b, a+b
return a
f=fib()
print('f[0]:',f[0])
print("f[1]:",f[1])
print("f[2]:",f[2])
print("f[3]:",f[3])
print("f[13]:",f[13])
运行结果:
image.png
_ getattr _
正常情况下,当调用的类的方法或属性不存在时,就会报错。
class Student(object):
def __init__(self):
self.name="lily"
s=Student()
print("s.name:",s.name)
print(" ")
print("s.score:",s.score)
print("s.score函数:",s.score())
由于类中没有score属性时,调用会报错
print("s.score:",s.score)语句的报错结果:
imageprint("s.score函数:",s.score)语句的报错结果:
image添加getattr方法后: return 99,所以调用时s.score即可
class Student(object):
def __init__(self):
self.name="lily"
def __getattr__(self, attr): #__getattr__方法
if attr == 'score':
return 99
s=Student()
print("s.name:",s.name)
print(" ")
print("s.score:",s.score)
返回函数也是可以的: return lambda : 25,所以调用时是s.score()
class Student(object):
def __init__(self):
self.name="lily"
def __getattr__(self, attr): #__getattr__方法
if attr == 'score':
return lambda :25 #此处是匿名函数lambda, 之前只是返回一个数值, return 99
# print('hell')
s=Student()
print("s.name:",s.name)
print(" ")
print("s.score:",s.score())#由于return后面返回的是一个函数,因此这里调用时应该是s.score(),带上括号,
# 而如果是return 99, 则调用时不必带括号
运行结果和上面相同:
image_ call _
调用实例方法时,使用“instance.method( )”形式来调用
问题:能不能直接在实例本身上调用呢?在python中,是肯定的
结果:任何类,只需要定义一个__call( )方法,就可以直接对实例进行调用
class Student(object):
def __init__(self,name):
self.name=name
def __call__(self):
return 'my name is %s' %self.name
s=Student('lily')
print(s())
image.png
网友评论