面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
class Student(object): # 类名一般大写
def __init__(self, name, score): # 注意:特殊方法“__init__”前后分别有两个下划线!!!
self.name = name
self.score = score
def print_score(self):
print('%s %s' % (self.name, self.score))
s1 = Student('wangxuan', 90)
s1.print_score()
print(type(s1)) # 类型是student类
print(s1) # <__main__.Student object at 0x105c07ad0>是一个类的实例
在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__ ,在Python中,实例的变量名如果以__ 开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法
class Student(object):
def get_name(self):
return self.__name
def get_score(self):
return self.__score
如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法
class Student(object):
def set_score(self, score):
self.__score = score
在方法中,可以对参数做检查,避免传入无效的参数
class Student(object):
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
raise ValueError('bad score')
变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量
变量名类似_name的,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”
变量名类似__name的,一般不能从外部访问,不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
>>> bart._Student__name
'Bart Simpson'
但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name改成不同的变量名
所有实例都拥有
class Student(object):
count = 0 # 类属性
def __init__(self, name):
self.name = name
Student.count += 1 # 每次调用则加一,统计注册学生的数量
s.name = 'zhangsan'
print(s.name)
# 动态给实例绑定一个方法(只有当前实例可以使用)
def set_age(self, age): # 定义一个函数作为实例方法
self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s) # 给实例绑定方法
s.set_age(20) # 调用实例方法
print(s.age) # 打印
# 动态给类添加方法
# 给类添加方法后所有的实例都可以使用了
Student.set_age = MethodType(set_age, Student)
s2 = Student()
s2.set_age(25)
print(s2.age)
s3 = Student()
s3.set_age(30)
print(s3.age)
上面的set_age方法可以直接定义在class中,但动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现。
# 限制实例属性
class Student(object):
__slots__ = ('name', 'age') # 限制只能添加name和age
s1 = Student()
s1.name = 'zhangsan'
s1.age = 30
# s1.score = 90 # 添加不进去
try:
s1.score = 99
except AttributeError as e:
print('AttributeError:', e)
由于’score’没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。
使用__slots__要注意,__ slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。