面向对象的基本概念
类和实例
- 定义类以及类的属性
- 创建实例
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))
zhang = Student('zhangweilin',100)
zhang.print_score()
- 访问限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以两个下划线开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def get_name(self):
return self.__name
def get_score(self):
return self.__score
def set_score(self, score):
self.__score = score
采用get_name(),get_score() 这种方法就可以对__开头的变量进行外部访问了。
这样的好处是当你尝试修改私有变量时可以在程序中检查参数有效性
继承和多态
# 实现继承 以及方法重写
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
def run(self):
print('Dog is running...')
class Cat(Animal):
def run(self):
print('Cat is running...')
a = Animal()
b = Dog()
print(isinstance(b,Animal)) # True
print(isinstance(a,Dog)) # False 继承只能向上兼容
# 实现多态,即把父类作为传入参数,这样面对不同对象时,传入不同子类就行了,因为各个子类属于父类这种类型
def run_twice(animal):
animal.run()
run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
-----------------------
True
False
Animal is running...
Dog is running...
Cat is running...
实例属性和类属性
class Student(object):
def __init__(self, name):
self.name = name
# 给实例绑定对象
s = Student('Bob')
s.score = 90
#或者绑定一个方法
def set_age(self, age): # 定义一个函数作为实例方法
self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s)
s.set_age(25)
print(s.age) #25
# 为类添加属性
class Student(object):
name = 'Mike'
s = Student()
print(s.name) # Mike
若想为类添加一个属性,直接在class中定义,这个属性虽然归类所有,但类的所有实例都可以访问到
创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性
给class 绑定方法
def set_score(self, score):
self.score = score
Student.set_score = set_score
使用slots
如果想对实例的属性做限制,即不能任由实例一直添加属性,则可以在类中使用slots 做限制
class Student(object):
__slots__ = ('name', 'age') #只允许对Student实例添加name和age属性
s = Student() # 创建新的实例
s.name = 'Michael' # 绑定属性'name'
s.age = 25 # 绑定属性'age'
s.score = 99 #报错!
------
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
使用 @property
在绑定属性时,如果我们直接把属性暴露出去,没办法检查参数,导致可以把成绩随便改,
所以最好这样写:
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!') # 抛出异常
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
这样可以在set_score()里面检查参数,但是这样貌似又略显复杂,那么这时候就要用到@property 内置的装饰器(个人理解是加了这一句 表示默认给方法提供了getter() 和setter()方法)
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
@property 广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性
类的多重继承
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn
class Dog(Animal, RunnableMixIn, CarnivorousMixIn):
pass
面向对象中的关键字
nonlocal关键字
python 中只有两种作用域:全局作用域和局部作用域。全局作用域是指当前代码所在模块的作用域,局部作用域是指当前函数或方法所在的作用域。
Python 3.x引入了 nonlocal 关键字,可以用于标识外部作用域的变量。
局部作用域里的代码可以读外部作用域(包括全局作用域)里的变量,但不能更改它。一旦进行更改,就会将其当成是局部变量。而如果在更改前又进行了读取操作,则会抛出异常
def outer():
num =10
def inner():
nonlocal num # nonlocal关键字声明
print('inner-nonlocal-num',num)
num = 100
print('inner-local-num',num)
print('outer-local-num',num)
inner()
print('outer-inner-local-num',num)
outer()
#---------------
outer-local-num 10
inner-nonlocal-num 10
inner-local-num 100
outer-inner-local-num 100
global关键字
global适用于函数内部修改全局变量的值
@staticmethod()
类中的变量(方法)分类两种:静态变量(方法)和实例变量(方法)
静态方法 f,类可以不用实例化就可以调用该方法 C.f(),当然也可以实例化后调用 C().f()
static 的好处就是当加载类时,就执行了静态代码块,在内存中只有一个拷贝(节省内存)
使用场景:1. 当需要在各个对象(实例)之间共享值时;2.方便访问变量时
class C(object):
@staticmethod
def f():
print('runoob');
C.f(); # 静态方法无需实例化
cobj = C()
cobj.f() # 也可以实例化后调用
java 中的 this,super,final 等关键字
this,super,final 在Java中放在变量或方法前
this:当前类的变量或方法
super: 父类的变量或方法
final: 在类前表示不能在被继承,其他表示该变量或方法不能被更改
# 方法1:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
FooParent.bar(self, message)
>>> FooChild().bar("Hello, Python.")
Hello, Python
#---------
# 方法2:
class FooParent:
def bar(self, message):
print(message)
class FooChild(FooParent):
def bar(self, message):
super(FooChild, self).bar(message) #或者简写 super().bar(message)
>>> FooChild().bar("Hello, Python.")
Hello, Python
当父类修改了方法名称,则要对子类引用都修改,麻烦!
第二种方法就显得轻松得多