面向对象编程
https://www.liaoxuefeng.com/
文章目录
1. 类和实例
class Student(object):
def __init__(self, name):
self.name = name
类是创建实例的模板,而实例则是一个一个具体的对象,各个实例互相独立,互不影响。
object
表示该类从哪个类继承下来的。所有类都从object
继承下来。__init__
类似构造函数。
2. 访问限制
class Student(object):
def __init__(self, name, score):
self.__name = name
self._score = score
def get_name(self):
return self.__name
__name
双下划线开头,私有变量(只能内部访问,不能外部访问);-
P
s
1
\color{blue}{{Ps}_1}
Ps1 可以通过
any_instance_name._Student__name
进行外部访问,但不建议这么干! -
P
s
2
\color{blue}{Ps_2}
Ps2 不要在外部,通过
any_instance_name.__name = "Some Value"
对私有变量进行赋值。- 这样看起来没错,实际上多创建了一个变量,很容易出问题的。
-
P
s
1
\color{blue}{{Ps}_1}
Ps1 可以通过
_score
单下划线开头,保护成员(可以外部访问,但当作私有变量);- 有
私有成员
和保护成员
的作用是为了更好地封装起来(个人理解)。
3. 继承和多态
3.1 继承
class Animal(object):
def run(self):
print("Animal is running...")
class Dog(Animal):
pass
class Cat(Animal):
pass
子类
Dog
和Cat
继承了父类
Animal
的全部功能。
3.2 多态
class Animal(object):
def run(self):
print("Animal is running...")
class Dog(Animal):
def run(self):
print("Animal is running...")
class Cat(Animal):
def run(self):
print("Animal is running...")
- 若
子类
存在和父类
相同的方法
,此时,子类的方法
会覆盖
父类的方法
。
4. 获取对象信息
4.1 type()
- 判断基本类型都可以用
type()
- 判断一个变量是否指向
函数
或者类
>>> type(abs)
<class 'builtin_function_or_method'>
4.2 isinstance()
- 判断一个对象是否是
该类型本身
,或者位于该类型的父继承类链
上。 a = Animal()
isinstance(a, Animal)
->True
isinstance(123, int)
->True
- 总是优先使用
isinstance()
判断类型,因为它能将指定类型及其子类“一网打尽”。
4.3 dir()
- 如果要获得一个对象的所有属性和方法,可以使用
dir()
方法。
>>> dir("ABC")
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
- 由上面这个例子,可以说明
Python一切皆是对象
- 所以
len('ABC')
等 价 \color{blue}{等价} 等价'ABC'.__len__()
,都为3
,由此展开到4.4
讲一点其他东西。- 实际上,在调用
len()
函数时,它自动调用该对象的__len__()
方法。
- 实际上,在调用
4.4 其他说明
- 类似
__xxx__
的属性或者方法
在 Python 中都是有特殊用途的。 - 可以在类里面加(例子见下)。
class MyObject(Object):
def __init__(self):
self.x = 9
def __len__(self):
return 100
test = MyObject()
print(len(test)) # 100
4.5 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
5. 实例属性和类属性
5.1 实例属性
- 给实例绑定属性:通过实例变量,或者通过
self
变量。
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
5.2 类属性
- 给类本身绑定一个属性:可以直接在class中定义属性。
class Student(object):
name = 'Student'
- 例子:当我们定义了一个类属性后,这个属性虽然归类所有,但类的所有实例都可以访问到。
- 关于【类属性】
>>> 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
5.3 小测试
- 为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加。
class Student(object):
count = 0
def __init__(self, name):
self.name = name
Student.count += 1
# 测试:
if Student.count != 0:
print('测试失败!')
else:
bart = Student('Bart')
if Student.count != 1:
print('测试失败!')
else:
lisa = Student('Bart')
if Student.count != 2:
print('测试失败!')
else:
print('Students:', Student.count)
print('测试通过!')