面向对象的程序设计

时间:2022-10-24 17:21:26

  面向过程的程序设计经常用于操作系统的内核,git等,一成不变的流水线式解决一个问题,极大程度降低程序复杂性。

  面向对象的程序设计解决了程序的扩展性(类可产生各种各样的对象,对于新增技能或修改技能可使用方法直接调用),但是可控性差,因为面向对象程序一旦开始就是由对象之间交互来解决问题。

  OOD面向对象的程序设计

  先找程序中所有的对象,将对象归纳出类(并归纳出共同属性与方法和不同的属性)。

  OOP面向对象编程

  编程时先定义出类,再根据类实例化出对象。

  python3统一了类与类型的概念,python3中的类型就是类。

  编程方式:

  面向过程: 根据代码在脚本的堆叠顺序,从上到下依次执行,

  函数式编程:将相同功能的代码封装到函数中,直接调用即可,减少代码重复性,

  面向对象:对函数进行分类和封装,将同类的函数放到一个类中,使调用更简单。

类的简介

  类和对象
  类就是一个模板,模板里可以包含多个方法(即函数),方法里实现一些功能,对象则是根据模板创建的实例,通过实例对象可以执行类中的函数。

面向对象的程序设计面向对象的程序设计
#创建类  class+类名
class foo: #class是关键字,表示类,foo是类的名字
def f1(self): #类的方法1
pass
def f2(self): #类的方法2
pass

#创建对象 对象
= 类名()
bar = foo() #创建一个bar对象 ,此对象中有类中所有的方法 ,创建对象,类名称后加括号即可

#调用对象的方法 对象.方法名()
bar.f1()
bar.f2()
创建类和变量的方式

  类名+()就等于在执行Person.__init__(),执行完__init__()就会返回一个对象。这个对象类似一个字典,存着属于这个人本身的一些属性和方法。

  这里提一嘴特殊的类属性。

  类名.__name__# 类的名字(字符串)

  类名.__doc__# 类的文档字符串

  类名.__base__# 类的第一个父类

  类名.__bases__# 类所有父类构成的元组

  类名.__dict__# 查看类和对象的名称空间

  类名.__module__# 类定义所在的模块

  类名.__class__# 实例对应的类(仅新式类中)

  python中使用class定义类,在python3中只有新式类(默认继承object),而python2中有新式类(手写继承object)与经典类的区别,可使用__basic__查看继承关系。

  python2的经典类:

面向对象的程序设计

  类的一般操作形式:

class Teacher:                 #定义类
x
=1 #调用属性时不论对象还是类指向的都是同一块内存地址,属性又称静态字段
def __init__(self,name,sex,age,money):#init不能有返回值,里面放的是独有特征,共有特征使用单独函数定义
self.name=name #普通字段
self.sex
=sex
self.age
=age
self.money
=money
def search(self):#teacher调用函数或者实例化对象的绑定方法调用的不是同一块内存地址,普通方法
print("scord")
def study(self):
print("study")
print(Teacher.x) #1
t=Teacher('jeff','male','110',10)#实例化出来的对象
print(t.name) #jeff
print(t.age) #110
t.study() #study
Teacher.y=5
print(Teacher.y)#5
面向对象的程序设计面向对象的程序设计
class 类名:
类属性
= None
def __init__(self,参数1,参数2):
self.对象的属性1
= 参数1
self.对象的属性2
= 参数2

def 方法名(self):pass

def 方法名2(self):pass

对象名
= 类名(1,2) #对象就是实例,代表一个具体的东西
#类名() : 类名+括号就是实例化一个类,相当于调用了__init__方法
#括号里传参数,参数不需要传self,其他与init中的形参一一对应
#结果返回一个对象
对象名.对象的属性1 #查看对象的属性,直接用 对象名.属性名 即可
对象名.方法名() #调用类中的方法,直接用 对象名.方法名() 即可
#
对象增加属性
对象.新的属性名 = 1000
通用的class定义方法

  类是整个单独的名称空间,定义类也就是单独定义了他的名称空间(变量,函数和类名字)用来存储类中定义的所有名字,这些名字称为类的属性,静态属性就是直接在类中定义的变量,动态属性就是定义在类中的方法。可以使用__dict__查看类和对象的名称空间。实例化对象会先从自己的dict查找变量,找不到就去类(父类)的dict找,没有则会报错。

  类可以进行实例化,可以进行属性引用。对象只能属性引用。对象本身只能引用属性(变量name,sex,age。。。)。

t.name2='tom'#
del t.name2#
t.name='jerry'#
print(t.name)#

  实例化对象之间的交互:

面向对象的程序设计面向对象的程序设计
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 #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

class Garen:
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 #根据自己的攻击力,攻击敌人就减掉敌人的生命值。


#对象之间的交互
r1=Riven('芮雯雯')
g1
=Garen('草丛轮')
print(r1.life_value)
g1.attack(r1)
print(r1.life_value)
德玛西亚大战瑞文

  私有属性

  特点:

  类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

  这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

  在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

  注意:

  这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N。

class people:
__name = 'jeff'
__age = 12
def set(self):
print(self.__name)
print(self.__age)
p
= people()
#print(p.__name,p.__age) #AttributeError: 'people' object has no attribute '__name'
p.set()
运行结果;
jeff
12

  封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。

面向对象的程序设计面向对象的程序设计
#类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
def __init__(self,name,owner,width,length,high):
self.name
=name
self.owner
=owner
self.
__width=width
self.
__length=length
self.
__high=high
def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
return self.__width * self.__length * self.__high


#对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
r1.tell_area()#对于用户只要知道这个接口的功能就可以了
扩展性

  property属性

  把绑定方法装饰的像一个属性一样调用,被property装饰的属性会优先于对象的属性被使用。

面向对象的程序设计面向对象的程序设计
class People:
def __init__(self,name,weight,height):
self.name
=name
self.weight
=weight
self.height
=height
@property
def bmi(self):
return self.weight / (self.height**2)

p1
=People('egon',75,1.85)
print(p1.bmi)
property属性
面向对象的程序设计面向对象的程序设计
import math
class Circle:
def __init__(self,radius): #圆的半径radius
self.radius=radius

@property
def area(self):
return math.pi * self.radius**2 #计算面积

@property
def perimeter(self):
return 2*math.pi*self.radius #计算周长

c
=Circle(10)
print(c.radius)
print(c.area) #可以像访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''
#注意:此时的特性area和perimeter不能被赋值
c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''
但是不能赋值

  将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。

  对于obj.name我们想要在实际中会有需求能改他的值,实例.name='jeff'就是改self.__name。

  这就需要用到@name.setter,删除特性的方法@name.deleter。

面向对象的程序设计面向对象的程序设计
class People:
def __init__(self,name,SEX):
self.name
=name
# self.__sex=SEX
self.sex=SEX #self.sex='male' p1.sex='male'
@property
def sex(self):
return self.__sex #p1.__sex

@sex.setter
def sex(self,value):
# print(self,value)
if not isinstance(value,str):
raise TypeError('性别必须是字符串类型')
self.
__sex=value #p1.__sex='male'
@sex.deleter
def sex(self):
del self.__sex #del p1.__sex

p1
=People('cobila','male')
p1.sex
='female'
print(p1.sex)
特性方法的修改和删除

  类方法

class people:
country
= 'china'
# 类方法,用classmethod来进行修饰
@classmethod
def getCountry(cls): #类方法自动将类作为cls传递进函数内
return cls.country
@classmethod
def setCountry(cls, country):
cls.country
= country
p
= people()
print(p.getCountry()) # 可以用过实例对象引用
print(people.getCountry()) # 可以通过类对象引用
p.setCountry('japan')
print(p.getCountry())
运行结果:
china
china
japan

  静态方法

class people:
country
= 'china'
@staticmethod
# 静态方法使用装饰器方式绑定,并且作用和普通函数一样并不会自动传递self
def getCountry():
return people.country
print(people.getCountry())
运行结果:
china

  普通方法 默认有一个self对象传进来,并且只能被对象调用——绑定到对象

  类方法 默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用——绑定到类

  静态方法 没有默认参数,并且可以被类和对象(不推荐)调用——非绑定

面向对象三大特性

  封装

  封装顾名思义就是将东西装起来然后留出接口供用户使用,不需要知道内部发生了什么,只需要知道接口如何调用即可。在此之前所说的__init__定义的普通字段的赋值,并提供普通方法作为调用接口就是python中的封装结构。除此之外,私有属性也是封装的一种方法之一。

  好处:将变化隔离; 

  便于使用;

  提高复用性; 

  提高安全性;

  封装原则:

  将不需要对外提供的内容都隐藏起来;

   把属性都隐藏,提供公共方法对其访问。

  多重封装:

面向对象的程序设计面向对象的程序设计
#创建类
class SQL:
def __init__(self,name,passwd):
self.name
= name
self.passwd
= passwd
def create(self,sql):
print(sql)

class test:
def __init__(self,name,obj):
self.name
= name
self.obj
= obj

def add(self,arg):
print(arg)

class test2:
def __init__(self,obj):
self.obj
= obj
def iner(slef,arg):
print(arg)

#创建对象
c1
= SQL('fuzj','12313')
c2
= test('aaa',c1) #把c1对象封装到c2对象里,c2对象会有c1对象的所有方法
c3
= test2(c2) #把c2对象封装到c3对象中,c3对象会有c2对象的所有方法,同时也就有了c1对象的所有方法

#调用
c1.create(
"c1调用自身create方法")
c2.obj.create(
'c2调用c1的create方法')
c3.obj.add(
'c3调用c2的add方法')
c3.obj.obj.create(
'c3调用c1的create方法')

结果:
c1调用自身create方法
c2调用c1的create方法
c3调用c2的add方法
c3调用c1的create方法
多重封装

  继承

  对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。

面向对象的程序设计面向对象的程序设计
class ParentClass1: #定义父类
pass

class ParentClass2: #定义父类
pass

class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass
pass

class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类
pass
继承

  一个类可以继承多个父类(基类,超类),这点与其他语言略有不同,当类是经典类时,多继承情况下,会按照深度优先方式查找;当类是新式类时,多继承情况下,会按照广度优先方式查找。

class D:
def bar(self):
print('D.bar')
class C(D):
def bar(self):
print('C.bar')
class B(D):
def bar(self):
print('B.bar')
class A(B, C):
def bar(self):
print('A.bar')
a
= A()
# 经典类执行bar方法时
#
首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
#
所以,查找顺序:A --> B --> D --> C
#
在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()
#新式类执行bar方法时的查找顺序为A --> B --> C --> D
面向对象的程序设计面向对象的程序设计
class Hero:#这个英雄类包含了所有英雄都有的属性和方法
def __init__(self, nickname,
aggressivity,
life_value):
self.nickname
= nickname
self.aggressivity
= aggressivity
self.life_value
= life_value

def attack(self, enemy):
enemy.life_value
-= self.aggressivity

class Garen(Hero):#盖伦继承了英雄类
camp='Demacia'
def attack(self, enemy):
pass
def fire(self):#盖伦独有的喷火技能
print('%s is firing' %self.nickname)
class Riven(Hero):
camp
='Noxus'
g1
=Garen('garen',18,200)
r1
=Riven('rivren',18,200)
# print(g1.camp)
#
print(r1.camp)
#
g1.fire()
g1.attack(g1)
瑞文大战德玛之继承
面向对象的程序设计面向对象的程序设计
class Animal:      #父类  
def __init__(self,name,life_value,aggr):
self.name
= name
self.life_value
= life_value
self.aggr
= aggr #攻击力
def eat(self):
self.life_value
+= 10

class Person(Animal): #子类
def __init__(self,money,name,life_value,aggr):
super().
__init__(name,life_value,aggr)#super调用父类的构造方法
self.money = money #派生属性

def attack(self,enemy): #人的派生方法
enemy.life_value -= self.aggr

class Dog(Animal): #派生子类
def __init__(self,breed,name,life_value,aggr):
#Animal.__init__(self,name,life_value,aggr) #让子类执行父类的方法,就是父类名.方法名(参数),连self也得传就是super()
super().__init__(name,life_value,aggr) #super关键字——新式类
#super(Dog,self).__init__(name,life_value,aggr) #super关键字——新式类
self.breed = breed
def bite(self,person): #狗的派生方法
person.life_value -= self.aggr

def eat(self): # 父类方法的重写
super().eat()
print('dog is eating~~~ ')

ha2
= Dog('牛头梗','旺财',20000,100)
print(ha2.life_value)
ha2.eat()
print(ha2.life_value)
# super(Dog,ha2).eat() #调用父类的
print(ha2.life_value)
人狗大战之派生
面向对象的程序设计面向对象的程序设计
class Hero:
def __init__(self, nickname, aggressivity, life_value):
self.nickname
= nickname
self.aggressivity
= aggressivity
self.life_value
= life_value
def attack(self, enemy):
print('Hero attack')
enemy.life_value
-= self.aggressivity
# print(Hero.__init__)
#
print(Hero.attack)
class Garen(Hero):
camp
= 'Demacia'
def __init__(self, nickname, aggressivity, life_value, script):
Hero.
__init__(self,nickname,aggressivity,life_value)
# self.nickname = nickname
# self.aggressivity = aggressivity
# self.life_value = life_value
self.script = script
def attack(self, enemy): # self=g1,enemy=r1
# self.attack(enemy) #g1.attack()
Hero.attack(self, enemy)
print('from garen attack')
def fire(self):
print('%s is firing' % self.nickname)
# g1=Garen('garen',18,200) #Garen.__init__(g1,'garen',18,200)
g1=Garen('garen',18,200,'人在塔在') #Garen.__init__(g1,'garen',18,200)
print(g1.script)
继承更加精简了代码

  多态

  多态即多种形态,在运行时确定其状态,在编译阶段无法确定其类型,这就是多态。Python中的多态和Java以及C++中的多态有点不同,Python中的变量是弱类型的,在定义时不用指明其类型,它会根据需要在运行时确定变量的类型(个人觉得这也是多态的一种体现),并且Python本身是一种解释性语言,不进行预编译,因此它就只在运行时确定其状态,故也有人说Python是一种多态语言。

  组合

  与继承不同,组合不是什么是什么的关系,而是一种什么有什么的关系,比如学生有课程,他们是一种并行的关系而不是可以继承的关系。

class Student:
def __init__(self,ID,name,sex):
self.id
=ID
self.name
=name
self.sex
=sex
self.course_list
=[]
class Course:
def __init__(self,name,price,period):
self.name
=name
self.price
=price
self.period
=period

s1
=Student('123123123123','cobila','female')

python_obj
=Course('python',1,'7m')
linux_obj
=Course('linux',1,'2m')

s1.course_list.append(python_obj)
s1.course_list.append(linux_obj)
print(s1.course_list[0].name)
print(s1.course_list[0].price)
运行结果:
python
1

  关于组合的问题看到一个哥们在博客里的人狗大战的代码,与德玛西亚大战瑞文一样,可以有一个装备类,装备有技能,也有属性,可以通过购买装备组合,也就是人与狗的实例化对象都可以拥有装备,装备加属性加技能再进行交互。

面向对象的程序设计面向对象的程序设计
class Person:  # 定义一个人类
'''
这是一个游戏里人物的数据类型
'''
role
= 'person' # 人的角色属性都是人
def __init__(self, name, aggressivity, life_value):
self.name
= name # 每一个角色都有自己的昵称;
self.aggressivity = aggressivity # 每一个角色都有自己的攻击力;
self.life_value = life_value # 每一个角色都有自己的生命值;
def attack(self,dog):
# 人可以攻击狗,这里的狗也是一个对象。
dog.life_value -= self.aggressivity
print("{0}打了{1}一下,{1}剩余血量{2}".format(self.name, dog.name, dog.life_value))

class Dog: # 定义一个狗类
'''
这是一个游戏里狗的数据类型
'''
role
= 'dog' # 狗的角色属性都是狗
def __init__(self, name, breed, aggressivity, life_value):
self.name
= name # 每一只狗都有自己的昵称;
self.breed = breed # 每一只狗都有自己的品种;
self.aggressivity = aggressivity # 每一只狗都有自己的攻击力;
self.life_value = life_value # 每一只狗都有自己的生命值;
def bite(self,people):
# 狗可以咬人,这里的狗也是一个对象。
people.life_value -= self.aggressivity
print("{0}咬了{1}一下,{1}剩余血量{2}".format(self.name,people.name,people.life_value))

class Weapon:
'''
这是一个游戏里武器的数据类型
'''
def __init__(self,name, price, aggrev, life_value):
self.name
= name #武器名称
self.price = price #武器价格
self.aggrev = aggrev #武器伤害加成
self.life_value = life_value #武器血量加成

def update(self, obj): #obj就是要带这个装备的人
obj.money -= self.price # 用这个武器的人花钱买所以对应的钱要减少
obj.aggressivity += self.aggrev # 带上这个装备可以让人增加攻击
obj.life_value += self.life_value # 带上这个装备可以让人增加生命值

def prick(self, obj): # 这是该装备的主动技能,绞龙
obj.life_value -= 3000 # 假设攻击力是3000
print("{0}发动主动技:蛟龙==>{1}剩余血量{2}".format(self.name, obj.name, obj.life_value))


a
= Person("苍井井",10,1000)
b
= Dog("egon","狼狗",200,20000)
c
= Weapon("蛟龙鞭",1000,40,2000)
a.money
= 2000

#判断是否买的起武器
if a.money > c.price :
c.update(a)
a.weapon
= c

#大战开始
while True :
a.attack(b)
if b.life_value <= 0 :
print(b.name + "" + a.name + "打死了!")
break
a.weapon.prick(b)
if b.life_value <= 0 :
print(b.name + "" + a.name + "绞死了!")
break
b.bite(a)
if a.life_value <= 0 :
print(a.name+""+b.name+"咬死了!")
break
人狗大战实例

  接口归一化设计

  父类中定义不操作,子类进行定义的衍生(子类都有相同功能,并且功能操作可能不一样)。如果子类没有定义或者也pass了,那这个方法就没有实际的意义了,为了防止这种现象的出现要采取一些措施。

面向对象的程序设计面向对象的程序设计
class Interface:#定义接口Interface类来模仿接口的概念,python中压根就没有interface关键字来定义一个接口。
def read(self): #定接口函数read
pass

def write(self): #定义接口函数write
pass


class Txt(Interface): #文本,具体实现read和write
def read(self):
print('文本数据的读取方法')

def write(self):
print('文本数据的读取方法')

class Sata(Interface): #磁盘,具体实现read和write
def read(self):
print('硬盘数据的读取方法')

def write(self):
print('硬盘数据的读取方法')

class Process(Interface):
def read(self):
print('进程数据的读取方法')

def write(self):
print('进程数据的读取方法')



t1
=Txt()
s1
=Sata()
p1
=Process()



t1.read()
t1.write()

s1.read()
s1.write()

p1.read()
p1.write()
可能需要的场景
面向对象的程序设计面向对象的程序设计
class Animal:
def run(self):
raise AttributeError('子类必须实现这个方法')
def speak(self):
raise AttributeError('子类必须实现这个方法')
class People(Animal):
def run(self):
print('人正在走')

# def speak(self):
# print('说话')

class Pig(Animal):
def run(self):
print('pig is walking')
def speak(self):
print('哼哼哼')

peo1
=People()
# peo1.run()
peo1.speak()#异常咯
low主动抛异常

  这使得虽然大家的操作都不一样,但是调用的时候方法都是一样的,这就是归一化设计。

  这里存在一个问题,我们需要进行拓展,如果说,我们的子类没有进行父类的某一项普通方法的定义,根据广度优先的查找顺序,会在父类中找到此方法,但是此方法没有任何定义,自然这个操作毫无意义,所以我们可以在父类进行raise主动将异常抛出,或者使用abc模块自动抛出异常。

import abc
#抽象类:本质还是类,与普通类额外的特点的是:加了装饰器的函数,子类必须实现他们
class Animal(metaclass=abc.ABCMeta):
tag
='123123123123123'
@abc.abstractmethod
def run(self):
pass
@abc.abstractmethod
def speak(self):
pass
class People(Animal):
# def run(self): #子类没有定义父类有的方法,但是没有搜寻父类的方法直接报错
# pass
def speak(self):
pass

peo1
=People()
print(peo1.tag)
运行结果:
TypeError: Can
't instantiate abstract class People with abstract methods run

   注意:抽象类不能被实例化

super()函数的用法

  super在python2中的用法:

  1:super(自己的类,self).父类的函数名字

  2:super只能用于新式类

面向对象的程序设计面向对象的程序设计
class People(object):
def __init__(self,name,sex,age):
self.name
=name
self.age
=age
self.sex
=sex
def walk(self):
print('%s is walking' %self.name)
class Chinese(People):
country
='China'
def __init__(self,name,sex,age,language='Chinese'):
# self.name=name
# self.sex=sex
# self.age=age
# People.__init__(self,name,sex,age)
super(Chinese,self).__init__(name,sex,age)
self.language
=language
c
=Chinese('egon','male',18)
print c.name,c.age,c.sex,c.language
py2super
面向对象的程序设计面向对象的程序设计
class People:
def __init__(self,name,sex,age):
self.name
=name
self.age
=age
self.sex
=sex
def walk(self):
print('%s is walking' %self.name)
class Chinese(People):
country
='China'
def __init__(self,name,sex,age,language='Chinese'):
# self.name=name
# self.sex=sex
# self.age=age
# People.__init__(self,name,sex,age)
super().__init__(name,sex,age)
self.language
=language
def walk(self,x):
super().walk()
print('子类的x',x)
c
=Chinese('egon','male',18)
# print(c.name,c.age,c.sex,c.language)
c.walk(123)
py3super

  __str__

  _str__定义在类内部,必须返回一个字符串类型,打印由这个类产生的对象时,会触发执行.

面向对象的程序设计面向对象的程序设计
class People:
def __init__(self,name,age):
self.name
=name
self.age
=age
def __str__(self):
return '<name:%s,age:%s>' %(self.name,self.age)

p1
=People('egon',18)
print(p1)
str(p1)
#此时print触发----->p1.__str__()
#
所以打印结果为<name:egon,age:18>
__str__