python基础学习(九)--class and instance
#!/usr/local/bin/python3
# -*- coding: utf-8 -*
class Student(object): # 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且调用时不传递该参数。除此之外,类的方法和普通函数没有什么区别。 # 如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问 外部不能访问 def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s:%s' % (self.__name, self.__score)) bart = Student('梁辉', 100) bart.print_score()
# 双下划线开头的实例变量不能直接访问是因为 就__name而言,python解释器对外把它解释为_Student__name,所以仍然可以通过_Student__name访问__name 但是并不建议这么些 因为不同版本的python解释器可能会把__name改成不用的变量名
# 一、*****类的继承和多态*****
# 判断一个变量是否是某个对象的实例可以用isinstance判断
print(isinstance(bart, Student))
# 静态语言VS动态语言
# 对于静态语言(例如java)来说,如果需要传入Animal类型,则传入的对象必须是animal或者他的子类,否则无法调用run()方法
# 而对于python来说,不一定需要传入animal类型数据 只需要保证传入的对象有一个run()方法就行
# class Timer(object):
# def run(self):
# print('start...')
# 这就是动态语言的'鸭子类型',他并不要求严格的继承体系,一个对象只要看起来像鸭子,走起路来像鸭子,那他就可以被看作为鸭子
# python的file-like object 就是一种鸭子类型。对真正的文件对象 他有一个read()方法 。但是许多对象 只要有read()方法 都被视为file-like object
# 继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。
#
# 动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的
# 二、**************** 使用type()判断对象类型
print(type(bart))
# 如果需要判断一个对象是否是函数 可以使用types模块中定义的常量 FunctionType、BuiltinFunctionType、LambdaType、GeneratorType
# 判读一个变量是否是某个类的实例 可以使用isinstance()判断
print(isinstance(bart, Student))
# 能用type()判断的基本类型也可以用isinstance判断
print(isinstance('a', str))
# 三、************************* 使用dir()
# 使用dir()函数可以获取对象 的所有属性和方法 他返回一个包含字符串的list
print(dir(bart))
# 类似__xxx__的属性和方法在py中都是有特殊用途的 比如__len__方法返回长度,py中 使用len()函数获取一个对象的长度 实际上 在len()函数内部 它自动取调用该对象的__len__方法 所以
print(len('ABC'))
print('ABC'.__len__())
# 这两种写法是等价的
# 除此之外 还可以使用getattr() setattr() 以及 hasattr()
# 使用get时 如果获取一个不存在的属性 会抛出AttributeError的错误
# getattr()第三个参数可以设置默认值
# 假设我们希望从文件流fp中读取图像,我们首先要判断该fp对象是否存在read方法,如果存在,则该对象是一个流,如果不存在,则无法读取。hasattr()就派上了用场。
#
# 请注意,在Python这类动态语言中,根据鸭子类型,有read()方法,不代表该fp对象就是一个文件流,它也可能是网络流,也可能是内存中的一个字节流,但只要read()方法返回的是有效的图像数据,就不影响读取图像的功能。
# 四、在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉累的属性,而当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
#
# 实例属性属于各个实例所有,互不干扰;
#
# 类属性属于类所有,所有实例共享一个属性;
#
# 不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
# 五、使用__slots__
# 如果我们想要限制实例的属性,比如,只允许对Student实例添加name和age属性
# 为了达到限制的目的,python允许在定义class 的时候,定义一个特殊的变量__slots__,来限制该class实例能添加的属性
class Person(object):
__slots__ = ('name', 'age')
# __slots__仅对当前实例有效 对于继承的子类择不生效 除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
# 六、使用@property
# 使用python内置的@property装饰器可以吧一个方法变成一个属性调用
# @property的使用把一个getter方法变成一个属性,只需要加上@property就好了,此时@property本身又创建了另一个装饰器,@score.setter,负责把一个setter方法变成属性赋值,于是我们就拥有一个可控的属性操作
class Car(object): @property def speed(self): return self._speed @speed.setter def speed(self, value): if not isinstance(value, float): raise ValueError('speed must be float') if value < 0 or value > 255.00: raise ValueError('speed must between 0~255') self._speed = value @property def color(self): return 'black' car = Car() car.speed = 99.00 print(car.speed) print(car.color)
# 可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:比如car object中的color属性