-
对类的属性可以做出一些限制,需声明
__slots__
属性。
一般情况下,只限制类自身属性。当存在继承关系时,分情况如下:
子父类都有该属性,那么父类受自身影响,子类继承父类的限制,双重影响;
父类有该属性,子类没有,那么父类受自身影响,子类不受影响;
子类有该属性,父类没有,那么父类和子类都不受影响。 -
针对私有变量,简化
getter、setter
方法。 -
对一些方法(比如
__str__
、__repr__
等等)的用途作出简单介绍。
直接看例子和注释:
class Person:
# 限制Person类只能有name、age属性,注意是tuple类型
__slots__ = ('name', 'age')
# print(p)调用该方法,如果不自定义__str__方法,会输出<__main__.Person object at 0x00000000028DBB38>
# 自定义之后,就可以输出指定格式了。
def __str__(self):
return 'Person object (name: %s)' % self.name
# 命令行执行p后,会调用该方法
__repr__ = __str__
def do(self):
print('person...')
class Student(Person):
__slots__ = ('sex',)
p = Person()
p.name = 'tom'
print(p.name)
print(p)
s = Student()
s.age = 23
print(s.age)
class Teacher:
def __init__(self, name):
self._name = name
# 简化getter方法,针对私有变量
@property
def name(self):
# _name不能和函数名同名,即不能写成self.name
return self._name
# 简化setter方法,声明@property之后,就会有@函数名.setter装饰器
@name.setter
def name(self, name):
if isinstance(name, str):
self._name = name
else:
raise ValueError('str is required')
t = Teacher('fuck')
print(t.name)
t.name = 'tom'
print(t.name)
继承时,主线一般都是单一继承下来。当需要扩展功能时,只需设计额外的功能类,多重继承即可。这种设计一般称为MixIn。比如:
#会跑
class RunnableMixIn:
def do(self):
print('run...')
#会飞
class FlyMixIn:
def do(self):
print('fly...')
#多重继承,当父类中至少有两个父类拥有同样的方法时,子类调用该方法时遵循拓扑排序。关于拓扑排序会在下一篇当中专门介绍。
class My(Person, FlyMixIn, RunnableMixIn):
pass
m = My()
m.do()
如果想把对象定义成像list一样操作数据,需定义下面几个方法:
# 斐波那契数列
class Fib:
def __init__(self):
self.a = 0
self.b = 1
# 当需要迭代对象时,需要定义__iter__和__next__方法
def __iter__(self):
return self
def __next__(self):
self.a, self.b = self.b, self.a + self.b
return self.a
# 当需要和list一样用下标取值时,需要定义__getitem__方法
# item可能是下标,也可能是slice对象,当需要和list一样使用切片时,需做一下判断
# 如果把对象看成dict,item就看成是key
def __getitem__(self, item):
if isinstance(item, int):
a, b = 1, 1
for i in range(item):
a, b = b, a + b
return a
elif isinstance(item, slice):
# start stop可能为负数,这里暂时只考虑正数
start = item.start
if start is None:
start = 0
stop = item.stop
value = []
a, b = 1, 1
for i in range(stop):
if i >= start:
value.append(a)
a, b = b, a + b
# 每几个取一个
step = item.step
new_value = []
if step is not None and step != 1:
for i in range(len(value)):
if i * step < len(value) - 1:
new_value.append(value[i * step])
return new_value
else:
return value
# 给对象进行赋值的方法
def __setitem__(self, key, value):
pass
# 删除对象某个元素的方法
def __delitem__(self, key):
pass
# 当我们get对象中不存在的属性时,会报错,自定义__getattr__方法可以对没定义的属性进行赋值
# 如果该属性已经定义了,该方法针对该属性的赋值就无效
def __getattr__(self, item):
if item == 'c':
return 100
for v in Fib():
if v < 100:
print(v)
else:
break
print(Fib()[2])
print(Fib()[:10])
print(Fib()[:10:2])
print(Fib().c)
链式调用,定义__getattr__()和__call__()方法,利于组装url
class Chain:
def __init__(self, path=''):
self._path = path
# 当实例.属性不存在时,调用该方法
def __getattr__(self, path):
return Chain('%s/%s' % (self._path, path))
def __str__(self):
return self._path
__repr__ = __str__
# 对象实例()会调用该方法
def __call__(self, args):
return Chain('%s/%s' % (self._path, args))
print(Chain().status.user.timeline.list) --> 结果:/status/user/timeline/list
print(Chain().users('michael').repos) --> 结果:/users/michael/repos
# callable(obj) 判断obj是否是callable,class中必须要有__call__方法,部分函数例外
print(callable(Chain())) --> 结果:True
print(callable([1, 2])) --> 结果:False
print(callable(max)) --> 结果:True
type()函数可以查看变量或者函数的类型。
# 类型是class type
print(type(Chain))
# 类型是class Chain
print(type(Chain()))
type(args1, args2, args3)函数还可以可以创建类。
args1: 类名
args2: 父类tuple
args3: 类中方法名绑定方法
一般采用class Xxx声明类,Python解释器遇到class定义时,只是扫描一下class定义的语法,然后调用type()方法创建class,所以动态语言Python本身支持运行期动态创建class。
def fn(self, name='233'):
print('name: %s' % name)
# 创建类
Test = type('Test', (object,), dict(test=fn))
# name: HelloTest
Test().test('HelloTest')
网友评论