Python 面向对象
- 面向过程:根据业务逻辑从上到下写垒代码
- 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
- 面向对象:对函数进行分类和封装,让开发“更快更好更强...”
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
创建类
使用 class 语句来创建一个新类,class 之后为类的名称并以冒号结尾:
面向对象方式格式:
定义:
class 类名: - 定义了一个类
def 函数名(self): - 在类中编写了一个"方法"
pass
调用:
x1 = 类名() - 创建了一个对象/实例化一个对象
x1.函数名() - 通过对象调用其中一个方法.
4. 示例: class Account: def login(self): user = input('请输入用户名:') pwd = input('请输入密码:') if user == 'alex' and pwd == 'sb': print('登录成功') else: print('登录失败') obj = Account() obj.login()
实例
以下是一个简单的 Python 类的例子:
#!/usr/bin/python # -*- coding: UTF-8 -*- class Employee: '所有员工的基类' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary
-
empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。
-
第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
-
self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()
以上实例执行结果为:
<__main__.Test instance at 0x10d066878> __main__.Test
从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。
self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的.
class LaoGou: def __init__(self,name,age,gender): # 特殊的方法,如果 类名() ,则该方法会被自动执行 (构造方法) self.n1 = name self.n2 = age self.n3 = gender def kc(self): data = "%s,性别%s,今年%s岁,喜欢上山砍柴" %(self.n1,self.n3,self.n2) print(data) def db(self): data = "%s,性别%s,今年%s岁,喜欢开车去东北" %(self.n1,self.n3,self.n2) print(data) def bj(self): data = "%s,性别%s,今年%s岁,喜欢大宝剑" %(self.n1,self.n3,self.n2) print(data) obj = LaoGou('老狗',20,'男') obj.kc() obj.db() obj.bj()
总结:
1. 构造方法
示例一:
class Foo:
def __init__(self,name): 构造方法,目的进行数据初始化.
self.name = name
self.age = 18
obj = Foo('侯明魏')
通过构造方法,可以将数据进行打包,以后使用时,去其中获取即可.
示例二:
class Bar:
pass
obj = Bar()
2. 应用
a. 将数据封装到对象中,以供自己在方法中调用
class FileHandler: def __init__(self,file_path): self.file_path = file_path self.f = open(self.file_path, 'rb') def read_first(self): # self.f.read() # ... pass def read_last(self): # self.f.read() # ... pass def read_second(self): # self.f... # ... pass obj = FileHandler('C:/xx/xx.log') obj.read_first() obj.read_last() obj.read_second() obj.f.close()
b. 将数据封装到对象中,以供其他函数调用
def new_func(arg): arg.k1 arg.k2 arg.k6 class Foo: def __init__(self,k1,k2,k6): self.k1 = k1 self.k2 = k2 self.k6 = k6 obj = Foo(111,22,333) new_func(obj)
练习: 信息管理系统
1. 用户登录
2. 显示当前用户信息
3. 查看当前用户所有的账单
4. 购买姑娘形状的抱枕
示例: class UserInfo: def __init__(self): self.name = None def info(self): print('当前用户名称:%s' %(self.name,)) def account(self): print('当前用户%s的账单是:....' %(self.name,)) def shopping(self): print('%s购买了一个人形抱枕' %(self.name,)) def login(self): user = input('请输入用户名:') pwd = input('请输入密码:') if pwd == 'sb': self.name = user while True: print(""" 1. 查看用户信息 2. 查看用户账单 3. 购买抱枕 """) num = int(input('请输入选择的序号:')) if num == 1: self.info() elif num ==2: self.account() elif num == 3: self.shopping() else: print('序号不存在,请重新输入') else: print('登录失败') obj = UserInfo() obj.login()
总结:
class Foo: def func2(self): print('func2') def func1(self): self.fun2() print('func1') obj = Foo() obj.func1()
2. 面向对象代码如何编写
a. 规则
class Foo: def __init__(self,name): self.name = name def detail(self,msg): print(self.name,msg) obj = Foo() obj.detail()
b. 什么时候写?如何写?
方式一:归类+提取公共值
归类:
class File: def file_read(self,file_path): pass def file_update(self,file_path): pass def file_delete(self,file_path): pass def file_add(self,file_path): pass class Excel: def excel_read(self,file_path): pass def excel_update(self,file_path): pass def excel_delete(self,file_path): pass def excel_add(self,file_path): pass 提取公共值: class File: def __init__(self,file_path): self.file_path = file_path def file_read(self): pass def file_update(self): pass def file_delete(self): pass def file_add(self): pass class Excel: def __init__(self,file_path): self.file_path = file_path def excel_read(self): pass def excel_update(self): pass def excel_delete(self): pass def excel_add(self): pass
方式二:在指定类中编写和当前类相关的所有代码 + 提取公共值
class Message: def email(self): pass class Person: def __init__(self,na, gen, age, fig) self.name = na self.gender = gen self.age = age self.fight =fig def grassland(self): self.fight = self.fight - 10 def practice(self): self.fight = self.fight + 90 def incest(self): self.fight = self.fight - 666 cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色 dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色 bo = Person('波多多', '女', 19, 2500) # 创建波多多角色 dong.grassland()
3. 面向对象的三大特性:封装/继承/多态
封装:
将相关功能封装到一个类中:
class Message: def email(self):pass def msg(self):pass def wechat(self):pass
将数据封装到一个对象中:
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender obj = Person('孙福来',18,'女')
继承:
class SuperBase: def f3(self): print('f3') class Base(SuperBase): # 父类,基类 def f2(self): print('f2') class Foo(Base): # 子类,派生类 def f1(self): print('f1') obj = Foo() obj.f1() obj.f2() obj.f3() # 原则:现在自己类中找,么有就去父类
总结:
1. 继承编写
class Foo(父类):
pass
2. 支持多继承(先找左/再找右)
3. 为什么要有多继承? 提供代码重用性
练习: 找self到底是谁的对象?从谁开始找.
多态:
多种形态或多种状态
鸭子模型,只要可以嘎嘎叫就是鸭子.
Python # 由于python原生支持多态,所以没有特殊性. """ class Foo1: def f1(self): pass class Foo2: def f1(self): pass class Foo3: def f1(self): pass def func(arg): arg.f1() obj = Foo1() # obj= Foo2() obj = Foo3() func(obj) """
创建实例对象
实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式。
以下使用类的名称 Employee 来实例化,并通过 __init__ 方法接收参数。
"创建 Employee 类的第一个对象" emp1 = Employee("Zara", 2000) "创建 Employee 类的第二个对象" emp2 = Employee("Manni", 5000)
访问属性
可以使用点号 . 来访问对象的属性。使用如下类的名称访问类变量:
emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
完整实例:
#!/usr/bin/python # -*- coding: UTF-8 -*- class Employee: '所有员工的基类' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary "创建 Employee 类的第一个对象" emp1 = Employee("Zara", 2000) "创建 Employee 类的第二个对象" emp2 = Employee("Manni", 5000) emp1.displayEmployee() emp2.displayEmployee() print "Total Employee %d" % Employee.empCount
执行以上代码输出结果如下:
Name : Zara ,Salary: 2000 Name : Manni ,Salary: 5000 Total Employee 2
你可以添加,删除,修改类的属性,如下所示:
emp1.age = 7 # 添加一个 'age' 属性 emp1.age = 8 # 修改 'age' 属性 del emp1.age # 删除 'age' 属性
你也可以使用以下函数的方式来访问属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
- delattr(obj, name) : 删除属性。
-
hasattr(emp1, 'age') # 如果存在 'age' 属性返回 True。 getattr(emp1, 'age') # 返回 'age' 属性的值 setattr(emp1, 'age', 8) # 添加属性 'age' 值为 8 delattr(emp1, 'age') # 删除属性 'age'
Python内置类属性
一:我们定义的类的属性到底存到哪里了?有两种方式查看 dir(类名):查出的是一个名字列表 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 二:特殊的类属性 类名.__name__# 类的名字(字符串) 类名.__doc__# 类的文档字符串 类名.__base__# 类的第一个父类(在讲继承时会讲) 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 类名.__dict__# 类的字典属性 类名.__module__# 类定义所在的模块 类名.__class__# 实例对应的类(仅新式类中)
Python内置类属性调用实例如下:
class Employee: '所有员工的基类' empCount = 0 def __init__(self, name, salary): self.name = name self.salary = salary Employee.empCount += 1 def displayCount(self): print "Total Employee %d" % Employee.empCount def displayEmployee(self): print "Name : ", self.name, ", Salary: ", self.salary print "Employee.__doc__:", Employee.__doc__ print "Employee.__name__:", Employee.__name__ print "Employee.__module__:", Employee.__module__ print "Employee.__bases__:", Employee.__bases__ print "Employee.__dict__:", Employee.__dict__
执行以上代码输出结果如下:
Employee.__doc__: 所有员工的基类 Employee.__name__: Employee Employee.__module__: __main__ Employee.__bases__: () Employee.__dict__: {'__module__': '__main__', 'displayCount': <function displayCount at 0x10a939c80>, 'empCount': 0, 'displayEmployee': <function displayEmployee at 0x10a93caa0>, '__doc__': 'xe6x89x80xe6x9cx89xe5x91x98xe5xb7xa5xe7x9ax84xe5x9fxbaxe7xb1xbb', '__init__': <function __init__ at 0x10a939578>}
类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
继承语法
class 派生类名(基类名) ...
在python中继承中的一些特点:
- 1、如果在子类中需要父类的构造方法就需要显示的调用父类的构造方法,或者不重写父类的构造方法。详细说明可查看:python 子类继承父类构造函数说明。
- 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
- 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
class SubClassName (ParentClass1[, ParentClass2, ...]): ...
实例 #!/usr/bin/python # -*- coding: UTF-8 -*- class Parent: # 定义父类 parentAttr = 100 def __init__(self): print "调用父类构造函数" def parentMethod(self): print '调用父类方法' def setAttr(self, attr): Parent.parentAttr = attr def getAttr(self): print "父类属性 :", Parent.parentAttr class Child(Parent): # 定义子类 def __init__(self): print "调用子类构造方法" def childMethod(self): print '调用子类方法' c = Child() # 实例化子类 c.childMethod() # 调用子类的方法 c.parentMethod() # 调用父类方法 c.setAttr(200) # 再次调用父类的方法 - 设置属性值 c.getAttr() # 再次调用父类的方法 - 获取属性值
以上代码执行结果如下:
调用子类构造方法
调用子类方法
调用父类方法
父类属性 : 200
你可以继承多个类
class A: # 定义类 A ..... class B: # 定义类 B ..... class C(A, B): # 继承类 A 和 B .....
你可以使用issubclass()或者isinstance()方法来检测。
- issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
- isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true。