微专业 python面向对象语法精讲笔记 第一周

第一周python面向对象基础

导学-对象:独立存在或作为目标的事务

  • 独立性:对象都存在清晰的边界,重点在于划分边界。
  • 功能性:对象都能表现出一些功能,操作或行为。
  • 交互性:对象之间存在交互:如继承和运算。

1.面向对象编程模式-“万物皆对象”

  • python语言中所有数据类型都是对象,函数是对象,模块也是对象。
  • python所有类都继承于最基础的类object。
  • python语言中数据类型的操作功能都是类方法的体现。

面向对象:以问题对象构建和应用为核心编程写程序的方式。
面向过程:以解决问题的过程步骤为核心编程写程序的方式。

2.面向对象编程模式-OOP(面向对象编程)的三个重要特性

  • 封装:属性和方法抽象,用数据和操作数据的方法来形成对象的逻辑。
  • 继承:代码复用的高级抽象,用对象之间的继承关系来形成代码复用。
  • 多态:方法灵活性的抽象。让对象的操作更加灵活,更多复用代码。

封装(encapsulation):属性和方法的抽象

  • 属性的抽象:对类的属性(变量)进行定义,隔离及保护。
  • 方法的抽象:对类的方法(函数)进行定义,隔离及保护。
  • 目标是形成一个类对外可操作性属性和方法的接口。

继承(inheritance):代码复用的高级抽象

  • 继承是面向对象设计的精髓之一。
  • 实现了以类为单位的高级抽象级别代码复用。
  • 继承是新定义类能够几乎完全使用原有类属性和方法的过程。

多态polymorphism:仅针对方法,方法灵活性的抽象

  • 参数模型的多态:一个方法能够处理多个类型的能力。
  • 参数形式的多态:一个方法能够接收多个参数的能力。
  • 多态是opp的一个传统概念,python天然支持多态,不需要特殊语法。

3.面向对象编程模式-面向对象术语概述

类(class)和对象(object)

  • 类:逻辑抽象和产生对象的模板,一组变量和函数的特性编排。
  • 对象:具体表达数据及操作的实体。相当于程序中的变量。
  • 实例化:从类到对象的过程,所有“对象”都源于某个类。

类(class)和对象(object)的分类

  • 对象:类对象、实例对象。
  • 属性:存储数据的“变量”。包括:类属性和实例属性。
  • 方法:操作数据的“函数”。包括:类方法、实例方法、自由方法、静态方法、保留方法。

类对象VS实例对象

  • 类对象:class object,维护每个python类基本信息的数据结构。
  • 实例对象:instance object,python类实例后产生的对象。
  • 这是一组概念,类对象全局只有一个,实例对象可以生成很多个。

例:

'''商品价格统计,有3个商品:电脑、打印机和投影仪,每个商品有1个
原始售价和1个折扣售价,求3个商品原始售价的和以及折扣售价的和。'''
class Product()def __init__(self,name):
		self.name=name #定义了抽象的product类,保存名字和价格等信息
		self.label_price=0 #初始价格为0
		self.real_price=0
c=Product("电脑") #产生3个对象,分别对应具体的商品
d=Product("打印机")
e=Product("投影仪")
c.label_price,c.real_price=10000,8000 #对3个对象商品赋值价格
e.label_price,e.real_price=2000,1000
d.label_price,d.real_price=1500,900
for i in [c,d,e]: #求和并输出价格
	s1+=i.label_price
	s2+=i.real_price
print(s1,s2)
'''面向过程编写可能更短,但是从语义理解上更直接利于理解'''

三个特性:封装、继承、多态

  • 继承:基类、派生类、子类、父类、超类、重载。
  • 命名空间:程序元素作用域的表达。
  • 构造和析构:生成对象和删除对象的过程。

4.类的基本构建方法-python类的构建

使用class保留字定义类

class <类名>"类描述  ‘XXXXXXXXXX’"
	<语句块>
  • 类的定义不限位置,可以包含在分支或其他从属语句块中,执行时存在即可。如:ClassName,BasicAuto,BasicCreature
  • 类的名字:可以是任何有效标识符,建议采用大写单词的组合。
  • 类描述:在类定以后首行,以独立字符串形式定义。定以后通过<类名>.__doc__属性来访问。
class DemoClass:
	"this is a demo for python class"
	pass
print(DemoClass.__doc__)
#输出为 this is a demo for python class

类对象

  • 类定以后,默认生成一个类对象。
  • 每个类唯一对应一个类对象,用于存储这个类的基本信息。
  • 类对象是type类的实例,表达为type类型。
class DemoClass:
	"this is a demo for python class"
	print("hello demo class")
print(DemoClass.__doc__)
print(type(DemoClass))
#输出为
#hello demo class
#this is a demo for python class
#
  • 类对象内直接包含的语句会被执行,因此,一般不在类定义中直接包含语句。

实例对象

  • 实例对象(instance object)的创建(最主要的使用方式)。
    • <对象名>=<类名>.([参数列表])
    • 进一步采取<对象名>.<属性名>和<对象名>.<方法名>( )体现类的功能。
class DemoClass:
	"this is a demo for python class"
	print("hello demo class")
print(type(DemoClass))
cn=DemoClass()
print(type(cn))
#输出为hello demo class
#
#

了解python类的构造函数

  • 类的构造函数用于从创建实例对象的过程。
  • 类的构造函数为实例对象创建提供了参数输入方式。
  • 类的构造函数为实例属性的定义和赋值提供了支持。

了解python类的属性和方法

  • 类的属性:类中定义的变量,用来描述类的一些特性参数。
  • 类的方法:类中定义的且与类相关的函数,用来给出类的操作功能。
  • 属性和方法是类对外交互所提供的两种接口方式。

类的构造函数

  • python使用预定义的__init__(self,<参数列表>)作为构造函数。
class <类名>:
	def __init__(self,<列参>):
		print(name)
dc1=DemoClass("老王")
dc2=DemoClass("老李")
#输出为
#老王
#老李
  • 类实例化时所使用的函数,可以接受参数并完成初始操作。
  • 通过构造函数__init__()可以为python对象提供对象

init()的使用说明

  • 参数:第一个参数约定是self表示类实例自身,其他参数是实例参数。
  • 函数名:python解释器内容定义,由双下划线__开始和结束。
  • 返回值:构造函数没有返回值,或返回None,否则产生typeerror异常。

self在类定义内部代表类的实例

  • self是python面向对象中约定的一个类参数。
  • self是代表类的实例,在类内部,self用于组合访问实例相关的属性和方法。
  • 相比,类名代表类对象本身。

属性是类内部定义的变量

  • 类属性:类对象的属性,由所有实例对象所共享。
  • 实例属性:实例对象的属性,由实例对象所独享。

属性是类内部定义的变量

class <类名>:
	<类属性名>=<类属性初值>
	def __init__(self,<参数列表>:
		self.<实例属性名>=<实例属性初值>

#例子DemoClass.count+=1可以常用于统计类被实例化了多少次。

class DemoClass:
	count=0 #类属性
	def __init__(self,name,age):
		self.name=name
		self.age=age
		DemoClass.count+=1
		#直接在类中定义或赋值,统一用<类名>.<属性名>访问。
dc1=DemoClass("老王",45)
dc2=DemoClass("老李",51)
print("总数:",DemoClass.count)
print(dc1.name,dc2.name)
#输出为
#总数:2
#老王 老李

属性是类内部定义的变量

  • 类属性访问:<类名>.<属性名>
    也可以用<对象名>.<类属性名>访问,但是无论如何类属性值是所有实例对象共享的
  • 实例类型访问:
    • 在类内部,用self .<属性名>访问。
    • 在类外部,用<对象名>.<属性名>访问。
    • 实例对象的属性,由各实例对象所独享。

类的方法:方法是类内部定义的函数

  • 实例方法:实例对象的方法,由各实例对象独享,最常用的形式。
  • 类方法:类对象的方法,由所有实例对象共享。
  • 自由方法:类中的一个普通函数,由类所在命名空间管理,类对象独享。
  • 静态方法:类中的一个普通函数,由类对象和实例对象共享。
  • 保留方法:由双下划线开始和结束的方法,保留使用,如__len__()。

实例方法是类内部定义的函数,与实例对象相关。

class <类名>def <方法名>(self,<参数列表>:
		......
  • 实例方法采用<对象名>.<方法名>(<参数列表>)方式使用。
class DemoClass:
	def __init__(self,name):
		self.name=name
	def lucky(self):#实例方法的定义,第一个参数是self
		s=0
		for c in self.name:
			s+=ord(c)%100
		return s
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc1.name,"的幸运数字是:",dc1.lucky())
print(dc2.name,"的幸运数字是:",dc2.lucky())
#输出为
#老王的幸运数字是:148
#老李的幸运数字是:115

类方法是与类对象相关的函数,由所有实例对象共享。

class <类名>:
	@classmethod #装饰器
	def <方法名>(cls,<参数列表>) #第一个参数默认保留为cls,表示一个类。
		......

  • 类方法采用<类名>.<方法名>(<参数列表>)或<对象名>.<方法名>(<参数列表>)方式使用。
  • 类方法至少包含一个参数,表示类对象,建议用cls。
  • @classmethod是装饰器,类方法定义所必须。
  • 类方法只能操作类对象所属的属性和其他类方法,不能操作(self.XXX)实例属性和实例方法。
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1

	@classmethod #类方法使用装饰器表示
	def getChrCount(cls): #类方法只能使用类属性或其他类方法
		s="零一二三四五六七八九多"
		return s[DemoClass.count]
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(dc1.getChrCount()) #类方法的调用可以用类名或对象名
print(DemoClass.getChrCount())
#输出为
#二
#二

自由方法是定义在类命名空间的普通函数

class <类名>def <方法名>(<参数列表>)......
  • 自由方法不需要使用self或cls这类参数,可以没有参数。
  • 自由方法只能操作类属性和类方法,不能操作(self.XXX)实例属性和实例方法。
  • 自由方法的使用只能使用<类名>,不能使用对象名,它只是类命名空间中的普通函数。理解为:定义在类命名空间中的函数,也可以定义在类外,习惯不同。严格上讲,它不是一个方法,它就是一个函数,只不过定义在类的命名空间中。为了统一说法,叫自由方法,仅此而已.
  • 自由方法采用<类名>.<方法名>(<参数列表>)方式使用,<类名>表示命名空间。
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	def foo():
		DemoClass.count*=100
		return DemoClass.count
dc1=DemoClass("老王")
print(DemoClass.foo())
#输出为
#100

静态方法是定义在类中的普通函数,能够被所有实例对象共享

class <类名>:
	@staticmethod
	def <方法名>(<参数列表>)
		......
  • 静态方法可以没有参数,可以理解为定义在类中的普通函数。
  • @staticmethod是装饰器,静态方法定义所必须。
  • 静态方法只能操作类属性和其他方法,不能操作实例属性和实例方法。
  • 相比于自由方法,静态方法能够使用<类名>和<对象名>两种方式使用。
  • 静态方法用<类名>.<方法名>(<参数列表>)或<对象名>.<方法名>(<参数列表>)
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	@staticmethod
	def foo():
		DemoClass.count*=100
		return DemoClass.count
dc1=DemoClass("老王")
print(DemoClass.foo())
print(dc1.foo())
#输出为
#100
#10000

保留方法由双下划线开始和结束的方法,保留使用。

class <类名>def <保留方法名><参数列表>):
		......
例:
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		Democlass.count+=1
	def __len__(self):
		return len(self.name)
dc1=DemoClass("老王")
dc2=DemoClass("小诸葛")
print(len(dc1))
print(len(dc2))
#输出为
#2
#3
  • 保留方法一般都对应类的某种操作,但操作产生时调用。

类的析构函数

  • python使用预定义的__del__()作为析构函数
class <类名>def __def__(self):
		<语句块>
	......
	'''析构函数在真是删除实例对象时被调用。'''
class DemoClass:
	def __init__(self,name):
		self.name=name
	def __del__(self):
		print("再见",self.name)

dc1=DemoClass("老王")
del dc1
#输出为
#再见 老王

del()的使用说明

  • 函数名和参数:python解释内部约定,保留方法。
  • 调用条件:当实例对象被真实删除时,才调用该函数语句。
  • 真实删除:当前对象的引用数为0或当前程序退出。
class DemoClass:
	def __init__(self,name):
		self.name=name
	def __del__(self):
		print("再见",self.name)
dc1=DemoClass("老王")
dc2=dc1 #删除dc1时,由于dc2存在,则仅删除dc1引用。
del dc1 #退出时,真实删除dc2对应对象。
print(dc2.name)
#输出结果为:
#	老王
#	再见老王
  • 实例对象:真实创建的对象,分配对象内存。
  • 实例引用:实例指针,仅分配指针内存。
  • 在删除对象前,python解释器会检查引用次数。
  • 引用次数不为0,则仅删除当前引用;0,则删除对象。
  • 如果程序退出,则由垃圾回收机制删除对象。

sys.getrefcount(<对象名>)获得对象的引用次数

  • 返回对象引用次数的方法,辅助删除对象时的分析。
  • sys.getrefcount(<对象名>)函数返回值为 被引用值+1。
  • 非特定目标,不建议自己撰写析构函数,利用python垃圾回收机制。
import sys
class DemoClass:
	def __init__(self,name):
		self.name=name
	def __del__(self):
		return "再见"+self.name
dc1=DemoClass("老王")
dc2=dc1
print(sys.getrefcount(dc1))
#输出为
#3

5.类的封装

封装EncapSulation:属性和方法的抽象

  • 属性的抽象:对类的属性(变量)进行定义,隔离及保护。
  • 方法的抽象:对类的方法(函数)进行定义,隔离及保护。
  • 目标是形成一个类对外可操作属性和方法的接口。

属性

  • 私有属性:只能在类内部访问。
  • 公开属性:可以通过类/对象名访问。
  • 属性的抽象:可以选择公开或隐藏属性,隐藏属性的内在机理。

方法

  • 私有方法:只能在类内部使用。
  • 公开方法:可以通过类/对象名访问。
  • 方法的抽象:可以选择公开或隐藏方法,隐藏方法的内部逻辑。

封装:让数据和代码成为类的过程,表达为:类-属性-方法。

公开属性:即类属性

class <类名>:
	<类属性名>=<类属性初值>
	def __init__(self,<参数列表>):
		self.<实例属性名>=<实力属性初值>

私有类属性:仅供当前类访问的类属性,子类亦不能访问。

class <类名>:
	__<私有类属性名>=<类属性初值>
	def __init__(self,<参数列表>)
		......
  • 区别:私有类属性名开始需要有两个下划线(__),如:__count
  • 只能在类的内部被方法所访问。
  • 不能通过<类名>.<属性名>和<对象名>.<属性>方式访问。
  • 有效保证了属性维护的可控性。
  • 私有实例属性:仅供当前类内部访问的实例属性,子类亦不能访问。
class DemoClass:
	__count=0 #私有类属性定义
	def __init__(self,name):
		self.name=name
		DemoClass.__count+=1 #私有类属性的内部使用
	@classmethod
	def getCount(cls):
		return DemoClass.__count #私有类属性的内部使用
dc1=DemoClass("老王")
dc2=DemoClass("老李")
print(DemoClass.getCount()) #类的类方法
  • 双下划线方法只是一种转换约定,转换后,类内原有名字发生了变化,这是一种形式上的私有。
  • python设计逻辑不明确支持私有,用print(<对象名>._DemoClass__name)仍旧可以访问。

私有方法

  • 私有方法是类内部定义并使用的函数。
class <类名>:
	def __<方法名>(self,<参数列表>...
class DemoClass:
	def __init__(self,name):
		self.__name=name
	def __getName(self):
		if self.__name!="":
			return self.__name
		else:
			return "老张"
	def printName(self):
		return "{}同志".format(self.__getName())
dc1=DemoClass("老王")
dc2=DemoClass("")
print(dc1.printName(),dc2.printName())
#输出为
#老王同志 老张同志
  • 私有方法名开始需要有两个下划线(__),如__getcount()。
  • 各类方法都可以通过增加双下划线变为私有方法。
  • 私有方法从形式上保护了python类内部使用的函数逻辑。
  • 私有与公开是程序员逻辑,不是安全逻辑,重视约定。

类的保留属性

  • python解释器预留的类属性,以双下划线开头和结尾。
  • 也叫:特殊属性。
  • 作用:为理解python类提供的属性接口。
  • 属性值:具有特定含义,类定义后直接使用。
类的名称 作用
.__ doc __ 类描述,写在类定义下的首行字符串,不能继承
. __name __ 类的名称
.__ qualname __ 以.分割从模块全局命名空间开始的类名称
.__ bases __ 类所继承的基类名称
<类>. __ dict __ 包含类成员信息的字典,key是属性和方法名称,value是地址
<对象>. __ dict __ 包含对象属性信息的字典,key是属性名称,value是值
.__ class __ 对象所对应的类信息,即type信息
.__ module __ 类所在模块的名称
class DemoClass:
	"a demo class"
	def __init__(self,name):
		self.name=name
	def getName(self):
		return self.name
dc1=DemoClass("老王")
print(DemoClass.__qualname__,DemoClass.__name__,DemoClass.__bases__)
#DemoClass DemoClass(,)
class DemoClass:
	"a demo class"
	def __init__(self,name):
		self.name=name
	def getName(self):
		return self.name
dc1=DemoClass("老王")
print(DemoClass.__doc__,DemoClass.__module__,DemoClass.__class__)
print(dc1.__doc__,dc1.__module__,dc1.__class__)
#a demo class,__main__,
#a demo class,__main__,

python解释器预留的类方法,以双下划线开头和结尾。

也叫:特殊方法。
特点:双下划线开头和结尾。
作用:为操作python类提供了统一的方法接口。
方法逻辑:具有特定含义,一般与操作符有关联,类定义需要重载。

保留方法 对应操作 描述
obj.__ init __ obj=ClassName() 初始化实例对象的函数逻辑
obj.__ del __ del obj 删除实力兑现的函数逻辑
obj.__repr __ repr(obj) 定义对象可打印字符串的函数逻辑
obj.__ str __ str(obj) 定义对象字符串转换操作的函数逻辑
obj.__ bytes __ bytes(obj) 定义对象字节串转换操作的函数逻辑
obj.__ format __ obj.format() 定义对象格式化输出的函数逻辑
obj.__ hash __ hash(obj) 定义对象哈希操作的函数逻辑
obj.__ bool __ bool(obj) 定义对象布尔运算的函数逻辑
obj.__ len __ len(obj) 定义对象长度操作的函数逻辑
obj.__ reversed __ reversed(obj) 定义对象逆序的函数逻辑
obj.__ abs __ abs(obj) 定义对象绝对值的函数逻辑
obj.__ int __ int(obj) 定义对象整数转换的函数逻辑
  • 常用保留方法:比较操作。
  • python保留了超过100个各类保留方法。请参考各类型方法。
  • 保留方法对应对象、对象间、对象方法的各种操作。

6.python的继承

继承inheritance:代码复用的高级抽象

  • 继承是面向对象程序设计的精髓之一。
  • 实现了以类为单位的高级抽象级别代码复用。
  • 继承是新定义类能够几乎完全使用原有类属性与方法的过程。

继承定义

  • 父类(基类)、子类(派生类)、基类属性的继承,基类方法的继承,派生类新增属性、派生类新增方法。
  • 子类直接继承是父类。
  • 子类间接继承的是超类。

类继承的构建

  • 在定义类时声明继承关系
class <类名>(基类名)def __init__(self,<参数列表>):
		<语句块>
		......
  • 基类名可以带有路径:modulename.baseclassname
  • 派生类可以直接使用基类的属性和方法
  • 基类的属性基本等同于定义在派生类中。
  • 派生类可以直接使用基类的类属性、实例属性。
  • 派生类可以直接使用基类的各种方法。
  • 使用基类的类方法和类属性时,要用基类的类名调用
class DemoClass: #基类
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	def getName(self):
		return self.name
class HumanNameClass(DemoClass): #派生类
	def printName(self):
		return str(DemoClass.count)+self.name+"同志"#对基类类属性的使用
dc1=HumanName("老王") #对基类实例方法的使用
print(dc1.getName()) #对派生类实例方法的使用
print(dc1.printName())

两个与继承关系判断有关的python内置函数

函数 描述
isinstance(obj,cls) 判断对象obj是否是类cls的实例或子类实例,返回True/False。
issubclass(cls1,cls2) 判断类cls1是否是类cls2的子类,返回True/False
class DemoClass: #基类
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	def getName(self):
		return self.name
class HumanNameClass(DemoClass): 
	def printName(self):
		return str(DemoClass.count)+self.name+"同志"
dc1=HumanNameClass("老王")
print(isinstance(dc1,DemoClass))
printisinstance(dc1,HumanNameClass)print(issubclass(HumanNameClass,DemoClass))
#返回全True

派生类的约束

  • 派生类只能继承基类的公开属性和方法。
  • 派生类不能继承基类的私有属性和方法。

object类是python所有类的基类

  • object是python最基础类的名字,不建议翻译理解。
  • 所有类定义时默认继承object。
  • 保留属性和保留方法本质上是object类的属性和方法。

python对象的三要素:标识、类型和值

  • 标识identity:对象一旦构建不会改变,用id()获得,一般是内存地址。
  • 类型type:对象的类型,用type()
  • 值value:分为可变mutable与不可变immutable两种。

2个与基础类有关的python内置功能

函数 描述
id(x) 返回X的标识,python用内存地址表示。
x is y 判断x和y的标识是否相等,返回True/False,不判断值。
class DemoClass: #基类
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	def getName(self):
		return self.name
class HumanNameClass(DemoClass): 
	def printName(self):
		return str(DemoClass.count)+self.name+"同志"
dc1=HumanNameClass("老王")
print(id(dc1),type(dc1))
print(id(DemoClass),type(DemoClass))
print(dc1 is DemoClass)
print(type(object),type(type))
'''
86222320 
86207768 
False
 
'''

类的重载

  • 重载:派生类对基类属性或方法的再定义。
  • 属性重载:派生类定义并使用了与基类相同名称的属性。
  • 方法重载:派生类定义并使用了与基类相同名称的方法。

最近覆盖原则:重载无需特殊标记。

  • 步骤1:优先使用派生类重定义的属性和方法。
  • 步骤2:然后寻求基类的属性和方法。
  • 步骤3:再寻找超类的属性和方法。
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
class HumanNameClass(DemoClass):
	count=99
	def __init__(self,name):
		self.name=name
		HumanNameClass.count-=1
	def printCount(self):
		return str(HumanNameClass.count)+self.name
dc1=HumanNameClass("老王")
print(dc1.printCount())
#输出为
#98老王

方法重载(派生类对基类方法的再定义)

  • 完全重载:派生类完全重定义与基类相同名称的方法。直接在派生类中定义同名方法即可。
  • 增量重载:派生类扩展定义与基类相同名称的方法。增量重载:使用super()方法。
class <派生类>(基类):
	def <方法>(self,参数列表):
		super().<基类>(参数列表)
class DemoClass:
	count=0
	def __init__(self,name):
		self.name=name
		DemoClass.count+=1
	def printCount(self)return str(DemoClass.count)+self.name
		
class HumanNameClass(DemoClass):
	def __init__(self,name):
		self.name=name
	def printCount(self):
		return super().printCount()+"同志"
dc1=HumanNameClass("老王")
print(dc1.printCount())
#输出为
#0老王同志

类的多继承

class <类名>(基类1,基类2):
	def __init__(self,参数列表):
		<语句块>
		......
#基类名可以带有路径:ModuleName.BaseClassName

类多继承的使用说明

  • 所有属性和方法的使用按照“深度优先”、“从左到右”的方式选取。
  • 构造函数也参照上述原则,super()也参照上述原则。
  • 多个基类是顺序的关键。
class DemoClass:
	def __init__(self,name):
		self.name=name
	def printName(self):
		return self.name
class NameClass:
	def __init__(self,title):
		self.nick=title
	def printName(self):
		return self.nick+"同志"
class HumanNameClass(DemoClass,NameClass):
	pass
dc1=HumanNameClass("老王")
print(dc1.printName())
#输出为
#老王

你可能感兴趣的:(微专业 python面向对象语法精讲笔记 第一周)