类
下面代码包含,初始化构造函数、类变量、类方法、生成实例、多态性、封装
#!/usr/bin/env python class Dog(object): age = 22 # 类变量, 存在类的内存地址里, 可以被所有实例共享应用 def __init__(self, name, dog_type, sex): # self是当前的实例化对象 self.name = name self.dog_type = dog_type self.__sex = sex def sex(self): print('%s sex %s' % (self.name, self.__sex)) def balk(self): print('%s wang.. wang.. wang..' % self.name) def eat(self, food): print('%s eating %s' % (self.name, food)) d = Dog('dog1', 'yesheng', '公') c = Dog('dog2', 'yesheng', '母') print(d.__sex) # __对外是访问不到的 d.sex() # 类中写一个方法可以访问到__sex , 这就是封装 d.balk() d.eat('sandwish') d.age = 23 # 修改公共属性,只修改当前实例的 print(d.age) print(c.age) def func(obj): # 一个接口,多种形态 ,obj就是多态性 obj.balk() func(d) func(c)
继承
class Course(object): course_name = "Python 自动化" period = "7m" outline = "sdfsfsdfsfsdf" test = 321 print("in course") class SchoolMember(object): members = 0 test = 123 print("in Schoolmember") def __init__(self, name,age,sex): self.name = name self.age = age self.sex = sex SchoolMember.members +=1 # 每次子类实例化时,执行构造函数里的SchoolMember.members +=1 将members存到类变量里 # self.members 是 子类实例化调用members后存在新的变量 print("初始化了一个新学校成员",self.name) def tell(self): info = ''' -----info of %s ------- name: %s age : %s sex : %s '''%(self.name,self.name,self.age,self.sex) print(info) def __del__(self):#析构方法 print("%s 被开除了"% self.name) SchoolMember.members -=1 class Teacher(SchoolMember): def __init__(self,name,age,sex,salary): SchoolMember.__init__(self,name,age,sex ) # super(Teacher,self).__init__(name,age,sex) #自己找到自己父类
#super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
#self.name = name #t.name =name self.salary = salary def teaching(self,course): print("%s is teaching %s"%(self.name,course)) class Student(SchoolMember,Course): def __init__(self,name,age,sex,grade,teacher ): SchoolMember.__init__(self,name,age,sex ) #self.name = name #t.name =name self.grade = grade self.my_teacher = teacher def pay_tuition(self,amount): self.paid_tuition = amount print("stduent %s has paid tution amount %s" %(self.name,amount)) t = Teacher("Alex",22,"F",3000) s = Student("Liuhao",24,"M","pys16", t) # s2 = Student("YanShuai",46,"F","pys26") # s4 = Student("NiNing",32,"F","pys26") print("my teacher",s.my_teacher.name) s.my_new_teacher = t print(SchoolMember.members) print(t.members) print(SchoolMember.members) print(s.members) #del s4 # t.tell() # s.tell() # s2.tell() # t.teaching("python") # s.pay_tuition(11000) # print(SchoolMember.members) # print(s.course_name,s.outline) # print("test:",s.test)
抽象类
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
import abc class AllFile(metaclass=abc.ABCMeta): #抽象类 def test(self): print('testing') @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Text(AllFile): #Text继承了AllFile,下面的类方法必须写read、write,如果不写或写错会出现类型错误的异常 def read(self): print('text read') def write(self): pass t=Text() t.test() # a=AllFile() # a.test()
类方法
如果我们想通过类来调用方法,而不是通过实例,那应该怎么办呢?
Python 提供了 classmethod
装饰器让我们实现上述功能,看下面的例子:
class A(object):
bar = 1
@classmethod
def class_foo(cls):
print 'Hello, ', cls
print cls.bar
>>> A.class_foo() # 直接通过类来调用方法
Hello, <class '__main__.A'>
1
在上面,我们使用了 classmethod
装饰方法 class_foo
,它就变成了一个类方法,class_foo
的参数是 cls,代表类本身,当我们使用 A.class_foo()
时,cls 就会接收 A 作为参数。另外,被 classmethod
装饰的方法由于持有 cls 参数,因此我们可以在方法里面调用类的属性、方法,比如 cls.bar
。
静态方法
在类中往往有一些方法跟类有关系,但是又不会改变类和实例状态的方法,这种方法是静态方法,我们使用staticmethod
来装饰,比如下面的例子:
class A(object):
bar = 1
@staticmethod
def static_foo():
print 'Hello, ', A.bar
>>> a = A()
>>> a.static_foo()
Hello, 1
>>> A.static_foo()
Hello, 1
可以看到,静态方法没有 self 和 cls 参数,可以把它看成是一个普通的函数,我们当然可以把它写到类外面,但这是不推荐的,因为这不利于代码的组织和命名空间的整洁。
强调,注意注意注意:静态方法和类方法虽然是给类准备的,但是如果实例去用,也是可以用的,只不过实例去调用的时候容易让人混淆,不知道你要干啥
特性
1 什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
import math class Circle: def __init__(self,radius): #圆的半径radius self.radius=radius @property def area(self): return math.pi * self.radius**2 #计算面积 @property def perimeter(self): return 2*math.pi*self.radius #计算周长 c=Circle(10) print(c.radius) print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c.perimeter) #同上 ''' 输出结果: 10 314.1592653589793 62.83185307179586 '''
注意:此时的特性arear和perimeter不能被赋值
c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''
2 为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
常用的类特殊成员方法
__init__ 构造方法,通过类创建对象时,自动触发执行
__del__ 析构方法,当对象在内存中被释放时,自动触发执行
__call__ 对象后面加括号,触发执行
__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
#!/usr/bin/env python class MyType(type): def __init__(self, *args, **kwargs): # 第三步 print("Mytype __init__", *args, **kwargs) def __call__(self, *args, **kwargs): print("Mytype __call__", *args, **kwargs) obj = self.__new__(self) # 创建实例的内存地址 print("obj ", obj, *args, **kwargs) print(self) self.__init__(obj, *args, **kwargs) # 实例赋值 return obj # 把对象返回给实例 def __new__(cls, *args, **kwargs): # 第二步 print("Mytype __new__", *args, **kwargs) return type.__new__(cls, *args, **kwargs) # 调__new__,执行__init__, print('here...') class Foo(object, metaclass=MyType): # 第一步MyType def __init__(self, name): self.name = name print("Foo __init__") def __new__(cls, *args, **kwargs): print("Foo __new__", cls, *args, **kwargs) return object.__new__(cls) f = Foo("Alex") # 第四步 ,MyType的__call__方法 print("f", f) print("fname", f.name)
反射
1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
while True: choice = input('[%s]:' % self.username).strip() if len(choice) == 0: continue if choice == 'exit': break cmd_list = choice.split() if hasattr(self, '_%s' % cmd_list[0]): # 判断输入的命令在类中的方法是否存在 func = getattr(self, '_%s' % cmd_list[0]) #调用该方法 func(cmd_list) else: print('Invalid cmd.')
领域模型
好了,你现在会了面向对象的各种语法了, 那请看下本章最后的作业需求,我相信你可能是蒙蔽的, 很多同学都是学会了面向对象的语法,却依然写不出面向对象的程序,原因是什么呢?原因就是因为你还没掌握一门面向对象设计利器, 你说我读书少别骗我, 什么利器?
答案就是:领域建模。 从领域模型开始,我们就开始了面向对象的分析和设计过程,可以说,领域模型是完成从需求分析到面向 对象设计的一座桥梁。
领域模型,顾名思义,就是需求所涉及的领域的一个建模,更通俗的讲法是业务模型。 参考百度百科(http://baike.baidu.cn/view/757895.htm ),领域模型定义如下:
从这个定义我们可以看出,领域模型有两个主要的作用:
发掘重要的业务领域概念
建立业务领域概念之间的关系
领域建模三字经
领域模型如此重要,很多同学可能会认为领域建模很复杂,需要很高的技巧。然而事实上领域建模非常简 单,简单得有点难以让人相信,领域建模的方法概括一下就是“找名词”! 许多同学看到这个方法后估计都会笑出来:太假了吧,这么简单,找个初中生都会啊,那我们公司那些分 析师和设计师还有什么用哦?
分析师和设计师当然有用,后面我们会看到,即使是简单的找名词这样的操作,也涉及到分析和提炼,而 不是简单的摘取出来就可,这种情况下分析师和设计师的经验和技能就能够派上用场了。但领域模型分析 也确实相对简单,即使没有丰富的经验和高超的技巧,至少也能完成一个能用的领域模型。
虽然我们说“找名词”很简单,但一个关键的问题还没有说明:从哪里找? 如果你还记得领域模型是“需求到面向对象的桥梁”,那么你肯定一下子就能想到:从需求模型中找,具 体来说就是从用例中找。
归纳一下域建模的方法就是“从用例中找名词”。 当然,找到名词后,为了能够更加符合面向对象的要求和特点,我们还需要对这些名词进一步完善,这就 是接下来的步骤:加属性,连关系!
最后我们总结出领域建模的三字经方法:找名词、加属性、连关系。
练习项目:
0:初始化
创建admin用户、密码
1:管理员
选项 查看管理员选项
创建学校 输入学校名、学校地址,创建成功
查看学校 查看所有学校的名称、地址、创建成功
创建课程 选择学校,输入程名、课程价格、课程周期,创建成功
查看课程 查看课程名、价格、周期、校区
创建班级 选择课程,输入班级名,创建成功
查看班级 查看班级、课程、校区
创建老师 选择学校,选择班级,输入老师信息,创建成功
查看老师 查看老师、班级、校区
创建学生 选择学校,选择班级,输入学生信息,创建成功
查看学生 查看学生、班级、校区
退出 exit
2:老师(未实现)
选项 查看老师选项
3:学生
选项 查看学生选项
注册 选择学校,选择班级,输入学生,创建成功
登录 登录学生用户名密码
登录成功
交学费,已交过会提示,没交过进入交款功能
退出 exit