Python类的定义与实例化
在Python中,通过class关键字定义一个类,比如我们需要定义一个人的类。按照 Python 的编程习惯,类名以大写字母开头。因此可以这样定义:
class Person: pass
注意,在这个Person类的定义里面,并没有继承任何类,除了这样定义以外,还可以有以下两种定义方式。
class Person(): pass class Person(object): pass
定义了类之后,就可以对类进行实例化了,实例化是指,把抽象的类,赋予实物的过程。比如,定义好Person这个类后,就可以实例化多个Person出来了。
创建实例使用类名+(),类似函数调用的形式创建:
class Person(object): pass
xiaohong = Person()
xiaoming = Person()
Python实例属性的定义
虽然前面我们已经通过Person类创建出xiaoming、xiaohong等实例,但是这些实例看上去并没有任何区别。在现实世界中,一个人拥有名字、性别、年龄等等的信息,在Python中,可以通过以下的方式赋予实例这些属性,并且把这些属性打印出来。
xiaohong.name = 'xiaohong'
xiaohong.sex = 'girl'
xiaohong.age = 13
print(xiaohong.name)
print(xiaohong.sex)
print(xiaohong.age)
除此以外,这些属性也可以和普通变量一样进行运算。比如xiaohong长大了一岁:
xiaohong.age = xiaohong.age + 1
Python实例属性的初始化
在定义 Person 类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,init()方法被自动调用,我们就能在此为每个实例都统一加上以下属性:
class Person(object):
def __init__(self, name, sex, age):
self.name = name
self.sex = sex
self.age = age
*需要注意的是,init() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法),*后续参数则可以自由指定,和定义函数没有任何区别。
定义类后,就可以相应的实例化对象了,需要注意的是,在实例化的时候,需要提供除self以外的所有参数。
xiaoming = Person(‘Xiao Ming’, ‘boy’, 13)
xiaohong = Person(‘Xiao Hong’, ‘girl’, 14)
而访问这些属性的方式和之前的一样:
print(xiaohong.name)
print(xiaohong.sex)
print(xiaohong.age)
# 但当访问不存在的属性时,依然会报错
print(xiaohong.birth)
Python类属性
类和实例对象是有区别的,类是抽象,是模板,而实例则是根据类创建的对象,比如类:动物,只是一个抽象,并没有动物的详细信息,而猫、狗等,则是具体的动物,是类的对象。
在前面,实例对象绑定的属性只属于这个实例,绑定在一个实例上的属性不会影响其它实例;同样的,类也可以绑定属性,但是类的属性不属于任何一个对象,而是属于这个类。如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
定义类属性可以直接在 class 中定义,比如在前面的Animal类中,加入地域的类属性:
class Animal(object):
localtion = 'Asia'
def __init__(self, name, age):
self.name = name
self.age = age
在上面的代码中,localtion就是属于Animal这个类的类属性,此后,通过Animal()实例化的所有对象,都可以访问到localtion,并且得到唯一的结果。
dog = Animal('wangwang', 1)
cat = Animal('mimi', 3)
print(dog.localtion) # ==> Asia
print(cat.localtion) # ==> Asia
# 类属性,也可以通过类名直接访问
print(Animal.localtion) # ==> Asia
类属性也是可以动态添加和修改的,需要注意的是,因为类属性只有一份,所以改变了,所有实例可以访问到的类属性都会变更:
Animal.localtion = 'Africa'
print(cat.localtion) # ==>Africa
print(dog.localtion) # ==>Africa
Python类属性和实例属性的优先级
可以看到,属性可以分为类属性和实例属性,那么问题就来了,如果类属性和实例属性名字相同时,会怎么样,这就涉及Python中类属性和实例属性的优先级的问题了。
我们可以做一个实验,在前面类定义的基础上,在实例属性中,也初始化一个localtion的属性。
class Animal(object):
localtion = 'Asia'
def __init__(self, name, age, localtion):
self.name = name
self.age = age
self.localtion = localtion
接着我们初始化两个实例,并把localtion打印出来。
dog = Animal('wangwang', 1, 'GuangDong')
cat = Animal('mimi', 3, 'ChongQing')
print(dog.localtion) # ==> GuangDong
print(cat.localtion) # ==> ChongQing
print(Animal.localtion) # ==> Asia
可见,在类属性和实例属性同时存在的情况下,实例属性的优先级是要高于类属性的,在操作实例的时候,优先是操作实例的属性。
另外,当实例没有和类同名的时候,通过实例对象,依然可以访问到类属性。
class Animal(object):
localtion = 'Asia'
def __init__(self, name, age):
self.name = name
self.age = age
cat = Animal('mimi', 3)
print(cat.localtion) # ==> Asia
那通过实例,可不可以修改类属性呢?我们来尝试一下:
cat.localtion = 'Africa'
print(Animal.localtion) # ==> Asia
这里依然打印了Asia,可见通过实例是无法修改类的属性的,事实上,通过实例方法修改类属性,只是给实例绑定了一个对应的实例属性:
# 新增的实例属性
print(cat.localtion) # ==> Africa
//把count改为私有__count,这样实例变量在外部无法修改__count
//参考代码:
class Animal(object):
__count = 0
def __init__(self, name):
Animal.__count = Animal.__count + 1
self.name = name
print(Animal.__count)
p1 = Animal('Cat')
p2 = Animal('Dog')
print(Animal.__count)
//结果
Traceback (most recent call last):
File "index.py", line 12, in
print(Animal.__count)
AttributeError: type object 'Animal' has no attribute '__count'
1
2
Python中的访问限制
并不是所有的属性都可以被外部访问的,这种不能被外部访问的属性称为私有属性。私有属性是以双下划线’__'开头的属性。
# 类私有属性
class Animal(object):
__localtion = 'Asia'
print(Animal.__localtion)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Animal' has no attribute '__localtion'
# 实例私有属性
class Animal(object):
def __init__(self, name, age, localtion):
self.name = name
self.age = age
self.__localtion = localtion
dog = Animal('wangwang', 1, 'GuangDong')
print(dog.name) # ==> wangwang
print(dog.age) # ==> 1
print(dog.__localtion)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute '__localtion'
在外部访问私有属性将会抛出异常,提示没有这个属性。
虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。
私有属性是为了保护类或实例属性不被外部污染而设计的。