python之类与面向对象
文章最后更新时间为:2018年08月14日 10:16:15
1、面向对象的概念
段子手觉得面向对象对程序员来说真是个扯淡的东西,没有对象怎么面向对象编程?
但是没有对象我们也可以创造对象!
面向对象是一种程序设计方法,和面向过程相比,面向对象的核心在于对象,一切皆为对象,一个对象就是一个封装体,具有状态和操作。定义好一个对象并给它赋予属性和方法之后,我们便可以在任何地方调用这个对象。
看以下实例
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class obb: # obb 是一个对象
def mult(x,y): # obb对象有mult方法
print( x * y )
obb.mult(2,4) # 调用obb对象的mult方法
obb.mult(3,7)
上述例子中我们首先定义了obb对象,给一个对象添加属性和方法之后,在程序里我们可以随时调用这个对象,实现不同的需求。
2、python中类和对象的概念
面向对象最重要的概念就是类(Class)和实例(Instance),类是抽象的模板,比如学生、老师、人类等都可以是一个类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
举个例子,学生是一个类,我们把张三李四都看作一个学生,这就是对于学生这个类的两个不同的实例,每个实例都有自己的数据,在这个例子中就是选课、成绩、学号等等。
以下是一个简单的 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 (self.empCount)
def displayEmployee(self):
print ( self.name, self.salary)
t=Employee('xiaoming',1000)
t.displayCount()
t.displayEmployee()
# 运行结果
1
xiaoming 1000
- empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用 Employee.empCount 访问。为什么要创建这个类变量而不在方法中创造,其实是变量作用域的原因,类变量可以被类中的所有方法访问。
- self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。需要注意的是self代表类的实例,而非类。
- t是一个实例,我们可以给其赋予name、salary等属性,也可以调用存在的方法。
3、python类的说明
(1)、关于_ init _
init _ _是一个特殊的方法,在创建实例的时候,这个方法就会被调用,一般用于传递参数。
注意到_ init _ 方法的第一个参数永远是self,表示创建的实例本身,因此,在 _init __方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了_ init _ 方法,在创建实例的时候,就不能传入空的参数了,必须传入与_ init _ 方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
>>> t=Employee('xiaoming',1000)
>>> t.name
'gengyanqing'
>>> t.salary
1000
需要注意的是,在类的方法中,第一个参数永远是self,调用时不用传递这个参数。除此之外类的方法和普通的函数没有太大的区别。
(2)、访问类的属性以及其内置属性
除了使用 t.name , 我们还可以通过以下函数来访问类的属性:
- getattr(obj, name[, default]) : 访问对象的属性。
- hasattr(obj,name) : 检查是否存在一个属性。
- setattr(obj,name,value) : 设置一个属性。如果属性不存在,会创建一个新属性。
- delattr(obj, name) : 删除属性。
举例:
>>> t.name # t的name属性
'gengyanqing'
>>> t.salary # t的salary属性
1000
>>> getattr(t,'name') # 获取t.name
'gengyanqing'
>>> hasattr(t,'name') # 判断是否存在t.name
True
>>> setattr(t,'name','xiaoming2') # t.name改为xiaoming2
>>> getattr(t,'name')
'xiaoming2'
>>> delattr(t,'name') # 删除t的name属性
>>> hasattr(t,'name')
False
上述属性都是我们在定义类的时候赋予的,实际上python类含有很多内置属性,即只要你新建了类,系统就会自动创建这些属性。
1、 dict : 类的属性(包含一个字典,由类的数据属性组成)
2、_ doc _ :类的文档字符串
3、_ module _ : 类定义所在的模块(类的全名是' main_ .className',如果类 位于 一个导入模块mymod中,那么className. _ module 等于 mymod)
>>> t.__dict__
{'name': 'gengyanqing', 'salary': 1000}
>>> t.__doc__
'所有员工的基类'
>>> t.__module__
'__main__'
还有很多其他的内置属性,这里只列举了常见的。
怎么查看类的所有属性和方法,我们可以使用dir()函数:
>>> dir('t')
['__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', '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']
(3)、类的私有属性和私有方法
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线_ ,在Python中,实例的变量名如果以 _开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Employee类改一改:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
def __init__(self, name, salary):
self.name = name
self.__salary = salary
# 调用结果
>>> t=Employee('xiaoming',10000)
>>> t.salary
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module>
t.salary
AttributeError: 'Employee' object has no attribute 'salary'
>>> t.__salary
Traceback (most recent call last):
File "<pyshell#22>", line 1, in <module>
t.__salary
AttributeError: 'Employee' object has no attribute '__salary'
可以看出我们无法通过t来访问_ _ salary属性,也无法修改这个属性。我们可以在类中写一个方法返回这个属性,然后在外部调用即可访问。
不仅是属性,我们也可以定义私有方法。两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print self.__secretCount
counter = JustCounter()
counter.count()
counter.count()
print counter.publicCount
print counter.__secretCount # 报错,实例不能访问私有变量
Python不允许实例化的类访问私有数据,但我们可以使用 object. className _ attrName 访问属性。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Employee:
def __init__(self, name, salary):
self.name = name
self.__salary = salary
# 调用结果
>>> t=Employee('xiaoming',10000)
>>> t._Employee__salary
10000
那么定义私有属性的目的何在:原因是我们可以在内部对其修改做一定的限制。这个机制其实没啥卵用,我们还可以通过其他方式在外部访问这个属性,主要是要警告我们要自觉,不要干坏事。
(4)、类的继承和重写
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。继承完全可以理解成类之间的类型和子类型关系。
举例:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
def __init__(self):
print ("调用父类构造函数")
def parentMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def __init__(self):
print ("调用子类构造方法")
def childMethod(self):
print( '调用子类方法')
t=Child()
t.childMethod()
t.parentMethod()
执行结果:
调用子类构造方法
调用子类方法
调用父类方法
上述例子中可以看出。Child类继承了Parent类,也就具有了父类的方法。啥事也没干,就获得了parentMethod方法。
需要注意的是:在继承中基类的构造( init ()方法)不会被自动调用
当然,我们也可以继承多个父类:
class A: # 定义类 A
.....
class B: # 定义类 B
.....
class C(A, B): # 继承类 A 和 B
.....
同样如果我们不喜欢父类的方法,我们也可以在子类中进行重写:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
def __init__(self):
print ("调用父类构造函数")
def parentMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def __init__(self):
print ("调用子类构造方法")
def childMethod(self):
print( '调用子类方法')
def parentMethod(self):
print ('这个还是子类方法')
t=Child()
t.childMethod()
t.parentMethod()
结果:
调用子类构造方法
调用子类方法
这个还是子类方法
重写的原因在于:
Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
(5)、关于下划线说明
1、单下划线、双下划线、头尾双下划线说明:
foo _: 定义的是特殊方法,一般是系统定义名字 ,类似 _ init () 之类的。
2、_ foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
3、_ _ foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
3、总结
python面向对象可以说是python高级编程的基础了,不断的编程实践才能出真知。
关于多态,python类的构造析构,对象的深入理解等还有很多知识需要理解。本文如有错误,欢迎指正。
参考:
廖雪峰官方网站:https://www.liaoxuefeng.com
菜鸟教程:http://www.runoob.com
python核心编程第二版