类实际上就是一个数据结构,对于python而言,它是一个相似于字典的结构。当根据类建立了对象以后,这个对象就有了一个数据结构,包含一些赋值了的属性。在这一点上,它和其它语言的struct的做用是相似的:存储数据并提供数据检索功能。java
例如,下面是史上最简单的类:python
class Person: pass
pass关键字表示这个类没有实际的逻辑体。这里只是定义了一个类,这个类的对象初始化时不会存听任何数据。如今,构造一个对象,让它和dict同样存放一些数据:数据结构
p = Person() # 构造对象 p.name = "longshuai" # 建立对象的属性name p.age = 23 # 建立对象的属性age
如今,Person的实例对象p中就存放了两个属性:p.name和p.age。能够直接去检索存放在p中的数据:函数
print(p.name) # 输出"longshuai" print(p.age) # 输出23
也可使用dict来存储这些数据:学习
>>> d={} >>> d["name"]="longshuai" >>> d["age"]=23 >>> print(d["name"]) longshuai >>> print(d["age"]) 23
在数据存储方面,它们的做用是彻底等价的。实际上对象/类在内部就是使用一个名为__dict__
的dict类型来存放它所拥有的数据的。code
>>> p.__dict__ {'name': 'longshuai', 'age': 23}
上面的name和age属性是在构建了对象以后附加上去的,若是想要建立对象时就存放好数据,能够定义类的构造函数__init__()
。例如:对象
class Person: def __init__(self,name,age): self.name = name self.age = age
而后建立对象的时候,传递name参数和age参数便可。blog
>>> p = Person("longshuai",23) >>> p.__dict__ {'name': 'longshuai', 'age': 23}
若是想定义这个类公有的数据,能够将公有属性定义为类的属性。好比中国人都是黄皮肤:get
class Person: skin = "yellow" def __init__(self,name,age): self.name = name self.age = age
这样每次建立Person的对象实例时,每一个对象都会有相同的肤色:yellow。但注意,这个skin属性是类属性,不是对象属性,它是存放在类的名称空间中的。当对象真的须要这个属性的时候,会临时去检索类的名称空间来获取。看下面的__dict__
字典便可知道:it
>>> p = Person("longshuai",23) >>> p.__dict__ {'name': 'longshuai', 'age': 23} >>> p.skin 'yellow'
但注意,按照面向对象的封装原则,在类中定义类变量属性是不合理的,由于要在外部访问它须要经过x.y
的方式,这意味着打开了封装好的"黑匣子",暴露了属性。除非真的有须要,不然能够将类变量的定义放进构造函数__init__()
中,这样每一个初始化的对象都会有该属性。
在面向对象的角度上考虑,通常是不建议直接在类的外部经过x.name
的方式赋值、取值的。而是定义对应的方法,经过方法来取得对应的值。这两类方法称为setter、getter方法:setter用于赋值或设置属性值,getter用于取得属性值。
class Person: skin = "yellow" def __init__(self,name,age): self.name = name self.age = age def set(self,job): self.job = job return self def get(self): return self.name,self.age,self.job
上面的set方法用于设置一个新属性job。get用于返回对象的3个属性。
>>> p = Person("longshuai",23) >>> p.set("manager") >>> name, age, job = p.get() >>> print([name,age,job]) ['longshuai', 23, 'manager']
须要注意,setter方法能够有多种类型的返回值,经常使用的有4种:
这4种返回值都很常见,特别是第三种用来串联对象方法的时候很是好用。修改上面的set方法:
class Person: skin = "yellow" def __init__(self,name,age): self.name = name self.age = age def set(self,job): self.job = job return self def get(self): return self.name,self.age,self.job
上面的set()返回self对象自身。因而串联set()和get():
>>> p = Person("longshuai",23) >>> name,age,job = p.set("manager").get()
不管使用何种返回值方式,都不会真正影响程序的使用。但使用合理的返回值类型,可能会简化代码的编写。另外,决定了返回值的方式后,就不要再去修改,由于极可能会牵一发而动全身。
上面的getter返回了多个值,但通常来讲getter只返回一个对应的属性。好比getname()返回name属性,getage()返回age属性等。这样须要定义多个getter方法。
def get_name(self): return self.name def get_age(self): return self.age def get_job(self): return self.job
不少时候能够合并setter和getter方法。合并的方式是判断方法的参数,若是调用方法的时候给了参数,就表示setter,没有给定参数,就表示是getter。
例如,对于job属性:
def set_get_job(self, job=None): if job: self.job = job else: return self.job
如今能够以给参数和不给参数两种不一样的方式来调用set_get_job()方法:
p = Person("longshuai", 23) p.set_get_job("manager") # 给了参数,说明是setter job = p.set_get_job() # 没给参数,说明是getter
上面解释了各类setter、getter的方式,还解释了将它们进行合并。
实际上在python中访问、设置、删除对象属性的时候,大概有如下几种方式:
getter()
、setter()
、deleter()
方法__getattr__()
、__setattr__()
、__delattr__()
运算符,这决定了x.y
的访问、赋值方式以及del x.y
的方式__getattribute__()
方法这些还未介绍到的属性管理方式,在后面的文章中会逐渐展开解释。
本文介绍了各类设置对象属性的方式,属性其实就是数据,对象/类就是属性的容器,这一点很重要。我最开始学java的面向对象时,虽然对类和对象有那些教科书式的理解,但始终没有感觉到类/对象其实就是一种用来存储数据的数据结构。直到学习了Python/Perl,我才意识到这一点,而后理解面向对象就容易的多了。