面向对象编程

  面向对象编程:使用类和对象实现一类功能。

类与对象

  类:类就是一个模板,模板里可以包含多个函数,函数里实现一些功能。

  对象:是根据模板创建的实例,通过实例对象可以执行类中的函数。

面向对象应用

  根据模板创建一系列例子的时候;当多个函数需要用到共同的参数时(提取公共参数放入构造函数中);应用场景(SSH)

定义类

class 类:
def func1(self):
def func22(self):

类的特性

封装:将内容封装到某个地方,以后再去调用被封装在某处的内容;对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。类中封装了字段和方法,对象中封装了普通字段的值。

  1. 防止数据被随意修改;
  2. 使外部程序不需要关注对象内部的构造,只需要通过此对象对外提供的接口进行直接访问即可。

继承:对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。即通过父类,子类以最小代码量的方式实现不同角色的共同点和不同点的同时存在。

class Person(object):
def __init__(self, name,age):
self.name=name
self.age=age class BlackPerson(Person):
def __init__(self, nation): # 先继承,再重构
self.nation=nation
Person.__init__(self,name,age) b = BlackPerson('A',22,'blabla')
# Person.__init__(self,name,age) 这里的self相当于b,b.name='A',b.age=22 # 继承方法二:新式类写法
super(BlackPerson, self).__init__(name,age)

实例

class SchoolMember(object):
members = 0 #初始学校人数为0
def __init__(self,name,age):
self.name = name
self.age = age def tell(self):
for k,v in self.__dict__:
print(k,v) def enroll(self):
'''注册'''
SchoolMember.members +=1
print("\033[32;1mnew member [%s] is enrolled,now there are [%s] members.\033[0m " %(self.name,SchoolMember.members)) def __del__(self):
'''析构方法'''
print("\033[31;1mmember [%s] is dead!\033[0m" %self.name) class Teacher(SchoolMember):
def __init__(self,name,age,course,salary):
super(Teacher,self).__init__(name,age)
self.course = course
self.salary = salary
self.enroll() def teaching(self):
'''讲课方法'''
print("Teacher [%s] is teaching [%s] for class [%s]" %(self.name,self.course,'s12')) class Student(SchoolMember):
def __init__(self, name,age,grade,sid):
super(Student,self).__init__(name,age)
self.grade = grade
self.sid = sid
self.enroll() if __name__ == '__main__':
pass

多继承:Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

经典类与新式类:当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

class 类名(object):   新式类,使用super来继承父类属性,         super(BlackPerson, self).__init__(name,age) 
class 类名:       经典类,使用类名.__init__()继承父类属性, Person.__init__(self,name,age)

继承查找方式:

  • python3:广度查找
  • python2:经典类,深度查找;新式类,广度查找

经典类多继承:深度查找

#-*-coding:utf-8 -*-
class D:
def bar(self):
print ('D.bar')
class C(D): def bar(self):
print ('C.bar')
class B(D): def bar(self):
print ('B.bar')
class A(B, C): def bar(self):
print ('A.bar') a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> D --> C
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

新式类多继承:广度查找

class D(object):

    def bar(self):
print ('D.bar')
class C(D):
def bar(self):
print ('C.bar')
class B(D):
def bar(self):
print ('B.bar')
class A(B, C):
def bar(self):
print ('A.bar')
a = A()
# 执行bar方法时
# 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
# 所以,查找顺序:A --> B --> C --> D
# 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
a.bar()

通过组合实现代码扩展

class Person(object):
def __init__(self, name,age):
self.name=name
self.age=age class BlackPerson(Person):
def __init__(self, nation,name,age,person_obj): # 先继承,再重构
self.nation=nation
self.person=person_obj #实例化组合实现扩展

多态:接口重用,一种接口,多种实现。

class F1:
pass
class S1(F1):
def show(self):
print ('S1.show')
class S2(F1):
def show(self):
print ('S2.show')
def Func(obj):
print (obj.show()) s1_obj = S1()
Func(s1_obj) s2_obj = S2()
Func(s2_obj)

实例化

类 =》实例化 =》 实例对象

obj = 类()
obj.函数1()
obj是对象,实例化的过程,通过对象去访问类中的函数

类的成员

所有成员中,只有普通字段的内容保存对象中,即:根据此类创建了多少对象,在内存中就有多少个普通字段。而其他的成员,则都是保存在类中,即:无论对象的多少,在内存中只创建一份。

构造函数__init__

self.name = name # 属性,成员变量,普通字段(对象可以访问;类内部可以访问;派生类中可以访问)

公有属性(静态字段):在类里直接定义的属性即为公有属性,所有实例化后的实例对象都能访问的属性。每个对象中保存相同的东西时,可以使用静态字段。

修改共有属性

类名.公有属性名 = value       # 改变所有实例的属性值
实例名.公有属性名 = value # 改变单个实例的属性值

注:实例化对象时,实例内存中没有存储公有属性,访问公有属性会直接通过类的内存中寻找;当使用实例名.公有属性 = value后,会在实例内存中生成一个公有属性名的变量,以后访问直接访问实例内存的值。前者相当于全局变量,后者为局部变量。

普通字段:在__init__里定义的属性为成员属性

私有属性:__private_attr_name = value; 私有成员命名时,前两个字符是下划线;仅类内部可以访问

访问私有属性

#  对外提供只读访问接口
def get_private_attr_name(self):
return self.__private_attr_name # 强制访问私有属性:
实例化名._类名__私有属性名

析构方法

在引用完成后,即实例被清除后(例如,del 实例名),执行析构方法,清空在内存中保存的实例信息。比如在server断开连接后,执行连接close等方法。

定义:def __del__(self)

类成员:方法

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
  • 类方法:    由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
  • 静态方法:由类或对象调用;无默认参数;

公有方法:在类中定义的方法为公有方法,缩进和公有属性一个级别。可以在类外面定义一个方法,然后通过实例名.方法名 = 新定义的方法名来实现。

静态方法

  定义:@staticmethod

  • 在类中的一个方法,只是名义上归类管理,但是和类基本没太大关系,只是通过类名或者实例名调用,在静态方法中访问不了类或实例中的任何属性;
  • self参数的区别,如果静态方法有参数self,调用时需要把实例当做self传入。
  • 制作工具包时,可以使用,工具包中的各种方法可以没什么关联,例如os模块。

类方法:只能访问类变量,不能访问实例变量。

  定义:@classmethod

class Foo:
def __init__(self, name):
self.name = name def ord_func(self):
""" 定义普通方法,至少有一个self参数 """
print('普通方法') @classmethod
def class_func(cls):
""" 定义类方法,至少有一个cls参数 """
print('类方法') @staticmethod
def static_func():
""" 定义静态方法 ,无默认参数"""
print ('静态方法') # 调用普通方法
f = Foo('name')
f.ord_func() # 调用类方法
Foo.class_func() # 调用静态方法
Foo.static_func()
f.static_func()

注:self就是调用当前方法的对象,类的方法保存类内存中,实例不保存类的方法,调用类方法时相当于实例指针指向类;实例化时,成员属性(普通属性)保存在实例内存中,公有属性(静态属性)保存在类内存中,可以节省内存。(静态字段的使用场景,每个对象中保存相同的东西时,可以使用静态属性)

属性方法

  定义:在普通方法的基础上添加 @property 装饰器;属性仅有一个self参数;调用时,无需括号;把一个方法变成一个静态属性。

  • 不能直接给属性方法赋值,需要使用@属性方法名.setter重新定义属性方法,并且赋值。
  • 删除属性,使用@属性方法名.deleter重新定义属性方法,并且赋值。
class Foo:

    def func(self):
print('this is method test') # 定义属性
@property
def prop(self):
print("this is property")
return 'test property'
# ############### 调用 ###############
foo_obj = Foo() foo_obj.func()
print(foo_obj.prop ) #调用属性
'''
this is method test
this is property
test property
'''

经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法;新式类中的属性有三种访问方式,并分别对应了三个被@property(获取)、@方法名.setter(修改)、@方法名.deleter(删除)修饰的方法。

class Goods(object):

    def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 @property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price @price.setter
def price(self, value):
self.original_price = value @price.deleter
def price(self):
del self.original_price obj = Goods()
print(obj.price ) # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价

静态字段方法

静态字段方法:创建值为property对象的静态字段

由于静态字段方式创建属性具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除。

class Goods(object):

    def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 def get_price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price def set_price(self, value):
self.original_price = value def del_price(self):
del self.original_price PRICE = property(get_price, set_price, del_price, 'description...') obj = Goods()
print(obj. PRICE ) # 获取商品价格
obj. PRICE = 200 # 修改商品原价
print(obj.PRICE)
print(obj.PRICE.__doc__)
del obj. PRICE # 删除商品原价

property的构造方法中有个四个参数:

  • 第一个参数是方法名,调用对象.属性时,自动触发执行方法
  • 第二个参数是方法名,调用对象.属性=xx 时,自动触发执行方法
  • 第三个参数是方法名,调用del 对象.属性时,自动触发执行方法
  • 第四个参数是字符串,调用对象.属性.__doc__ ,此参数是该属性的描述信息

类的特殊成员

__doc__:表示类的描述信息

class Foo(object):
""" description... """ def func(self):
pass a = Foo()
print (a.__doc__)
# description...

__moudle__:表示当前操作的对象在哪个模块

__class__:表示当前操作的对象的类是什么

# moudle file
class Foo(object):
""" description... """
def func(self):
pass # import file
from lib.test import Foo obj = Foo()
print(obj.__module__)
print(obj.__class__)
# lib.test
# <class 'lib.test.Foo'>

__init__:构造方法,通过类创建对象时,自动触发执行。

__del__:析构方法

  当对象在内存中被释放时,自动触发执行;此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

__call__:对象后面加括号,触发执行

class Foo:
def __init__(self):
pass def __call__(self, *args, **kwargs):
print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __call__ #构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

__dict__:类或对象中的所有成员

class Province(object):

    country = 'China'

    def __init__(self, name, count):
self.name = name
self.count = count def func(self, *args, **kwargs):
pass # 获取类的成员,即:静态字段、方法、
print (Province.__dict__)
# {'__dict__': <attribute '__dict__' of 'Province' objects>, 'country': 'China', '__doc__': None,
# '__module__': '__main__', 'func': <function Province.func at 0x0000000000A2E598>,
# '__init__': <function Province.__init__ at 0x0000000000A2E510>,
# '__weakref__': <attribute '__weakref__' of 'Province' objects>} obj1 = Province('Jiangxi',100000)
print (obj1.__dict__)
# {'name': 'Jiangxi', 'count': 100000} obj2 = Province('HuNan', 200000)
print(obj2.__dict__)
# {'name': 'HuNan', 'count': 200000}

__str__:如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。

class Province(object):

    country = 'China'

    def __init__(self, name, count):
self.name = name
self.count = count def __str__(self):
return '__str__: %s' % self.name obj1 = Province('Jiangxi',100000)
print(obj1)
#__str__: Jiangxi

__getitem__、__setitem__、__delitem__(用于索引操作,如字典。以上分别表示获取、设置、删除数据)

class Foo(object):

    def __init__(self ):
self.data = {} def __getitem__(self, key):
print('__getitem__ ',key)
return self.data.get(key) def __setitem__(self, key, value):
print('__setitem__ ',key,value)
self.data[key] = value def __delitem__(self, key): #可以用来判断是否删除
print('__delitem__',key)
del self.data[key] obj = Foo()
obj['name'] = 'Greath'
print(obj['name'])

__new__:用于创建实例,在实例化时,先执行__new__(cls,*args,**kwargs),然后执行__init__(self),如果需要自定义实例化内容时,需要用到__new__(),然后return object.__new__(cls), cls相当于类名

__metaclass__:用来表示该类由 谁 来实例化创建,用于关联原类(__metaclass__ = Mytype),在自定义类时,可以通过自定义原类中的__call__()方法,__new__()是通过原类中的__call__方法来创建的。

# -*-coding:utf-8 -*-

'''

class Foo(object):
def __init__(self):
pass obj = Foo()
print(type(obj)) # <class '__main__.Foo'>
print(type(Foo)) # <class 'type'>
# obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,
# 因为在Python中一切事物都是对象。
# obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。 # 通过type创建类: 类是由 type 类实例化产生
def func(self):
pass Foo = type('Foo', (object,), {'func': func})
# type第一个参数:类名
# type第二个参数:当前类的基类
# type第三个参数:类的成员
''' class MyType(type): def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)
print('Mytype init') def __call__(self, *args, **kwargs):
print('Mytype call')
obj = self.__new__(self, *args, **kwargs)
self.__init__(obj) class Foo(object): __metaclass__ = MyType def __init__(self):
# self.name = name
print('Foo init') def __new__(cls, *args, **kwargs):
print('Foo new')
return object.__new__(cls, *args, **kwargs) # 第一阶段:解释器从上到下执行代码创建Foo类
# 第二阶段:通过Foo类创建obj对象
obj = Foo()
#
# Foo new
# Foo init #python2和python3区别: 在python2中输出情况:Mytype init,Mytype call,Foo new,Foo init

注:

类的生成调用顺序依次是 __init__ (原类init)--> __call__(原类call) --> __new__(新类new)-->__init__(新类init)

metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好

反射

通过字符串的形式调用对象的相关成员,由以下4个内置函数实现:

  • hasattr(obj,str_attr):判断obj是否含有以str_attr字符串对应的方法或属性,返回True or False
  • getattr(obj, str_attr):获取 obj 的 str_attr,返回obj.str_attr的地址
  • setattr(obj, str_attr, value):设置一个新属性,相当于obj.str_attr = value
  • delattr(obj, str_attr):删除属性str_attr
# -*-coding:utf-8 -*-

class Foo(object):
def __init__(self):
self.name = 'greath' def func(self):
print('this is func')
obj = Foo()
# #### 检查是否含有成员 ####
print(hasattr(obj, 'name')) # True
print(hasattr(obj, 'func')) # True # #### 获取成员 ####
print(getattr(obj, 'name')) # greath
getattr(obj, 'func')() # this is func # #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
print(obj.age) #
print(obj.show(10)) # choice = input('>>')
setattr(obj, choice, 'CH') # CH
print(getattr(obj,choice))
#print(obj.choice) # AttributeError: 'Foo' object has no attribute 'choice' # #### 删除成员 ####
delattr(obj, 'name')
#print(obj.name) # AttributeError: 'Foo' object has no attribute 'name'

python修炼之路---面向对象的更多相关文章

  1. Python学习之路--面向对象

    1.面向对象概述 面向过程:根据业务逻辑从上到下写垒代码  函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可  面向对象:对函数进行分类和封装,让开发“更快更好更强...”  面向 ...

  2. Python修炼之路-函数

    Python编程之函数 程序的三种方式 面向对象:类------->class 面向过程:过程------>def 函数式编程:函数------>def 定义函数 函数:逻辑结构化与 ...

  3. python修炼之路——控制语句

    Python编程之print python2.x和python3.x的print函数区别:python3.x的print函数需要加括号(),python2.x可以不加. #-*- coding:utf ...

  4. Python修炼之路-数据类型

    Python编程之列表 列表是一个使用一对中括号"[   ]" 括起来的有序的集合,可以通过索引访问列表元素,也可以增加和删除元素. 列表的索引:第一个元素索引为0,最后一个元素索 ...

  5. Python修炼之路-异常

    异常处理 在程序出现bug时一般不会将错误信息直接显示给用户,而是可以自定义显示内容或处理. 常见异常 AttributeError # 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性 ...

  6. Python修炼之路-文件操作

    Python编程之文件操作 文件操作流程 打开文件,得到文件句柄并赋值给一个变量 通过句柄对文件进行操作 关闭文件 每次文件打开.读取信息时,Python自动记录所达到的位置,好比一个书签,之后每一次 ...

  7. Python修炼之路-模块

    模块 模块与包 模块:用来从逻辑上组织python代码(可以定义变量.函数.类.逻辑:实现一个功能),本质就是.py结尾的python文件. 例如,文件名:test.py,对应的模块名为:test 包 ...

  8. Python修炼之路-装饰器、生成器、迭代器

    装饰器 本质:是函数,用来装饰其他函数,也就是为其他函数添加附加功能. 使用情景 1.不能修改被装饰的函数的源代码:        2.不能修改被装饰的函数的调用方式. 在这两种条件下,为函数添加附加 ...

  9. Python修炼之路-Socket

    网络编程 socket套接字 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过“套接字”向网络发出请求或者应答网络请求. socket ...

随机推荐

  1. ControlTemplate in WPF —— ItemsControl

    <ItemsControl Margin=" ItemsSource="{Binding Source={StaticResource myTodoList}}"& ...

  2. 阶段3 2.Spring_06.Spring的新注解_6 Qualifier注解的另一种用法

    复制上面的数据源到下面改改名字 现在就是有两个数据源 创建一个eesy02的数据库 找到sql语句再创建Account表 现在就相当于有连个库一个eesy一个是eesy02这连个库. account里 ...

  3. js移动端滑动效果

    移动端触屏滑动的效果其实就是图片轮播,在PC的页面上很好实现,绑定click和mouseover等事件来完成.但是在移动设备上,要实现这种轮播的效果,就需要用到核心的touch事件.处理touch事件 ...

  4. 二叉搜索树倒序O(nlogn)建树

    由于在某些糟糕情况下,二叉查找树会退化成链,故而朴素建树过程其复杂度可能会退化成\(O(n^2)\). 采用倒序连边建树的方法可以使得二叉查找树建树复杂度稳定在\(O(nlogn)\). 具体思路如下 ...

  5. 【神经网络与深度学习】CIFAR-10数据集介绍

    CIFAR-10数据集含有6万个32*32的彩色图像,共分为10种类型,由 Alex Krizhevsky, Vinod Nair和 Geoffrey Hinton收集而来.包含50000张训练图片, ...

  6. 【计算机视觉】Emvisi2

    Emvisi2: A background subtraction algorithm, robust to sudden light changes Making Background Subtra ...

  7. sql回显注入-笔记

     拼接sql命令查询数据   注释 常用于sql注入            # 井号 单行注释 注意:URL编码 %23          -- 两个减号加空格 单行注释           /*   ...

  8. 拼音检查python

    #coding=utf-8 #!/usr/bin/python import sys, re, collections #读入文件 def read_file(filename): try: fp = ...

  9. Java第四周总结报告

    本周做了什么? 学习了Java的面向对象知识,包括对类,对象,抽象的理解 下周准备做什么? 学习Java面向对象的有关知识,包括对象与类,继承关系等内容 代码联系时间五个小时,看书四个小时. 本周遇到 ...

  10. mysql 加密 解密函数

    select   HEX(AES_ENCRYPT('你好世界','ABC123456')) select   AES_DECRYPT(UNHEX('E85A104B6142A7375E53C0545C ...