面向对象编程
python可以直接使用class进行类的创建和使用
class Animal(): def __init__(self, name): self.name = name def print_name(): print(self.name) def print_type(): print("animal") a = Animali("lili") a.print_name() # lili a.print_type() # animal
a就是类Animal的实例化对象,可以使用类定义的一些属性,但是此时我们可以在外部进行使用和操作a的name
a.name = "xiaoxiao" print(a.name) # xiaoxiao
在大部分情况,我们可能不希望对象的私有属性能随意的被外部修改和操作,如果在属性前面加上__就默认为私有变量,只能在对象内部函数能够操作
class Animal(): def __init__(self, name): self.__name = name def print_name(self): print(self.__name) def print_type(self): print("animal") a = Animali("lili") a.print_name() # lili a.print_type() # animal print(a.__name) # 'Animal' object has no attribute '__name'
而对于共有属性来说,我们可以通过getattr和hasattr来进行获取属性的值或者判断对象是否存在该属性,而不至于出现上述的报错情况
print(getattr(a, "__name"), "not fount") # not fount print(getattr(a, "print_name", "not fount")) # <bound method print_name of <__main__.Count object at 0x0000011FAFC86550>> print(hasattr(a, "__name")) # False print(haseattr(a, "print_name")) # True
当然,还有一种属性叫做类属性,属于类而不是属于实例化对象,所有的对象都可以访问,类也可以直接访问
class Animal(): count = 0 # 添加计数器,每次实例化增加1 def __init(self, name): self.__name = name Animal.count += 1 def print_name(self): print(self.__name) print(Animal.count) # 0 a = Animal("xiaoxiao") print(Animal.count) # 1 print(a.count) # 1
同样的,我们也可以给实例化对象添加自己额外的属性
a.weight = 10 print(a.weight) # 10 print(Animal.weight) # type object 'Count' has no attribute 'hehe'
也可以添加私有的方法
# MethodType可以绑定self from types import MethodType def set_name(self, name): self.name = name # 绑定自定义的函数 a.set_name = MethodType(set_name, a) a.set_name("xiao bai") print(a.name) # xiao bai
当然,我们可能不会希望使用者能随意的添加属性到实例化对象,我们可以通过slots来进行限制
class Animal(object): __slots__ = ("name", "weight") def __init__(self, name): self.name = name a = Animal("xixi") a.age = 1 print(a.age) # 'Animal' object has no attribute '_Animal__age'
class也提供了对应的getter和setter操作来监听属性的变化,当然可能比起vue来说相对难看一点
class Animal(object): def __init__(self, name): self.__name = name @property def name(self): print("get") return def.__name @name.setter def name(self, name): print("set") self.__name = name a = Animal("xiao bai") a.name = "da bai" # set print(a.name) # get # da bai
但是,如果我们只写getter那一部分的话,则会得到can't set attribute的提示,说明属性是只读属性
我们可以看到,通过打印实例化对象,会返回一段地址,看起来肥肠的难受,class里面支持修改__str__以及__repr__来个性化打印信息
class Animal(object): def __init__(self, name): self.name = name def __str__(self): return "name: " + self.name __repr__ = __str__ a = Animal("xiao bai") print(a) # name: xiaobai
同时,class也可以支持迭代器,只需要实现__iter__和__next__方法,然后不停返回下一个迭代就好,也可以实现__getitem__方法来实现下标访问
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 > 100000: raise StopIteration() return self.a f = fib() for i in Fib(): print(i) #0, 1, 1, 2, 3, 5 ......75025 class Myarr(object): def __getitem__(self, index): a, b = 1, 1 for x in range(n): a, b = b, a + b return a print(Myarr[1]) # 1
但是,如果传入的是切片的话,就会有问题了,print(Myarr()[1: 5]),所以,还需要在getitem里面处理一下
class Myarr(object): def __getitem__(self, n): if isinstance(n, int): # n是索引 a, b = 1, 1 for x in range(n): a, b = b, a + b return a if isinstance(n, slice): # n是切片 start = n.start stop = n.stop if start is None: start = 0 a, b = 1, 1 L = [] for x in range(stop): if x >= start: L.append(a) a, b = b, a + b return L print(Myarr()[1:5]) # [1,2,3,5]
一个链式调用的demo,可以用来定制api
class Chain(object): 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__ Chain().status.user.timeline.list # '/status/user/timeline/list' Chain().users('michael').repos # '/users/:user/repos'
python同时也提供了可以调用实例化对象的方法,可以将对象当做方法来调用,可以通过callable来判断一个对象或者方法能否被调用
class Animal(object): def __init__(self, name): self.name = name def __call__(self): print("my name is %s" % self.name) a = Animal("xiao bai") a() # my name is xiao bai callable(a) # True