# OOP 实战通过简单的case 更好的理解OOP思想, 如果使用代码,可以下载附件修改为.py即可
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 2017年3月24日
@author: fWX457893
'''
# 类的封装
class Student(object):
# __ 双下划线可使变量私有变成private,只有在函数每部可以访问,外部不能访问,
def __init__(self, name, score, **kw):
self.__name = name
self.__score = score
self.kw = kw
# 如果还想要让外部访问,可是添加方法 get_name, get_score, get_kw
def get_name(self):
return self.__name
def get_score(self):
return self.__score
# 又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:
def set_name(self, name):
self.__name = name
def set_score(self, score):
if 0 <= score <= 100:
self.__score = score
else :
raise ValueError('bad score')
def print_score(self):
print('%s: %s \t %s' % (self.__name, self.__score, self.kw))
def get_grade(self):
if self.__score >= 90:
return 'A'
elif self.__score >= 60:
return 'B'
else :
return"C"
bart = Student('fyh', 100, address='bj')
bart.print_score()
bart.set_score(10)
bart.print_score()
grade = bart.get_grade()
print grade
# 表面上看,外部代码“成功”地设置了__name变量,但实际上这个__name变量和class内部的__name变量不是一个变量!
# 内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量。不信试试:
bart.__name = 'new name'
print bart.__name
bart.print_score()
# -------------------------------------------------------------------------------
# OOP 的 继承和多态
class Animal(object):
def run(self):
print 'Animal is running...'
def eat(self):
print('Eating food...')
class Dog(Animal):
def run(self):
print('Dog is running...')
def eat(self):
print('Dog eating meat...')
class Cat(Animal):
def run(self):
print('Cat is running...')
def eat(self):
print('Cat eating fish...')
ani = Animal()
ani.run()
cat = Cat()
cat.run()
def run_eat(animal):
animal.run()
animal.eat()
run_eat(Animal())
run_eat(Dog())
run_eat(Cat())
'''
对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,
而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上,由运行时该对象的确切类型决定,
这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,
只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
对扩展开放:允许新增Animal子类;
对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。
'''
#
'''
静态语言 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“。
许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。
'''
class Husky(Dog):
def run(self):
print('Husky is running...')
def eat(self):
print('Husky eating meat...')
# 使用isinstance()
# 对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。
# object -> Animal -> Dog -> Husky
animal = Animal()
dog = Dog()
husky = Husky()
print isinstance(husky, Husky), isinstance(husky, Dog), isinstance(husky, Animal)
# True True True husky 是husky dog object 但是 dog 不是husky 是dog object
#定义一个父类一个子类
class Province(object):
def __init__(self,proname):
self.proname=proname
def ps(self):
print('I am in %s'%self.proname)
class City(Province):
def __init__(self,proname,cityname):
self.cityname=cityname
Province.__init__(self,proname)
def ps1(self):
print('I\'m in %s-%s' %(self.proname,self.cityname))
#定义一个独立的类
class Timer(object):
def ps(self):
print('我不属于Province类或其子类,但我有ps方法我同样可以被调用')
def ps1(self):
print('我不属于Province类或其子类,但我有ps1方法我同样可以被调用')
#定义一个函数
def func(x):
x.ps()
x.ps1()
#调用部分
func(City('北京','海淀'))
func(Timer())
# 部分参考廖神的python教程。
网友评论