根据同一个类建立的实例(或对象)具有相同的方法,但是他们各自可以有不同的数据。
类是对同一种事物的抽象(即一种事物所具有的相同部分),在 python 中使用关键字 class 来定义一个类,下面是一个最简单的类的定义
class Person:
pass
以上代定义了一个空的类,该类不存在任何的属性和方法。从属于类的变量我们称之为类的属性,从属于类的函数我们称之为类的方法。
属性有两种类型,从属于某一个类本身或从属于摸一个类的实例。从属于类的示例的我们称之为示例属性,从属于类本身的我们称之为类属性。
通过实例变量或 self 关键字可以给实例绑定属性
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
class Person:
def __init__(self, name):
self.name = name
person = Person('Bob')
person.age = 31
print(person.name)
print(person.age)
print(Person.name)
print(Person.age)
以上代码执行结果如下
Bob
31
Traceback (most recent call last):
File "class.py", line 13, in <module>
print(Person.name)
AttributeError: type object 'Person' has no attribute 'name'
以上代码使用实例 person 和 self 分别定义了属性 age 和 name,在访问属性时通过实例 person 可正常获取 age 和 name 的值,但是当使用类 Person 来访问属性 age 和 name 是 python 提示 type object 'Person' has no attribute 'name',即类 Person 不存在属性 name。
如果类 Person本身需要一个属性,可以直接在类中定义,它属于 Person 类本身,所有通过 Person 实例化的示例均可访问该属性。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
class Person:
name = 'Person'
def __init__(self, age):
self.age = age
person1 = Person(23)
person2 = Person(33)
print(Person.name)
print(person1.name)
print(person1.age)
print(person2.name)
print(person2.age)
以上代码执行结果如下
Person
Person
23
Person
33
通过以上代码可以看出属性 name 直接在类中进行定义,不仅类 Person 可访问该属性,Person 的实例 person1 和 person2 同样可以访问该属性。
示例属性仅在该示例内可以使用。类属性不仅类可使用,通过该类实例化的实例同样可使用。
既然类的属性在类的实例中可使用,那么实例属性和类属性相同此时会发生什么呢,让我们来看以下代码。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
class Person:
name = 'Person'
def __init__(self, name, age):
self.name = name
self.age = age
person = Person('Bob', 33)
print(person.name)
print(person.age)
print(Person.name)
以上代码运行结果如下
Bob
33
Person
通过以上代码可以看出,当类属性和实例属性相同时,实例属性并不会覆盖类属性的值,通过实例访问时获取的是实例属性,通过类访问时获取到的是类属性。
在编写代码时要尽量避免出现类属性和实例属性相同的情况,因为此时实例属性会覆盖类属性,可能会得到与预期不同的结果。
在以上我们看到的代码中类或示例的属性对所有人都是可见,事实上使用类的初衷是隐藏内部的数据,通过方法来操作数据,从目前来说这与我们的初衷相悖。那么如果要隐藏内部属性该怎么做呢?我们可以在属性的名称前加上两个下划线,在 Python 中,实例的变量名如果以 __ 开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。我们将以上代码修改如下:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def print_age():
print("%s age is %s" % (self.name, self.age))
person = Person('Bob', 33)
person.print_age()
print(person.__age)
以上代码运行结果如下
Bob age is 33
Traceback (most recent call last):
File "<stdin>", line 14, in <module>
AttributeError: 'Person' object has no attribute '__age'
如上所示类的属性不能直接访问,这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。但是如果想要获取或修改内部属性改怎么处理,我们可以通过增加 get 和 set 方法来实现。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
def print_age():
print("%s age is %s" % (self.name, self.age))
def get_name():
return self.__name
def get_age():
return self.__age
def set_name(name):
self.__name = name
def set_age(age):
self.__age = age
person = Person('Bob', 33)
person.print_age()
print(person,get_age())
person.set_age(34)
print(person,get_age())
以上代码运行结果如下
Bob age is 33
33
34
类的方法既类中的函数,和普通函数不同的是类的方法第一个参数是 self,但是在调用该方法时不需要传入 self。除此之外,类的方法和普通函数没有什么区别,因此你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
方法中的 self 是必须的,即使没有其它参数也必须有 self 参数。
在前面的代码中总是看到 __init__ 方法,__init__ 方法是类的一个特殊方法,它有一个名字叫初始化函数,它在类被实例化时立即运行,它可以对任何你需要操作的目标对象进行初始化操作。就像前面的示例中所使用的,你不必显式调用该函数,在类的实例化过程中 python 会自动调用该函数。
需要注意的是在 __init__ 方法前后分别有两个下划线。