面向对象编程


简称OOP,是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。数据封装、继承和多态是面向对象的三大特点。

在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是

面向对象中的类(Class)的概念。

给对象发消息实际上就是调用对象对应的关联函数,称之为对象的方法(Method)


OOP最重要的概念就是(Class)和实例(Instance),牢记类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。(艾维铝酉和cjk区别——#)

定义类通过class关键字

 class Student(object):
pass #object表示该类是从哪个类继承下来的,如果没有合适的继承类就使用object类,这是所有类最终都会继承的类。

创建实例通过类名+()

 bart = Student()                        

可以给实例的变量绑定属性

 bart.name = 'Bart Simpson'

由于类可以起到模板的作用,在创建实例的时候可以通过定义__init__方法把认为必要的属性强制填写进去绑定

 class Student(object):

      def __init__(self, name, score):   #将name和score属性绑定
self.name = name
self.score = score #__init__方法的第一个参数永远是self,表示创建的实例本身,因此可以把各种属性绑定到self,因为self就指向创建的实例本身。

有了__init__方法,在创建实例的时候,就不能传入空的参数了而必须传入与__init__方法匹配的参数,self不需要传

 >>> bart = Student('Bart Simpson', 59)
>>> bart.name
'Bart Simpson'
>>> bart.score
59

在类中定义的函数和普通函数相比只有一点不同,就是第一个参数永远是实例变量self,并且调用时不用传递该参数。

访问实例的数据,没必要用外面的函数去访问,可以直接在类的内部定义访问数据的函数,这样,就把“数据”给封装起来了,称为数据封装。这些封装数据的函数是和类本身是关联起来的,称为类的方法

 class Student(object):

     def __init__(self, name, score):
self.name = name
self.score = score def print_score(self):
print('%s: %s' % (self.name, self.score)) #调用方法>>>bart.print_score()

封装的一个好处是不用知道内部实现的细节容易调用,另一个是好处是可以给类增加新的方法

 class Student(object):
... def get_grade(self): #给该类增加一个get_grade方法
if self.score >= 90:
return 'A'
elif self.score >= 60:
return 'B'
else:
return 'C'

类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;

方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据(普通函数需要访问类);


使用上述方法可以隐藏内部复杂逻辑,而在属性名称前加上两个下划线__可以访问限制,使得外部代码不能自由修改实例的属性

 class Student(object):

     def __init__(self, name, score):         #之前>>> bart.score  98
# >>> bart.score = 59
5 # >>> bart.score 59
self.__name = name
self.__score = score #之后>>> bart.__name Error def print_score(self):
print('%s: %s' % (self.__name, self.__score))

如果外部代码要获取属性,可以给类增加get_nameget_score这样的方法

 class Student(object):
... def get_name(self):
return self.__name def get_score(self):
return self.__score

如果又要允许外部代码修改属性,可以再给类增加set_score方法

 class Student(object):
... def set_score(self, score):
self.__score = score

类似__xxx__是特殊变量,可以直接访问,但是不要定义这样的变量名

一个下划线开头的变量,可以被外部访问,但是约定俗成视为私有变量,不要随意访问

两个下划线开头的变量,可以通过   实例名._类名__变量名   来访问(不同版本.后的可能不同)

总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。


OOP程序设计中定义一个class的时候,可以从某个现有的class继承,子类将获得了父类的全部功能(方法),也可以对子类增加方法。如果一个变量是子类的数据类型,那么它同时也是父类、爷类...类型,这就是多态

 class Animal(object):                    #编写一个名为Animal的class
def run(self):
print('Animal is running...') class Dog(Animal): #直接从Animal类继承
pass 运行
dog = Dog()
dog.run()
Animal is running... class Dog(Animal): #对子类增加方法 def run(self):
print('Dog is running...')
18
19 运行
20 Dog is running... #调用时子类会覆盖与父类定义同名的方法

多态的好处

def run_twice(animal):    #定义一个接收Animal类型的函数
animal.run() #调用函数时不管参数是父类Animal()其子类比如Dog(),实际调用的都是类中各自定义的叫 run 的方法,只要 实参是形参的子类,无需修改函数

注:

如果需要传入Animal类型,对于静态语言(如JAVA)传入的对象必须是Animal类型或其子类,否则无法调用run方法。对于动态语言(如Python),则不一定需要传入Animal类型,只需要保证传入的对象有一个run()方法就可以了。


获取对象信息

判断对象类型:基本类型都可以用type(),指向函数或者类的变量也可以用type()判断,返回对应的Class类型。

判断class的类型,可以使用isinstance( ,)函数,返回布尔值。

获得对象的所有属性和方法:可以使用dir()函数,返回一个包含字符串的list,

 >>> hasattr(obj, 'x')     # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
>>> fn = getattr(obj, 'y') # 获取属性'y'并赋值到变量fn #通过内置的一系列函数,可以对任意一个Python对象进行剖析,拿到其内部的数据。

注:

由于Python是动态语言,根据类创建的实例可以任意绑定属性。


给实例绑定属性

 class Student(object):               #通过self变量
def __init__(self, name):
self.name = name s = Student('Bob') #通过实例变量
s.score = 90

给类绑定属性

 class Student(object):       #直接在class中定义属性
name = 'Student'

实例属性类属性优先级高

给实例绑定方法

 >>> def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25

给类绑定方法,相当于给其所有实例绑定了方法

 >>> def set_score(self, score):        #定义一个函数并把它绑定给类
... self.score = score
...
>>> Student.set_score = set_score

限制实例的属性,在定义class的时候定义一个特殊的__slots__变量,比如只允许实例Student添加添加name和age属性:

 class Student(object):
__slots__ = ('name', 'age') # 用tuple装允许绑定的属性名称

如果暴露性地绑定属性(绑定在定义外),无法检查绑定的参数是否合法,可以通过内置方法来解决,然后通过python内置的@property装饰器将getter方法变成属性简单的使用,同时另一个装饰器@.setter把绑值setter方法变成属性。

 class Student(object):

     @property                           #编写获得值的方法并变成属性
def score(self):
return self._score @score.setter #编写带自检的设值(绑定属性)方法并变成属性
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value

如果只定义getter方法(@property),不定义setter方法(@.setter)就是一个只读属性

注:

动态绑定允许在程序运行的过程中动态给class加上功能,静态语言必须定义在class中。


面向对象高级编程


通过多重继承,一个子类就可以同时获得多个父类的所有功能。这种继承如果按树型层次继承是复杂度呈指数增长,所以采用称之为MixIn的设计。设计类的继承关系时,设计单一继承下来的主线,将需要混入的额外功能的父类名尾加MixIn,这样就可以优先考虑通过多重继承来组合多个MixIn的功能,而不是设计多层次的复杂的继承关系。

EXP Python自带了TCPServerUDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixInThreadingMixIn提供。通过组合,就可以创造出合适的服务来。

 class MyTCPServer(TCPServer, ForkingMixIn):    #编写一个多进程模式的TCP服务
pass class MyUDPServer(UDPServer, ThreadingMixIn): #编写一个多线程模式的UDP服务
pass

注:

只允许单一继承的语言(如Java)不能使用MixIn的设计。


定制类

枚举类:Enum类可以把一组相关常量定义在一个class中,即用枚举类型定义一个class,每个常量都是class的一个唯一实例。

 from enum import Enum            #定义Monthe类型的枚举类

 Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))                     #可以用Month.XXX引用一个常量

 for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
#枚举所有成员,value属性则是自动赋给成员的int常量,默认从1开始计数。 from enum import Enum, unique #可以通过从Enum派生出自定义类更精确的控制枚举 @unique #@unique装饰器可以帮助检查保证没有重复值。
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
Thu = 4
Fri = 5
Sat = 6

type()函数既可以返回一个对象的类型,又可以创建出新的类型。

要创建一个class对象,type()函数依次传入3个参数:

  1. class的名称;
  2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
  3. class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
 >>> def fn(self, name='world'): # 先定义函数
... print('Hello, %s.' % name)
...
>>> Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class

通过type()函数创建的类和直接写class是完全一样的,但是type()函数也允许我们动态创建出类来。

元类:除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass,直译为元类,简单的解释就是:先定义metaclass,就可以创建类,最后创建实例,可以把类看成是metaclass创建出来的“实例”。

metaclass是Python面向对象里最难理解,也是最难使用的魔术代码,它可以改变类创建时的行为,功能强大,但不常用,使用起来务必小心。

python advanced programming ( II )的更多相关文章

  1. python advanced programming (Ⅲ)

    IO编程 IO在计算机中指Input/Output.由于程序和运行时数据是在内存中驻留,由CPU来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口. IO编程中,Stream(流)是一个 ...

  2. python advanced programming ( I )

    函数式编程 函数是Python内建支持的一种封装,通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基 ...

  3. python's descriptor II

    [python's descriptor II] For instance, a.x has a lookup chain starting with a.__dict__['x'], then ty ...

  4. python network programming tutorial

    关于网络编程以及socket 等一些概念和函数介绍就不再重复了,这里示例性用python 编写客户端和服务器端. 一.最简单的客户端流程: 1. Create a socket 2. Connect ...

  5. python初步要点II

    [python初步要点II] 1.is & is not 操作符用于测试2个对象是否指向同一个对象,即 id(a) == id(b). 2.整形和字符串对象是不可变对象,python会高效地缓 ...

  6. Python 高级网络操作 - Python Advanced Network Operations

    Python 高级网络操作 - Python Advanced Network Operations Half Open Socket, 一个单向的 socket 被称为 half open sock ...

  7. [Python] Advanced features

    Slicing 12345 L[:10:2] # [0, 2, 4, 6, 8]L[::5] # 所有数,每5个取一个# [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, ...

  8. #3使用html+css+js制作网页 番外篇 使用python flask 框架 (II)

    #3使用html+css+js制作网页 番外篇 使用python flask 框架 II第二部 0. 本系列教程 1. 登录功能准备 a.python中操控mysql b. 安装数据库 c.安装mys ...

  9. Python Socket Programming

    本文介绍使用Python进行Socket网络编程,假设读者已经具备了基本的网络编程知识和Python的基本语法知识,本文中的代码如果没有说明则都是运行在Python 3.4下. Python的sock ...

随机推荐

  1. 使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...

  2. Http方式下载文件

    代码: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System ...

  3. 递归函数 day17

    一 递归函数 n = 1 金老板 38+2 =40n = 2 alex n+2= 金老板 36+2 = 38n = 3 wusir n+2 = alex wusir 36 def age(n): #n ...

  4. oracle 分页 where 三层

    查询[start,start+limit],包含start,包含start+limit,如start=21,limit=10结果就是21到30,包含21和30SELECT * FROM (SELECT ...

  5. c#一个统计运行时间方法

    public string STD(int HowManySecond) { ) { "; } string ShowStr = ""; * )) { ShowStr + ...

  6. 8N - 水果

    夏天来了~~好开心啊,呵呵,好多好多水果~~ Joe经营着一个不大的水果店.他认为生存之道就是经营最受顾客欢迎的水果.现在他想要一份水果销售情况的明细表,这样Joe就可以很容易掌握所有水果的销售情况了 ...

  7. President's Office

    President of Berland has a very vast office-room, where, apart from him, work his subordinates. Each ...

  8. Autel MaxiSys MS906TS tire pressure settings Lexus LS460h

    Use AUTEL MaxiSYS MS906TS error reader to install tire pressure Lexus LS460h in Vung Tau. Make : Lex ...

  9. BZOJ 3329 - Xorequ - 数位DP, 矩乘

    Solution 发现 $x \ xor \  2x = 3x$ 仅当 $x$ 的二进制中没有相邻的 $1$ 对于第一个问题就可以进行数位DP 了. 但是对于第二个问题, 我们只能通过递推 打表 来算 ...

  10. RPDU

    RPDU(Remote Power Distribution Unit) 又称网络电源控制系统.远程电源管理系统.智能PDU.智能电源分配系统,是由傲视恒安科技(北京)有限公司自主研发生产并在全国范围 ...