三、属性和方法
•类由成员变量(对应于对象的属性)和成员函数(对应于对象的方法)组成。属性是对数据的封装,方法则表示对象具有的行为。
•Python的构造函数、析构函数、私有属性或方法都是通过名称约定区分的。
此外,Python还提供了一些有用的内置方法,简化了类的实现
1、类的成员属性
•Python的类的成员一般分为私有属性和公有属性,像C++有定义属性的关键字(public、private、protect),而Python没有这类关键字,默认情况下所有的属性都是“公有的”,对公有属性的访问没有任何限制,且都会被子类继承,也能从子类中进行访问。
•若不希望类中的成员在类外被直接访问,就要定义为私有属性。Python使用约定属性名称来划分属性类型。若属性的名字以两个下划线开始,表示私有属性;反之,没有使用双下划线开始的表示公有属性。类的成员变量及成员函数都同样使用这个约定。
•另外,Python没有保护类型的修饰符。
Python的实例变量和类变量:
•实例变量是以self为前缀的成员变量,没有该前缀的成员变量是普通的局部变量。
•C++中有一类特殊的属性称为静态变量。静态变量能被实例化对象调用,还可以被类直接调用。当创建新的实例化对象后,静态变量并不会获取新的内存空间,而是使用类创建的内存空间。因此,静态变量能够被多个实例化对象共享。
•在Python中静态变量称为类变量,类变量可以在该类的所有实例中被共享。
关于Python私有属性的访问:
•类的外部不能直接访问私有属性。
•Python提供了直接访问私有属性的方式,可用于程序的测试和调试。
•私有属性访问的格式:
instance._classname__attribute
•说明:
–instance表示实例化对象;
–classname表示类名;
–attibute表示私有属性
•注意:classname之前是单下划线,attribute之前是双下划线
class Fruit: def __init__(self,color): self.__color=color #定义私有变量; if __name__=="__main__": apple=Fruit('red') #创建实例对象 print(apple._Fruit__color) #调用类的私有变量;输出结果:red
# -*- coding: utf-8 -*- """ Spyder Editor This is a temporary script file. """ class Fruit(object): price=0 #定义类类变量 def __init__(self,color): self.__color=color #定义私有变量; def getColor(self): print(self.__color) #输出私有变量 @staticmethod #使用@staticmethod修饰器定义静态方法 def getPrice(): print(Fruit.price) def __getPrice(): #定义私有方法 Fruit.price=Fruit.price+10 print(Fruit.price) count=staticmethod(__getPrice) #使用staticmethod 方法定义静态方法 if __name__=="__main__": apple=Fruit('red') #创建实例对象 apple.getPrice() #使用实例调用方法 Fruit.count() #使用类名调用静态方法 banana=Fruit('yellow') Fruit.getPrice() Fruit.count()
输出方法:
0 10 10 20
#构造函数应用一 class Person(object): def __init__(self,name='',age=0): self.name=name self.age=age def __str__(self): return "Person('%s','%d')" % (self.name,self.age) if __name__=="__main__": p=Person('Jack',25) print(p) p=Person() #可以创建空对象 print(p)输出结果为:
Person('Jack','25') Person('','0')
#构造函数应用二 class Fruit(object): def __init__(self,color): self.__color=color def getColor(self): print(self.__color) def setColor(self,color): if color in ('red','black','white','gray','blue'): self.__color=color if __name__=="__main__": color='red' fruit=Fruit(color) fruit.getColor() fruit.setColor('blue') fruit.getColor() fruit.setColor('yellow') fruit.getColor() fruit.setColor('white') fruit.getColor()
输出结果:
red blue blue white
类常用的内置方法
#析构函数应用 class Fruit(object): def __init__(self,color): #构造函数 self.__color=color #初始化属性color print(self.__color) def __del__(self): #析构函数 self.__color='' print('free...') def grow(self): print('grow...') if __name__=="__main__": color='red' fruit=Fruit(color) fruit.grow() del fruit #显示调用析构函数,不然无法保证析构函数何时被运行
输出结果:
red grow... free...
内置方法
描述
__init__(self, …)
初始化对象,在创建对象时调用
__del__(self)
释放对象,在对象被删除时调用
__str__(self)
生成对象的字符串表示,在使用print语句时被调用
__repr__(self)
生成对象的官方表示,在使用print语句时被调用
__getitem__(self, key)
获取序列的所有key对应的值,等价于seq[key]
__len__(self)
在调用内联函数len()时被调用
__cmp__(src, dst)
比较两个对象src和dst
内置方法
描述
__getattr__(self, name)
获取属性的值
__getattribute__(self, name)
获取属性的值,能更好地控制
__setattr__(self, name, val)
设置属性的值
__delattr__(self,name)
删除name属性
__call__(self, *args)
将实例对象作为函数调用
__gt__(self, other)
判断self对象是否大于other对象
__lt__(self, other)
判断self对象是否小于other对象
__ge__(self, other)
判断self对象是否大于或等于other对象
__le__(self, other)
判断self对象是否小于或等于other对象
__eq__(self, other)
判断self对象是否等于other对象
(1)__getatrr__()、__setattr__()和__getattribute__()
•当读取对象的某个属性时,Python会自动调用__getattr__()方法。例如,fruit.color将转换为fruit.__getattr__(color)。
•当使用赋值表达式对属性进行设置时,Python会自动调用__setattr__()方法。
•__getattribute__()的功能与__getattr__()类似,用于获取属性的值,但__getattribute__()能提供更好的控制,使代码更健壮。
垃圾回收机制
•Python使用垃圾回收机制来清理不再使用的对象。Python提供gc模块释放不再使用的对象,Python采用“引用计数”的算法来处理回收,即:当某个对象在其作用域内不再被其他对象引用时,Python就自动清除该对象。
•Python的函数collect()可以一次性收集所有待处理的对象(gc.collect())
# -*- coding: utf-8 -*- """ Spyder Editor This is a temporary script file. """ #使用gc模块显示地调用垃圾回收器 import gc class Fruit(object):#定义水果类 def __init__ (self,name,color): #初始化 name,color 属性 self.__name=name self.__color=color def getColor(self): return self.__color #返回color def setColor(self,color): #定义color self.__color=color def getName(self): #返回name return self.__name def setName(self,color): self.__name=name #定义name class FruitShop(object): #定义水果店类 def __init__(self): self.fruits=[] def addFruit(self,fruit): #添加水果 fruit.parent=self #将Fruit类关联到FruitShop 类 self.fruits.append(fruit) if __name__=="__main__": shop=FruitShop() shop.addFruit(Fruit('apple','red')) shop.addFruit(Fruit('banana','yellow')) print(gc.get_referrers(shop)) #打印出与shop对象相关联的所有对象 print() del shop #删除shop 对象,但与其相关联的其他对象并未释放 print(gc.collect()) #显示地调用垃圾回收器,释放与shop对象关联的其他对象#获取和设置对象的属性 class Fruit(object): def __init__(self,color='red',price=0): self.__color=color self.__price=price def __getatttibute__(self,name): #获取属性的方法 return object.__getattribute__(self,name) def __setattr__(self,name,value): #设置属性的方法 self.__dict__[name]=value # __dict__字典是类的内置属性,用于记录类定义的属性 #字典中的key表示属性名,value表示属性的值 if __name__=="__main__": fruit=Fruit("blue",10) print(fruit.__dict__.get('_Fruit__color')) #获取color属性值,因为color是私有 属性 print(fruit.__dict__.get('_Fruit__price')) #所以字典的索引表示为“_Fruit__color” fruit.__dict__['_Fruit__price']=5 #使用__dict__进行赋值 fruit.__dict__['_Fruit__color']='red' print(fruit.__dict__.get("_Fruit__color")) #h获取color属性的值 print(fruit.__dict__.get("_Fruit__price")) #获取price属性的值 print(fruit.__getattribute__('_Fruit__color')) print(fruit.__getattribute__('_Fruit__price'))
输出结果:
blue 10 red 5 red 5
•去掉上例的__getattribute__() 、__setattr__()的实现代码,并不会影响输出结果,但这些方法可以实现对属性的控制,根据属性名做不同的处理。
如果类中将某个属性定义为序列,可以使用__getitem__()输出序列属性中的各个元素。
#获取对象的属性为序列中的各个元素 class FruitShop(object): def __getitem__(self,i): #获取水果店的水果 return self.fruits[i] if __name__=="__main__": shop=FruitShop() shop.fruits=['apple ', 'banana'] #给fruits 赋值 print(shop[1]) for item in shop: print(item,end='')输出结果:
banana apple banana
•__str__()用于生成对象的字符串表示。实现了该方法后,可以直接使用print语句输出对象,也可以通过函数str()触发其执行。
方法的动态特性:
•Python作为动态脚本语言,编写的程序具有很强的动态性。
•可以动态添加类的方法,将某个已经定义的函数添加到类中。添加新方法的语法格式为:
class_name.method_name=function_name
•其中,class_name表示类名,method_name表示新的方法名,function_name表示1个已经存在的函数。
•还可以对已经定义的方法进行修改。修改方法的语法格式为:
class_name.method_name=function_name
•其中,class_name表示类名,method_name表示已经存在的方法名,function_name表示1个已经存在的函数,该赋值表达式表示将函数的内容更新到方法。
#动态添加方法 class Fruit(object): pass def add(self): #定义在类外的函数 print('grow...') if __name__=="__main__": Fruit.grow=add #d动态add添加函数 fruit=Fruit() fruit.grow()输出结果:
grow...
#动态更新方法 class Fruit(object): def grow(self): print('grow...') def update(): #定义在类外的函数 print('grow......') if __name__=="__main__": fruit=Fruit() fruit.grow() fruit.grow=update #将grow方法更新为update() fruit.grow()输出结果:
grow... grow......
例题
•创建一个新类表示整数集合
–初始时集合为空
–每个特定的整数只能在集合中出现一次(注:必须在方法中强制实现)
•内部数据表示
–用一个列表存储集合中的元素
•接口
–insert(e):若整数e不存在,则插入e到集合中
–member(e):若整数e在集合中返回True,否则返回False
–remove(e):从集合中删除整数e,若不存在则出错
#动态更新方法 class intSet(object): """An intSet is a set of integers The value is represented by a list of ints,self.vals. Each int in the set occurs in self.vals exactly once.""" def __init__(self): """Create an empty set of inntergers""" self.vals=[] def insert(self,e): """Assumes e is an integer and inserts e into self""" if not e in self.vals: self.vals.append(e) def member(self,e): """Assumes e is an interger Returns True if e is in self,and False otherwise""" return e in self.vals def remove(self,e): """Assumes e is an integer and removes e from self Raises ValueError if e is not in self """ try: self.vals.remove(e) except: raise ValueError(str(e)+'not found') def __str__(self): """Returns a string representation of self""" self.vals.sort() return '{' +','.join([str(e) for e in self.vals ])+'}'
输出结果:
创建一个关于人的信息的类及相关方法(例题)
•Person:name,birthday
–Get last name
–Sort by last name
–Get age
import datetime class Person(object): def __init__(self,name): self.name=name self.birthday=None self.lastName=name.split(' ')[-1] def getLastName(self): return self.lastName def setBirthday(self,month,day,year): self.birthday=datetime.date(year,month,day) def getAge(self): if self.birthday==None: raise ValueError return ((datetime.date.today()-self.birthday).days)//365 def __lt__(self,other): if self.lastName==other.lastName: return self.name<other.name return self.lastName<other.lastName def __str__(self): return self.name p1=Person('William Eric Grimson') print(p1) print(p1.getLastName()) p1.setBirthday(1,2,1991) print(p1.getAge()) print() p2=Person('cher') print(p2.getLastName()) print() plist=[p1,p2] plist.sort() for p in plist: print(p)输出结果:
William Eric Grimson Grimson 27
cher
William Eric Grimson cher