面向对象编程

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