使用__slots__
一、实例和类动态绑定方法
1、实例动态绑定方法
绑定的方法只有这一个实例可以使用,该类的其他实例不能用
from types import MethodType
class Student ( object ) :
pass
def set_age ( self, age) :
self. age = age
s = Student( )
s. set_age = MethodType( set_age, s)
s. set_age( 25 )
print ( s. age)
2、类动态绑定方法
def set_score ( self, score) :
self. score = score
Student. set_score = set_score
二、使用__slots__限制实例属性绑定
就是定义一个tuple类型的类属性来限制实例属性的动态添加,类还是可以不受限制动态绑定属性的 下面的代码表示除了name和age不能加其他的属性了这个类的实例 注意一点子类不受父类slots的影响,除非子类中也定义了 slots,这样子类实例允许定义的属性就是自身的slots加上父类的slots
class Student ( object ) :
__slots__ = ( 'name' , 'age' )
使用@property
@property
广泛应用在类的定义中,用来定义属性可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性下面就是property的使用方法,age没有定义setter,是一个只读属性;使用的时候取值和赋值都是直接进行,不必通过get/set方法;property本质就是一个装饰器
class Student ( object ) :
@property
def birth ( self) :
return self. _birth
@birth. setter
def birth ( self, value) :
self. _birth = value
@property
def age ( self) :
return 2015 - self. _birth
@property
def score ( self) :
return self. _score
@score. 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
多重继承
单一的继承结构导致如果程序比较庞大,我们需要设计的类就会很多,继承的结构会十分复杂 python中可以实现多继承,可以大大减少类的数量和继承结构的复杂程度 python中多继承的方式被称为 MixIn ,具体来说就是:在设计类的继承关系时,主线都是单一继承下来的,如果需要 混入 额外的功能,通过多重继承就可以实现 MixIn 的目的就是给一个类增加多个功能,这样一来我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类
class Dog ( Mammal, Runnable) :
pass
定制类
python 类中的特殊变量可以帮助我们用来定制类 比如前面的__slots__
可以限制实例属性添加,__len__
可以作用于len()
函数
class Demo ( object ) :
def __len__ ( self) :
return 100
d = Demo( )
print ( len ( d) )
一、__str__
就是类似于java中的toString方法,打印对象相关信息的 需要注意的是这个方法只会在print方法中被调用,交互模式直接输入对象变量回车显示对象信息内容和__repr__
有关,保证二者一样的定义就可以保证无论是print还是直接变量输出都是我们想看到的对象信息的输出
class Student ( object ) :
def __init__ ( self, name) :
self. name = name
def __str__ ( self) :
return 'Student object:(%s)' % self. name
s = Student( "allen" )
print ( s)
二、__iter__
如果一个类想被用于for … in循环,就必须实现一个__iter__()
方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()
方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环
class Fib ( object ) :
def __init__ ( self) :
self. a = 0
self. b = 1
def __iter__ ( self) :
return self
def __next__ ( self) :
self. a, self. b = self. b, self. a + self. b
while self. a > 10000 :
raise StopIteration( )
return self. a
fib = Fib( )
for i in range ( 10 ) :
print ( next ( fib) , end= " " )
for f in fib:
print ( f)
三、__getitem__
适当实现__getitem__
可以让自定义的类实现类似list的索引取值和切片等操作 相关的还有__setitem__
和__delitem__
,这些所有的方法如果有恰当的实现我们自定义的类完全就可以实现list、dict等容器的行为功能,这也是动态语言的鸭子类型的体现
class Fib ( object ) :
def __getitem__ ( self, item) :
if isinstance ( item, int ) :
a, b = 0 , 1
for x in range ( item) :
a, b = b, a + b
return b
if isinstance ( item, slice ) :
stop = item. stop
start = item. start
step = item. step
if start is None :
start = 0
if step is None :
step = 1
a, b = 1 , 1
L = [ ]
for i in range ( stop) :
if i >= start and ( i - start) % step == 0 :
L. append( a)
a, b = b, a + b
return L
fib = Fib( )
print ( fib[ 5 ] )
print ( fib[ : 5 ] )
print ( fib[ 0 : 8 ] )
print ( fib[ 0 : 8 : 2 ] )
print ( fib[ 0 : 8 : 3 ] )
四、__getattr__
这个的作用就是当我们试图获取一个对像的属性的时候,python解析器首先会搜索这个对象里面是否有这个属性,有的话就直接返回,没有的话就会试图调用__getattr
来返回属性,默认返回None,再没有的话就会报错 这实际上可以把一个类的所有属性和方法调用全部动态化处理了,不需要任何特殊手段
class Chain ( object ) :
def __init__ ( self, path= '' ) :
self. _path = path
def __getattr__ ( self, path) :
print ( path, end= " : " )
print ( self. _path)
return Chain( '%s/%s' % ( self. _path, path) )
def __str__ ( self) :
return self. _path
__repr__ = __str__
print ( Chain( ) . status. user. timeline. list )
五、__call__
任何类,只需要定义一个__call__()
方法,就可以直接对实例进行调用 对象和函数之间本来就没有根本上的区别,使用了可调用的对象概念后,二者之间的界限更加模糊了 将可调用对象看成函数,那么我们就可以在运行期间动态创建函数 通过callable()函数可以判断一个对象是否是可调用对象
class Haha ( ) :
def __call__ ( self, * args, ** kwargs) :
print ( 'call-test' )
Haha( ) ( )
print ( callable ( Haha( ) ) )
使用枚举类
定义一个class类型,然后每个常量都是class的一个唯一实例,就是所谓的枚举类型 枚举的本质就是一组离散的整数,默认是从1开始的,但是也可以自己指定
一、python提供的枚举支持
from enum import Enum
Month = Enum( 'Month' , ( 'Jan' , 'Feb' , 'Mar' , 'Apr' , 'May' , 'Jun' , 'Jul' , 'Aug' , 'Sep' , 'Oct' , 'Nov' , 'Dec' ) )
print ( Month. Mar)
print ( Month. Mar. value)
for name, member in Month. __members__. items( ) :
print ( name, '=>' , member, ',' , member. value)
二、自定义枚举类
from enum import Enum, unique
@unique
class Weekday ( Enum) :
Sun = 0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
使用元类
一、type()方法
type()函数既可以返回一个对象的类型,又可以创建出新的类型 我们在py文件中进行class的定义,本质上最后还是由编译器通过type方法为我们创建类 动态语言的灵活性体现之一就在于可以动态创建类,这对于静态语言是比较难实现的 type创建类第一个参数是类名,第二个是父类元组,第三个是类方法和属性的定义
def fn ( self, text= 'world' ) :
print ( 'hello %s' % text)
def f1 ( self, age) :
self. age = age
Hello = type ( "Hello" , ( object , ) , { 'hello' : fn, 'name' : 'mike' , '__init__' : f1} )
h = Hello( 12 )
h. hello( 'allen' )
h. hello( )
print ( h)
print ( Hello)
print ( type ( h) )
print ( type ( Hello) )
print ( h. name)
print ( Hello. name)
print ( h. age)
二、metaclass(元类)
连接起来就是:先定义metaclass,就可以创建类,最后创建实例 metaclass允许你创建类或者修改类,你可以把类看成是metaclass创建出来的实例
1、元类的简单使用
通过自定义的元类,这里就给自定义的list加上了一个add方法
class listmetaClass ( type ) :
def __new__ ( cls, name, bases, attrs) :
attrs[ 'add' ] = lambda lis, ite: lis. append( ite)
return type . __new__( cls, name, bases, attrs)
class MyList ( list , metaclass= listmetaClass) :
pass
l = MyList( )
l. add( '1' )
l. add( '54' )
l. add( '65' )
print ( l)
1、用元类写一个简单orm框架