(第七集——第一章)python面向对象
程序设计分类
面向过程
面向过程好比精心设计好一条流水线,是一种机械式的思维方式。
# 优点: 复杂度的问题流程化,进而简单化(一个复杂的问题,分成一个个小的步骤去实现,实现小的步骤将会非常简单) # 缺点: 一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。# 应用场景: 一旦完成很少改变的场景,例子有Linux內核,git,以及Apache HTTP Server等面向对象
对象是特征与技能的结合体,面向对象更加注重对现实世界的模拟,
优点:
程序的扩展性强。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:
编程的复杂度远高于面向过程
无法像面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果.
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方.
类与对象
类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,类是一系列对象相似的特征与技能的结合体。
类就是将数据与操作数据的方法组合到一起,实现数据与功能是统一.
属性查找
类的属性
# 数据属性:类的数据属性是所有对象共享的 print(id(s1.school)) # 4377347328 print(id(s2.school)) # 4377347328# id是python的实现机制,并不能真实反映内存地址, 如果有内存地址,还是以内存地址为准 # 函数属性:类的函数属性是绑定给对象用的 print(OldboyStudent.learn) # <function OldboyStudent.learn at 0x1021329d8> print(s1.learn) # <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>> print(s2.learn) # <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>> # 类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样,类的函数属性是绑定给对象使用的备注:在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类…最后都找不到就抛出异常
绑定到对象的方法的特殊之处
#改写 class OldboyStudent:school='oldboy'def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexdef learn(self):print('%s is learning' %self.name) #新增self.namedef eat(self):print('%s is eating' %self.name)def sleep(self):print('%s is sleeping' %self.name)s1=OldboyStudent('李坦克','男',18) s2=OldboyStudent('王大炮','女',38) s3=OldboyStudent('牛榴弹','男',78) 类中定义的函数(没有被任何装饰器装饰的)是类的函数属性, 类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数: OldboyStudent.learn(s1) #李坦克 is learning OldboyStudent.learn(s2) #王大炮 is learning OldboyStudent.learn(s3) #牛榴弹 is learning 类中定义的函数(没有被任何装饰器装饰的), 其实主要是给对象使用的,而且是绑定到对象的, 虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用, 谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理) s1.learn() #等同于OldboyStudent.learn(s1) s2.learn() #等同于OldboyStudent.learn(s2) s3.learn() #等同于OldboyStudent.learn(s3)注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self 类即类型:提示:python的class术语与c++有一定区别,与 Modula-3更像。python中一切皆为对象,且python3中类与类型是一个概念,类型就是类.#类型dict就是类dict >>> list <class 'list'>#实例化的到3个对象l1,l2,l3 >>> l1=list() >>> l2=list() >>> l3=list()#三个对象都有绑定方法append,是相同的功能,但内存地址不同 >>> l1.append <built-in method append of list object at 0x10b482b48> >>> l2.append <built-in method append of list object at 0x10b482b88> >>> l3.append <built-in method append of list object at 0x10b482bc8>#操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3 >>> l1.append(3) >>> l1 [3] >>> l2 [] >>> l3 []#调用类list.append(l3,111)等同于l3.append(111) >>> list.append(l3,111) #l3.append(111) >>> l3 [111]
对象之间的交互
class Garen: #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄;camp='Demacia' #所有玩家的英雄(盖伦)的阵营都是Demacia;def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...;self.nickname=nickname #为自己的盖伦起个别名;self.aggressivity=aggressivity #英雄都有自己的攻击力;self.life_value=life_value #英雄都有自己的生命值;def attack(self,enemy): #普通攻击技能,enemy是敌人;enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。 class Riven:camp='Noxus' #所有玩家的英雄(锐雯)的阵营都是Noxus;def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54;self.nickname=nickname #为自己的锐雯起个别名;self.aggressivity=aggressivity #英雄都有自己的攻击力;self.life_value=life_value #英雄都有自己的生命值;def attack(self,enemy): #普通攻击技能,enemy是敌人;enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。
继承与派生
继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。子类会“”遗传”父类的属性,从而解决代码重用问题。
python中类的继承分为:单继承和多继承 class ParentClass1: #定义父类passclass ParentClass2: #定义父类passclass SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClasspassclass SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类pass 查看继承: >>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>) 经典类与新式类: 只有在python2中才分新式类和经典类,python3中统一都是新式类 在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类 在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类 如: >>> ParentClass1.__bases__ (<class 'object'>,) >>> ParentClass2.__bases__ (<class 'object'>,)继承与抽象(先抽象再继承)
抽象: 继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承 抽象分成两个层次:1.将奥巴马和梅西这俩对象比较像的部分抽取成类; 2.将人,猪,狗这三个类比较像的部分抽取成父类。 (抽象最主要的作用是划分类别) 继承: 基于抽象的结果,通过编程语言去实现它,是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。 抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。继承与重用性
在开发程序的过程中,如果我们定义了一个类A,然后又新建立另外一个类B,但类B的大部分内容与类A的相同时,可以不用重新写一个类B,采用类的继承的概念。 通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用 class Hero:def __init__(self,nickname,aggressivity,life_value):self.nickname=nicknameself.aggressivity=aggressivityself.life_value=life_valuedef move_forward(self): print('%s move forward' %self.nickname)def move_backward(self):print('%s move backward' %self.nickname)def move_left(self):print('%s move forward' %self.nickname)def move_right(self):print('%s move forward' %self.nickname)def attack(self,enemy):enemy.life_value-=self.aggressivityclass Garen(Hero): # 继承Hero类passclass Riven(Hero): # 继承Hero类passg1=Garen('草丛伦',100,300) r1=Riven('锐雯雯',57,200)print(g1.life_value) r1.attack(g1) # 调用父类中的方法 print(g1.life_value)''' 运行结果 243 ''' class Foo:def f1(self):print('Foo.f1')def f2(self):print('Foo.f2')self.f1() # 因为self表示子类Bar的对象,所以会调用子类Bar类中的f1函数class Bar(Foo):def f1(self):print('Foo.f1')b=Bar() b.f2() ''' 打印结果: Foo.f2 Foo.f1 '''
派生
当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。 class Riven(Hero):camp='Noxus'def attack(self,enemy): #在子类中定义新的attack,不再使用父类的attack,不会影响父类print('from riven')def fly(self): #在子类中定义新的函数print('%s is flying' %self.nickname) 在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能, 应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值class Riven(Hero):camp='Noxus'def __init__(self,nickname,aggressivity,life_value,skin):Hero.__init__(self,nickname,aggressivity,life_value) #调用父类功能self.skin=skin #新属性def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类Hero.attack(self,enemy) #调用功能print('from riven')def fly(self): #在自己这里定义新的print('%s is flying' %self.nickname)r1=Riven('锐雯雯',57,200,'比基尼') r1.fly() print(r1.skin)''' 运行结果 锐雯雯 is flying 比基尼'''
组合与重用性
软件重用除继承外还有组合,指的是在一个类中以另外一个类的对象作为数据属性,称为类的组合:>>> class Equip: #武器装备类 ... def fire(self): ... print('release Fire skill') ... >>> class Riven: #英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类 ... camp='Noxus' ... def __init__(self,nickname): ... self.nickname=nickname ... self.equip=Equip() #用Equip类产生一个装备,赋值给实例的equip属性 ... >>> r1=Riven('锐雯雯') >>> r1.equip.fire() #可以使用组合的类产生的对象所持有的方法 release Fire skill 组合与继承都是有效地利用已有类的资源的方式。但是二者的概念和使用场景不同:1.继承的方式: 通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人2.组合的方式: 用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日, 教授教python和linux课程,教授有学生s1、s2、s3...当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好: class People:def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexclass Course:def __init__(self,name,period,price):self.name=nameself.period=periodself.price=pricedef tell_info(self):print('<%s %s %s>' %(self.name,self.period,self.price))class Teacher(People):def __init__(self,name,age,sex,job_title):People.__init__(self,name,age,sex)self.job_title=job_titleself.course=[]self.students=[]class Student(People):def __init__(self,name,age,sex):People.__init__(self,name,age,sex)self.course=[]t1=Teacher('egon',18,'male','沙河霸道金牌讲师') s1=Student('牛榴弹',18,'female')python=Course('python','3mons',3000.0) linux=Course('linux','3mons',3000.0)#为老师egon和学生s1添加课程 t1.course.append(python) # 将python对象添加到老师 course列表属性中 t1.course.append(linux) # 将linux对象添加到 老师course列表属性中 s1.course.append(python) # 将python对象添加到 学生course列表属性中#为老师egon添加学生s1 t1.students.append(s1)#使用 for obj in t1.course: # t1.course属性保存的是Cource类的对象obj.tell_info() # obj此时代表的是Cource类的对象,"""结果:<python 3mons 3000.0><linux 3mons 3000.0>"""接口与归一化设计
接口提取了一群类共同的函数,可以把接口当做一个函数的集合。然后让子类去实现接口中的函数。
归一化设计:
只要是基于同一个接口实现的类,所有这些类产生的对象在使用时,在用法上都一样。好处:
1、让使用者无需关心对象的类是什么,只要知道这些对象都具备某些功能,降低使用者的使用难度。
2、 归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合。
(如:有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,
他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,
还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样)模仿interface接口
抽象类
python模仿Interface代码只是看起来像接口,并未起到接口的作用,子类完全可不实现接口 ,这就用到了抽象类
抽象类:
抽象类是一个特殊的类,只能被继承,不能被实例化,采用内置模块实现
类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
从设计角度去看,如果类是从现实对象抽象而来的,抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法.
抽象类与接口:
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。抽象类是一个介于类和接口之间的概念,同时具备类和接口的部分特性,可以用来实现归一化设计.
继承实现的原理
Python中子类可以同时继承多个父类,如A(B,C,D),
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
python继承原理
python对于自定义的每一个类,python会计算出一个方法解析顺序(MRO)列表, MRO列表就是一个简单的所有基类的线性顺序列表:F.mro() # 等同于F.__mro_,查看继承顺序_ [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]实现继承时,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法实现,它实际就是合并所有父类的MRO列表,并遵循如下三条准则: 1.子类会先于父类被检查 2.多个父类会根据它们在列表中的顺序被检查 3.如果对下一个类存在两个合法的选择,选择第一个父类子类中调用父类的方法
方法一:指名道姓,即父类名.父类方法() #_*_coding:utf-8_*_ __author__ = 'Linhaifeng'class Vehicle: #定义交通工具类Country='China'def __init__(self,name,speed,load,power):self.name=nameself.speed=speedself.load=loadself.power=powerdef run(self):print('开动啦...')class Subway(Vehicle): #地铁def __init__(self,name,speed,load,power,line):Vehicle.__init__(self,name,speed,load,power) # 初始化父类中的构造方法,为父类中的内存提供参数self.line=linedef run(self):print('地铁%s号线欢迎您' %self.line)Vehicle.run(self) # 调用父类中的run方法,此时不会报错,因为上面调用了父类中的构造方法,内存中有该类,传入的参数为Subway对象line13=Subway('中国地铁','180m/s','1000人/箱','电',13) line13.run() # 调用子类中的run方法,该方法中包含调用父类中的方法,所以最终会调用父类中的方法 方法二:super():class Vehicle: #定义交通工具类Country='China'def __init__(self,name,speed,load,power):self.name=nameself.speed=speedself.load=loadself.power=powerdef run(self):print('开动啦...')class Subway(Vehicle): #地铁def __init__(self,name,speed,load,power,line):#super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)super().__init__(name,speed,load,power) # 初始化父类中的方法self.line=linedef run(self):print('地铁%s号线欢迎您' %self.line)super(Subway,self).run() # 调用父类中的方法,将Subway的对象作为参数传入class Mobike(Vehicle):#摩拜单车passline13=Subway('中国地铁','180m/s','1000人/箱','电',13) line13.run() # 两者区别: 强调:二者使用哪一种都可以,但最好不要混合使用 1、即使没有直接继承关系,super仍然会按照mro继续往后查找 #指名道姓:父类名.父类方法() class A:def __init__(self):print('A的构造方法') class B(A):def __init__(self):print('B的构造方法')A.__init__(self)class C(A):def __init__(self):print('C的构造方法')A.__init__(self)class D(B,C):def __init__(self):print('D的构造方法')B.__init__(self)C.__init__(self)pass f1=D() #A.__init__被重复调用 ''' D的构造方法 B的构造方法 A的构造方法 C的构造方法 A的构造方法 '''#使用super() class A:def __init__(self):print('A的构造方法') class B(A):def __init__(self):print('B的构造方法')super(B,self).__init__()class C(A):def __init__(self):print('C的构造方法')super(C,self).__init__()class D(B,C):def __init__(self):print('D的构造方法')super(D,self).__init__()f1=D() #super()会基于mro列表,往后找 ''' D的构造方法 B的构造方法 C的构造方法 A的构造方法 '''总结: 当使用super()函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次 (注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)多态与多态性
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪:import abc class Animal(metaclass=abc.ABCMeta): #同一类事物:动物@abc.abstractmethoddef talk(self): # 抽象类方法定义passclass People(Animal): #动物的形态之一:人def talk(self):print('say hello')class Dog(Animal): #动物的形态之二:狗def talk(self):print('say wangwang')class Pig(Animal): #动物的形态之三:猪def talk(self):print('say aoao') 文件有多种形态:文本文件,可执行文件:import abc class File(metaclass=abc.ABCMeta): #同一类事物:文件@abc.abstractmethoddef click(self):passclass Text(File): #文件的形态之一:文本文件def click(self):print('open file')class ExeFile(File): #文件的形态之二:可执行文件def click(self):print('execute file')多态性是指在不考虑实例类型的情况下使用实例:
向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。
多态性分为静态多态性和动态多态性:
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:如下
封装
python中用双下划线开头的方式将属性隐藏起来(设置成私有的):#其实这仅仅这是一种变形操作且仅仅只在类定义阶段发生变形 #类中所有双下划线开头的名称如__x都会在类定义时自动变形成:_类名__x的形式:class A:__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__Ndef __init__(self):self.__X=10 #变形为self._A__Xdef __foo(self): #变形为_A__fooprint('from A')def bar(self):self.__foo() #只有在类内部才可以通过__foo的形式访问到.# A._A__N是可以访问到的, # 但是在外部是无法通过__x这个名字访问到。 注意:1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。 2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形注意:1.python的封装机制并没有真正限制从外部直接访问属性, 当知道类名和属性名就可拼出名字:_类名__属性进行访问, 如a._A__N,该操作并非严格意义上的限制外部访问,只是一种语法意义上的变形,主要用来限制外部的直接访问。 2.变形的过程只在类的定义时发生1次,在定义后的赋值操作,不会变形 3.在继承中,父类如果不想让子类重写自己的方法,可将方法定义为私有#正常情况 >>> class A: ... def fa(self): ... print('from A') ... def test(self): ... self.fa() ... >>> class B(A): ... def fa(self): ... print('from B') ... >>> b=B() >>> b.test() from B#把fa定义成私有的,即__fa>>> class A: ... def __fa(self): #在定义时就变形为_A__fa ... print('from A') ... def test(self): ... self.__fa() #只有通过在自己类中对__fa()方法进行调用,即调用_A__fa ... >>> class B(A): ... def __fa(self): ... print('from B') ... >>> b=B() >>> b.test() # 调用父类中的test方法中封装的__fa()方法,传入的参数为b对象 from A
封装不是单纯意义的隐藏
1:封装数据:将数据隐藏不是目的。隐藏后对外提供操作该数据的接口,可在接口附加上对该数据操作的限制, 以此完成对数据属性操作的严格控制: class Teacher:def __init__(self,name,age):# self.__name=name # 封装属性# self.__age=age # 封装属性self.set_info(name,age)def tell_info(self):print('姓名:%s,年龄:%s' %(self.__name,self.__age))def set_info(self,name,age): # 对传入的参数进行验证if not isinstance(name,str): # 类型判断raise TypeError('姓名必须是字符串类型') # 抛出异常if not isinstance(age,int):raise TypeError('年龄必须是整型')self.__name=name # 验证通过,对封装的属性进行赋值self.__age=aget=Teacher('egon',18) t.tell_info()t.set_info('egon',19) t.tell_info() # 2:封装方法:目的是隔离复杂度封装方法举例: 1. 电视机本身是一个黑盒子,隐藏了所有细节,但是一定会对外提供了一堆按钮,这些按钮也正是接口的概念,所以说,封装并不是单纯意义的隐藏!!!2. 快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。#取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做 #隔离了复杂度,同时也提升了安全性class ATM:def __card(self):print('插卡')def __auth(self):print('用户认证')def __input(self):print('输入取款金额')def __print_bill(self):print('打印账单')def __take_money(self):print('取款')def withdraw(self):self.__card() # 调用在同一类中封装的方法self.__auth()self.__input()self.__print_bill()self.__take_money()a=ATM() a.withdraw() 3: 了解 python并不会真的阻止访问私有属性,模块也遵循这种约定, 如果模块名以单下划线开头,那from module import *时不能被导入, 但采用from module import _private_module依然可以导入。 调用一个模块的功能时会遇到单下划线开头的(socket._socket,sys._home,sys._clear_type_cache), 这都是私有,原则上是供内部调用的,作为外部调用时也可以用。python要像与其他编程语言一样,严格控制属性的访问权限, 需借助内置方法如__getattr__封装与扩展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。
这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
总结
以上是生活随笔为你收集整理的(第七集——第一章)python面向对象的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 电大计算机应用基础形考任务4答案,最新国
- 下一篇: 基于百度地图的python开发服务端_百