python进阶-- 03 面向对象编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python进阶-- 03 面向对象编程相关的知识,希望对你有一定的参考价值。
1.定义
1.1类定义
在Python中,类通过 class 关键字定义。
按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。
class Person(object):
pass
1.2实例创建
创建实例使用 类名+(),类似函数调用的形式创建。
xiaoming = Person()
xiaohong = Person()
2属性
2.1添加实例属性
由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值,该属性不必在类中声明。
class Person(object):
pass
p1 = Person()
p1.name = ‘Bart‘
p2 = Person()
p2.name = ‘Adam‘
p3 = Person()
p3.name = ‘Lisa‘
2.2.初始化实例属性
虽然我们可以自由地给一个实例绑定各种属性,但是,现实世界中,一种类型的实例应该拥有相同名字的属性。
在定义 Person 类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用,我们就能在此为每个实例都加上统一属性。
举例
class Person(object):
def __init__(self, name, gender, birth):
self.name = name
self.gender = gender
self.birth = birth
2.3.内部属性(私有属性)实现
如果一个属性由双下划线开头(__),该属性就无法被外部访问。
但是,如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在Python的类中被称为特殊属性,有很多预定义的特殊属性可以使用,通常我们不要把普通属性用"__xxx__"定义。
以单下划线开头的属性"_xxx"也可以被外部访问。
重要:即使该私有属性与后来实例绑定的属性同名,并且后来实例的属性被改变,该私有属性也不会改变。
>>> class test_c(object):
def __init__(self):
self.__test=3
def get_test_a(self):
return self.__test
test_a=property(get_test_a)
@property
def test_b(self):
return "bbb"
>>> a=test_c()
>>> a.test_a
3
>>> a.__test=5
>>> a.test_a
3
2.4类属性
2.4.1概念
在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
2.4.2特点
由于Python是动态语言,类属性也是可以动态添加和修改的。
因为类属性只有一份,所以,当Person类的address改变时,所有实例访问到的类属性都改变了。
2.4.3定义
定义类属性可以直接在 class 中定义:
#给 Person 类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Person 的实例。
class Person(object):
count=0
def __init__(self,name):
Person.count+=1
self.name=name
2.4.4类属性与实例属性冲突问题
当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
使用实例来修改类属性是错误的,因为你的修改相当于给实例绑定了一个实例属性而已,并没有改变类属性的值。
class Person(object):
address = ‘Earth‘
def __init__(self, name):
self.name = name
p1 = Person(‘Bob‘)
p2 = Person(‘Alice‘)
print ‘Person.address = ‘ + Person.address
p1.address = ‘China‘
print ‘p1.address = ‘ + p1.address
print ‘Person.address = ‘ + Person.address
print ‘p2.address = ‘ + p2.address
2.4.5类属性的__xx
直接使用“类名.__类属性名”访问无法访问到
使用“类对象._类名__类属性名”可以访问到
3.方法
3.1实例方法
定义
实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的。
def 实例方法名(self,参数1,参数2,...):
方法块
调用
实例.实例方法名(参数1,参数2,...) #self不需要显式传入
3.2动态将方法添加到实例上
因为方法也是一个属性,所以,它也可以动态地添加到实例上(只是添加到了此实例上,一般不用)。
import types
def fn_get_grade(self):
if self.score >= 80:
return ‘A‘
if self.score >= 60:
return ‘B‘
return ‘C‘
class Person(object):
def __init__(self, name, score):
self.name = name
self.score = score
p1 = Person(‘Bob‘, 90)
p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
print p1.get_grade()
# => A
p2 = Person(‘Alice‘, 65)
print p2.get_grade()
# ERROR: AttributeError: ‘Person‘ object has no attribute ‘get_grade‘
# 因为p2实例并没有绑定get_grade
3.3类方法
3.3.1定义
通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例;
类方法的第一个参数将传入类本身,通常将参数名命名为 cls;
3.3.2特点
因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。类方法一般用来处理内部类变量。
3.3.3举例
下面的 cls.count 实际上相当于 Person.count。
class Person(object):
__count = 0
@classmethod
def how_many(cls):
return cls.__count
def __init__(self,name):
self.name=name
Person.__count +=1
print Person.how_many()
p1 = Person(‘Bob‘)
print Person.how_many()
4.继承
4.1定义
新类不用重头编写
新类从现有的类继承,就自动拥有了现有类的所有功能
新类只需编写现有类缺少的功能
父类/基类/超类---子类/派生类/继承类
4.2优点
复用已有代码
自动拥有现有类的所有功能
只需编写缺少的新功能
4.3特点
子类 is a 父类 (学生 is a 人)
Python的任何类必须继承于某个类
不要忘记调用super(subClass,self).__init__(*args) # args不能再写self
4.4举例
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
class Teacher(Person):
def __init__(self, name, gender, course):
super(Teacher,self).__init__(name,gender)
self.course=course
4.5isinstance()判断类型
可用来判断某个对象是否为某类型。
注:一个对象是某子类类型,一定也是该子类的父类对应的类型。
isinstance(object, class-or-type-or-tuple) -> bool
# 详见python基础-- 06 函数
4.6多重继承
多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用。
举个例子,Python的网络服务器有TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer,而服务器运行模式有 多进程ForkingMixin 和 多线程ThreadingMixin两种。
要创建多进程模式的 TCPServer:
class MyTCPServer(TCPServer, ForkingMixin)
pass
要创建多线程模式的 UDPServer:
class MyUDPServer(UDPServer, ThreadingMixin):
pass
如果没有多重继承,要实现上述所有可能的组合需要 4x2=8 个子类。
5.多态
5.1定义
1.一般地(如JAVA中),父类具有某方法,其子类通过不同实现,实现了该方法,是多态;
2.由于Python是动态语言,所以,传递给多态方法的参数 x 不一定是父类或基类类型。任何数据类型的实例都可以,只要它有一个与多态方法同样名字的方法即可。
5.2原理
1.一般地(如JAVA中),方法调用将作用在 x 的实际类型上。s 是Student类型,它实际上拥有自己的 whoAmI()方法以及从 Person继承的 whoAmI方法,但调用 s.whoAmI()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止;
2. 由于Python是动态语言,所以,传递给多态方法的参数 x 不一定是父类或基类类型。任何数据类型的实例都可以,只要它有一个与多态方法同样名字的方法即可。
5.3动态语言的多态
动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。
理解:
Python提供了open()函数来打开一个磁盘文件,并返回 File 对象。File对象有一个read()方法可以读取文件内容:
例如,从文件读取内容并解析为JSON结果:
import json
f = open(‘/path/to/file.json‘, ‘r‘)
print json.load(f)
由于Python的动态特性,json.load()并不一定要从一个File对象读取内容。任何对象,只要有read()方法,就称为File-like Object,都可以传给json.load()。
import json
class Students(object):
def __init__(self):
pass
def read(self):
return r‘["Tim", "Bob", "Alice"]‘
s = Students()
print json.load(s)
# result: [u‘Tim‘, u‘Bob‘, u‘Alice‘]
6.类中常用函数
6.1setattr()
setattr(object, name, value)
用来设置对象的属性,详细使用help(setattr)查看
以上是关于python进阶-- 03 面向对象编程的主要内容,如果未能解决你的问题,请参考以下文章