使用__slots__
未使用__slots__,绑定 属性或函数 到 类或实例 上:
class Student(object): #暂定一种名为Student的类
pass
s=Student() #创建Student的一个实例s
s.name='Tom' #为s这个实例添加一个属性并赋值
print(s.name)
def set_age(self,age): #可以在类的定义外构造一个带有self参数的函数,以便于绑定给类
self.age=age
from types import MethodType #从模块 types 里加载功能 MethodType
s.set_age=MethodType(set_age,s) #将函数set_age绑定到实例s上
s.set_age(25)
print(s.age)
s2=Student()
def set_score(self,score):
self.score=score
Student.set_score=set_score #直接将函数 setscore 绑定到类 Studennt上
s.set_score(100)
s2.set_score(99)
print(s.score)
print(s2.score)
'''
Tom
25
100
99
'''
使用__slots__,限制实例的属性:
class Student(object):
__slots__=('name','age') #用元组定义允许绑定的属性名称
s=Student()
s.name='Tom'
s.age=20
# s.city='Putian' #没有出现在__slots__定义里的属性不能操作
# class GraduateStudent(Student):
# pass
# gs=GraduateStudent()
# gs.name='Jack' #__slots__定义的属性仅对当前类实例起作用,对其子类不起作用
class MiddleStudent(Student):
__slots__=('city') #在子类中也定义__slots__,这样子类允许定义的属性就是自身的slots加上父类的slots
ms=MiddleStudent()
ms.city='Beijing'
print(ms.city)
使用@property
限制参数的修改范围,以防胡乱修改:
class Student(object):
def set_score(self,value): #设置一个输入成绩的函数,同时可以进行错误数据检验
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0~100!')
self._score=value
def get_score(self): #再设置一个获取成绩的函数,通过这两个函数的设置,就不能随便改成绩了
return self._score
s=Student()
s.set_score(100)
print(s.get_score())
'''
100
'''
使用@property来·将类定义中的函数(方法)变成可修改属性:
class Student(object):
@property #将接下来的获取方法变成属性,其本身又创建了另一个装饰器 @score.setter
def score(self): #获取成绩的方法
return self._score
@score.setter #负责把一个输入setter方法变成属性
def score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0~100')
self._score=value
s=Student()
s.score=60 #这时的函数score就变成了属性score,可以直接赋值
print(s.score)
'''
60
'''
使用@property定义只读属性,只定义getter方法,不定义setter方法:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self,value): #biirth为可读写属性
self._birth=value
@property
def age(self):
return 2023-self._birth #age为只读属性1
多重继承
一个子类可以继承多个父类,这样的设计称为MixIn:
class Animal(object):
def fitht(self):
return ('fighting!!!')
class Artificial(object):
def think(self):
return ('thinking!!!')
class Human(Animal,Artificial):
def create(self):
return ('creating!!!')
human=Human()
print(human.fitht())
print(human.think())
print(human.create())
'''
fighting!!!
thinking!!!
creating!!!
'''
定制类
python的class中有许多类似于__slots__的方法,这些方法其实就是有特殊用途的函数,将这些函数用于类的定义中,可以帮助我们定制类。
__str__
__str__()方法是用于打印简洁易懂的实例的:
class Student(object):
def __init__(self,name):
self.name=name
def __str__(self): #__str__方法是用于描述实例自身的输出方法,可以使打印出的实例简洁明了
return 'Student object (name:%s)' % self.name
print(Student('Tom')) #打印出一个实例,实例中name的值为Tom
'''
Student object (name:Tom)
'''
若不用__str__方法,打印出的实例比较复杂:
class Student(object):
def __init__(self,name):
self.name=name
print(Student('Moss'))
'''
<__main__.Student object at 0x000002408B539390>
'''
之所以这里的实例这么复杂,是因为直接显示变量调用的不是__str__(),而是__repr__(),__str__()返回用户看到的字符串,__repr__()返回程序员看到的字符串,也就是说,__repr__()是为调试服务的。
__iter__
这个方法用于迭代类本身,这里以斐波那契数列为例:
class Fib(object):
def __init__(self):
self.a,self.b=0,1 #初始化两个计数器
def __iter__(self):
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)
__getitem__
这个方法用于下标访问:
class Fib(object):
def __getitem__(self,n):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
f=Fib()
for i in range(1,11):
print(f[i])
__getattr__
这个方法用于,当我们调用实例的一个属性时,若该属性不存在,__getattr__会尝试将我们输入的属性通过预设的条件语句进行比对,返回错误提醒:
class Student(object):
def __init__(self):
self.name='Tom'
def __getattr__(self,attr):
if attr=='score':
return 99
s=Student()
print(s.name)
print(s.score)
print(s.city) #若属性不存在于比对条件中,则会输出none
'''
Tom
99
None
'''
__call__
一个对象实例有自己的方法,要进行简易的调用,可以使用__call__方法:
class Student(object):
def __init__(self):
self.name='Tom'
def __call__(self):
return ('My name is %s.' % self.name)
s=Student()
print(s())
'''
My name is Tom.
'''
在调用之前,我们要判断这个对象是否可以调用,这就需要用到callable()函数:
print(callable(s))
print(callable(Student))
print(callable(abs))
print(callable('123'))
print(callable([1,2,3,4,5]))
'''
True
True
True
False
False
'''
使用枚举类
from enum import Enum #从enum模块中加载Enum类,即枚举类
Month=Enum('Month',('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'))
for name,member in Month.__members__.items():
print(name,'=>',member,',',member.value) #value属性是自动赋值给成员的int常量,默认从1开始计数
'''
Jan => Month.Jan , 1
Feb => Month.Feb , 2
Mar => Month.Mar , 3
Apr => Month.Apr , 4
May => Month.May , 5
Jun => Month.Jun , 6
Jul => Month.Jul , 7
Aug => Month.Aug , 8
Sep => Month.Sep , 9
Oct => Month.Oct , 10
Nov => Month.Nov , 11
Dec => Month.Dec , 12
'''
若要精确地为每个成员赋值可以从Enum派生出自定义类:
from enum import Enum,unique
@unique #unique装饰器可以检查保证没有重复值
class Weekday(Enum):
Sun=0
Mon=1
Tue=2
Wed=3
Thu=4
Fri=5
Sat=6
day1=Weekday.Thu
print(day1)
date1=Weekday.Sat.value
print(date1)
print(Weekday(0))
'''
Weekday.Thu
6
Weekday.Sun
'''
使用元类
type()
用来查看一个类型或变量的类型:
class Tree(object):
def __init__(self,height,age):
self.height=height
self.age=age
def fruit(self):
print('I\'m %d years old,%d meters high.' % (self.age,self.height))
tree=Tree(15,6)
print(type(Tree))
print(type(tree))
tree.fruit()
print(type(tree.fruit))
'''
<class 'type'> #Tree的类型就是 类 type
<class '__main__.Tree'> #tree是一个实例,它的类型就是Tree
I'm 6 years old,15 meters high.
<class 'method'> #fruit的类型就是 方法 Method
'''
type()函数还可以创建出新的类型:
def fn(self,name='world'):
print('Hello,%s.' % name)
Hello=type('Hello',(object,),dict(hello=fn)) #创建出一个class对象
h=Hello()
h.hello()
print(type(Hello))
print(type(h))
print(type(h.hello))
'''
Hello,world.
<class 'type'>
<class '__main__.Hello'>
<class 'method'>
'''
要创建出一个class,需要传入type()函数三个参数:
class的名称,用字符表示
继承的父类集合,这里的集合用元组表示,若元组内只有一个元素object,那么需要加一个逗号
最后将预先定义好的函数和这个class的方法进行逐一绑定,在括号内逐一赋值,然后转化为字典dict
metaclass
metalclass就是元类,类是元类的“实例”,元类是类的“类”,因此先定义metaclass,就可以创建类,最后创建实例。