定制类
python
定制类主要是实现特定功能,通过在类中定义特定的函数完成特定的功能。
class Student(object):
def __init__(self, name):
self.name =name
student = Student("lilei")
print(student)
str用法
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return ("self name is %s" %(self.name))
student2 = Student("hanmeimei")
print(student2)
实现__str__
函数,可以在print类对象时打印指定信息
通过实现__iter__
和__next__
同样可以使类对象产生可迭代序列,下面实现了斐波那契数列
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 > 30:
raise StopIteration()
return self.a
__iter__
返回一个可迭代对象,这里我们返回了Fib自己的对象。
__next__
是根据迭代器返回每一个迭代的序列,这里实现了运算规则,返回对象的a成员。
打印输出
for n in Fib():
print(n)
getitem用法
可以实现__getitem__
函数,这样就可以按照索引访问类对象中迭代元素了。
class OddNum(object):
def __init__(self):
self.num = -1
def __iter__(self):
return self
def __next__(self):
self.num = self.num +2
if self.num > 10:
raise StopIteration()
return self.num
def __getitem__(self,n):
temp = 1
for i in range(n):
temp += 2
return temp
for n in OddNum():
print(n)
oddnum = OddNum()
print(oddnum[3])
可以进一步完善OddNum类的__getitem__
函数,使其支持切片处理
def __getitem__(self, n):
if isinstance(n ,int):
temp =1
for i in range(n):
temp +=2
return temp
if isinstance(n, slice):
start = n.start
end = n.stop
if start is None:
start = 0
tempList = []
temp = 1
for i in range(end):
if i >= start:
temp += 2
tempList.append(temp)
return tempList
可通过如下方式调用
print(oddnum[1:4])
getattr用法
通过实现__getattr__
函数,可以在类对象中没有某个属性时,自动调用__getattr__
函数
实现__call__
函数,可以实现类对象的函数式调用
def __getattr__(self,attr):
if attr == 'name':
return 'OddNum'
if attr == 'data':
return lambda:self.num
raise AttributeError('\'OddNum\' object has no attribute \'%s\'' %attr)
def __call__(self):
return "My name is OddNum!!"
只有在没有找到属性的情况下,才调用__getattr__
,已有的属性不会在__getattr__
中查找。
print(oddnum.name)
print(oddnum.data)
#没有func函数会抛出异常
#print(oddnum.func)
#可以直接通过oddnum()函数式调用
print(oddnum())
定制类案例
下面是一个链式转化例子,用到了这些特定函数
class Chain(object):
def __init__(self, path=''):
self.path = path
def __getattr__(self,attr):
return Chain('%s/%s'%(self.path, attr))
def users(self, users):
return Chain('%s/users/%s' %(self.path, users))
def __str__(self):
return self.path
__repr__ = __str__
print(Chain().users('michael').repos)
repr表示一个对象的字符串显示,当我们打印这个对象时,如果没有实现str函数,则会调用repr函数。 另外,当我们打印datetime对象时,可以看到repr相比str目标更具有准确性,str目标在于可读性。 另外,在迭代器迭代打印的时候默认调用的是对象的repr函数。 所以在我们实现了str方法后,基本也会将其赋值给repr函数。 具体的参考连接https://www.cnblogs.com/miaoning/p/11399575.html 因为我们定义了getattr函数,所以当属性不存在时就会构造一个新的对象返回,返回的对象拼接了之前的path信息和attr属性。 我们定义了users函数,这样可以调用users函数了。但是我们可以用更简洁的办法实现各种函数的调用而不用定义他们,就是通过实现call函数,这样就可以实现链式调用。
class Chain(object):
def __init__(self, path=''):
self.path = path
def __getattr__(self,attr):
return Chain('%s/%s'%(self.path, attr))
def __call__(self, param):
return Chain('%s/%s'%(self.path, param))
def __str__(self):
return self.path
__repr__ = __str__
print(Chain().get.users('michael').group('doctor').repos)
当调用users('michael')时,因为没有定义users函数,所以会调用getattr函数,进而构造一个新的Chain对象。因为实现了call函数,所以这个对象可以被当作函数来使用,也就是Chain('michael')的方式。
enum枚举
python同样支持枚举
操作
from enum import 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)
from enum import unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6
for name , member in Weekday.__members__.items():
print(name, '=>', member, ',', member.value)