访问限制
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))
实例变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
注意__XX__,是特殊变量,特殊变量是可以直接访问的,不是private
如果看到类似于:_name这样的实例变量外部是可以访问的,
但是按照约定俗称的规定,当你看到这样的变量时,
“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”
双下划线开头的实例变量也可以访问,不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,
所以,仍然可以通过_Student__name来访问__name变量,但是不要这么干,
因为不同版本的Python解释器可能会把__name改成不同的变量名
最后注意下面的这种错误写法:
>>> bart = Student('Bart Simpson', 59)
>>> bart.get_name()
'Bart Simpson'
>>> bart.__name = 'New Name' # 设置__name变量!
>>> bart.__name
'New Name'
继承多态
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Eating meat...')
判断一个变量是否是某个类型可以用isinstance()判断:
>>> isinstance(a, list)
True
>>> isinstance(b, Animal)
True
>>> isinstance(c, Dog)
True
def run_twice(animal):
animal.run()
animal.run()
对于静态语言(例如Java)来说,如果需要传入Animal类型,
则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
对于Python这样的动态语言来说,则不一定需要传入Animal类型。
我们只需要保证传入的对象有一个run()方法就可以了:
class Timer(object):
def run(self):
print('Start...')
获取对象信息
>>> type('t')
<class 'str'>
>>> type (None)
<class 'NoneType'>
>>>
type()也可以判断函数或者类
>>> type(abs)
<class 'builtin_function_or_method'>
type()函数返回对应的Class类型
>>> type('abc')==str
True
>>> type('abc')==type(123)
False
判断一个对象是否是函数怎么办?可以使用types模块中定义的常量
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
对于class的继承关系来说,使用type()就很不方便,我们要判断class的类型,
可以使用isinstance()函数
>>> a = Animal()
>>> d = Dog()
>>> h = Husky()
然后,判断:
>>> isinstance(h, Husky)
True
能用type()判断的基本类型也可以用isinstance()判断:
>>> isinstance('a', str)
True
>>> isinstance(123, int)
True
>>> isinstance(b'a', bytes)
True
并且还可以判断一个变量是否是某些类型中的一种
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
使用dir()获取一个对象的所有的属性和方法
>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
>>> class MyDog(object):
... def __len__(self):
... return 100
...
>>> dog = MyDog()
>>> len(dog)
100
仅仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态:
>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
紧接着,可以测试该对象的属性:
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
获取对象方法
>>> hasattr(obj, 'power') # 有属性'power'吗?
True
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81
如果可以直接写
sum = obj.x + obj.y
就不要写:
sum = getattr(obj, 'x') + getattr(obj, 'y')
一个正确的用法的例子如下:
def readImage(fp):
if hasattr(fp, 'read'):
return readData(fp)
return None
实例属性和类属性
实例属性属于各个实例所有,互不干扰;
类属性属于类所有,所有实例共享一个属性;
不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
>>> class Student(object):
... name = 'Student'
...
>>> s = Student() # 创建实例s
>>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
Student
>>> print(Student.name) # 打印类的name属性
Student
>>> s.name = 'Michael' # 给实例绑定name属性
>>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
Michael
>>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
Student
>>> del s.name # 如果删除实例的name属性
>>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
Student
网友评论