python-面向对象-进阶篇

类的成员

类的成员可以分为三大类:字段、方法和属性

一、字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同

class Province:
     // 静态字段
    country = '中国'
    def __init__(self, name):
     // 普通字段
        self.name = name
obj = Province('河北省')
print(obj.name)
print(Province.country)

由上述代码可以看出【普通字段需要通过对象来访问】【静态字段通过类访问】,在使用上可以看出普通字段和静态字段的归属是不同的。其在内容的存储方式不同

由上图可是:

  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份

应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段

二、方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。

  • 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由调用; 至少一个cls参数;执行类方法时,自动将调用该方法的复制给cls
  • 静态方法:由调用;无默认参数;
class Foo(object):
    def __init__(self, name):
        self.name = name

    def ord_func(self):
        """ 定义普通方法,至少有一个self参数 """

        # print self.name
        print ('普通方法')

    @classmethod
    def class_func(cls):
        """ 定义类方法,至少有一个cls参数 """

        print ('类方法')

    @staticmethod
    def static_func():
        """ 定义静态方法 ,无默认参数"""

        print ('静态方法')


# 调用普通方法
f = Foo('阿郎')
f.ord_func()

# 调用类方法
Foo.class_func()

# 调用静态方法
Foo.static_func()
三种方法
class Student:
    f = open('student', encoding='utf-8')
    def __init__(self):
        pass
    @classmethod #类方法 :有个默认参数cls,并且可以直接使用类名去
                 #调用,还可以与类属性交互(也就是可以使用类属性)
    def show_student_info_class(cls):
        # f = open('student', encoding='utf-8')
        for line in cls.f:
            name,sex = line.strip().split(',')
            print(name,sex)
    @staticmethod  #静态方法:可以直接使用类名去调用,就像正常的函数调用一样
    def show_student_info_static(): #不用传self
        f = open('student',encoding='utf-8')
        for line in f:
            name,sex = line.strip().split(',')
            print(name,sex)
# egon = Student()
# egon.show_student_info_static()  #也可以这样调,但是还是推荐用类名去调
# egon.show_student_info_class()

Student.show_student_info_class()#类名.方法名()
print('-------------------')
Student.show_student_info_static()#类名.方法名()

staticmethod和classmethod
View Code

 

相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。

不同点:方法调用者不同、调用方法时自动传入的参数不同

三、属性 

如果你已经了解Python类中的方法,那么属性就非常简单了,因为Python中的属性其实是普通方法的变种。

对于属性,有以下2个知识点:

  • 属性的基本使用
  • 属性的两种定义方式

1、属性的基本使用

# ############### 定义 ###############
class Foo:

    def func(self):
        pass

    # 定义属性
    @property
    def prop(self):
        print('prop')
# ############### 调用 ###############
foo_obj = Foo()
foo_obj.func()
foo_obj.prop #调用属性
View Code

由属性的定义和调用要注意一下几点:

  • 定义时,在普通方法的基础上添加 @property 装饰器;
  • 定义时,属性仅有一个self参数
  • 调用时,无需括号
               方法:foo_obj.func()
               属性:foo_obj.prop

注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

        属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。

实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:

  • 根据用户请求的当前页和总数据条数计算出 m 和 n
  • 根据m 和 n 去数据库中请求数据
# ############### 定义 ###############
class Pager:
    
    def __init__(self, current_page):
        # 用户当前请求的页码(第一页、第二页...)
        self.current_page = current_page
        # 每页默认显示10条数据
        self.per_items = 10 


    @property
    def start(self):
        val = (self.current_page - 1) * self.per_items
        return val

    @property
    def end(self):
        val = self.current_page * self.per_items
        return val

# ############### 调用 ###############

p = Pager(1)
p.start 就是起始值,即:m
p.end   就是结束值,即:n
View Code

从上述可见,Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。

2、属性的两种定义方式

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段

装饰器方式:在类的普通方法上应用@property装饰器

# ############### 定义 ###############
class Goods(object):

    @property
    def price(self):
        print ('@property')

    @price.setter
    def price(self, value):
        print ('@price.setter')

    @price.deleter
    def price(self):
        print ('@price.deleter')

# ############### 调用 ###############
obj = Goods()

obj.price          # 自动执行 @property 修饰的 price 方法,并获取方法的返回值

obj.price = 123    # 自动执行 @price.setter 修饰的 price 方法,并将  123 赋值给方法的参数

del obj.price      # 自动执行 @price.deleter 修饰的 price 方法
View Code

静态字段方式

class Foo:

    def get_bar(self):
        return 'wupeiqi'

    BAR = property(get_bar)

obj = Foo()
reuslt = obj.BAR
# 自动调用get_bar方法,并获取方法的返回值
print (reuslt)
View Code

反射

反射:可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),python中一切皆对象,都可以使用反射。

反射有四种方法:

hasattr:hasattr(object,name)判断一个对象是否有name属性或者name方法。有就返回True,没有就返回False

getattr:获取对象的属性或者方法,如果存在则打印出来。hasattr和getattr配套使用

    需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址,如果需要运行这个方法,可以在后面添加一对()

setattr:给对象的属性赋值,若属性不存在,先创建后赋值

delattr:删除该对象指定的一个属性

class Foo:
    f = '类的静态变量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

检测是否含有某属性
print(hasattr(obj,'name'))   //ture
print(hasattr(obj,'say_hi')) //ture

获取属性
n=getattr(obj,'name')
print(n)
func=getattr(obj,'say_hi')
func()

#设置属性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name+'sb')
print(obj.__dict__)
//{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x000001FD977BC1E0>}
print(obj.show_name(obj)) 
//egonsb
# #删除属性
delattr(obj,'age')
delattr(obj,'show_name')
delattr(obj,'show_name111')#不存在,则报错

print(obj.__dict__)
//{'name': 'egon', 'sb': True}
View Code
class Foo:
    def __init__(self):
        self.name = 'egon'
        self.age = 51
    def func(self):
        print('hello')
egg = Foo()
print(hasattr(egg,'name'))  //#先判断name在egg里面存在不存在
print(getattr(egg,'name')) //#如果为True它才去得到
print(hasattr(egg,'func'))
print(getattr(egg,'func')) //#得到的是地址
# getattr(egg,'func')()  //#在这里加括号才能得到,因为func是方法
if hasattr(egg,'func'):
    getattr(egg,'func')()
else:
    print('没找到')

对象应用反射
View Code
class Foo:
    f = 123
    @classmethod
    def class_method_dome(cls):
        print('class_method_dome')

    @staticmethod
    def static_method_dome():
        print('static_method_dome')
print(hasattr(Foo,'class_method_dome'))
method = getattr(Foo,'class_method_dome')
method()
print('------------')
print(hasattr(Foo,'static_method_dome'))
method1 = getattr(Foo,'static_method_dome')
method1()
类的应用发射

模块应用反射

# 1.导入其他模块引用
import mymodule
print(hasattr(mymodule,'test'))
getattr(mymodule,'test')()

//# # 这里的getattr(mymodule,'test')()这一句相当于
//# p = getattr(mymodule,'test')
//# p()

导入其他模块反射

本模块中反射

# 2.在本模块中应用反射
def demo1():
    print('wwww')
import sys
# print(sys.modules)
module_obj = sys.modules[__name__]  #相当于'__main__'
print(module_obj)
print(hasattr(module_obj,'demo1'))
getattr(module_obj,'demo1')()

<module '__main__' from 'D:/pcxm/面向对象/类的复习.py'>
True
wwww
View Code
# 举例
def 注册():
    print('regiester')
def 登录():
    print('login')
def 购物():
    pass
print('注册,登录,购物')
ret = input('请输入你要做的操作:')
import sys
my_module = sys.modules[__name__]  #利用sys模块导入一个自己的模块
print(my_module)
if hasattr(my_module,ret):
    getattr(my_module,ret)()
自己导入例子
def bulk(self):
    print("%s is yelling....."%self.name)
class Dog(object):
    def __init__(self,name):
        self.name=name
    def eat(self,food):
        print("%s is eating%s"%(self.name,food))
d=Dog("张文学")
choice=input(">>_").strip()
if hasattr(d,choice):
    getattr(d,choice)
    setattr(d,choice,"alex")
    print(d.name)
    
else:
    setattr(d,choice,bulk)
    c=getattr(d,choice)
    c(d)
反射例子

类的特殊成员

上文介绍了Python的类成员以及成员修饰符,从而了解到类中有字段、方法和属性三大类成员,并且成员名前如果有两个下划线,则表示该成员是私有成员,私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况,Python的类成员也是如此,存在着一些具有特殊含义的成员,详情如下:

1. __doc__

表示类的描述信息

class Foo:
    """ 描述类信息,这是用于看片的神奇 """

    def func(self):
        pass

print (Foo.__doc__)
#输出:类的描述信息
View Code

2. __module__ 和  __class__ 

  __module__ 表示当前操作的对象在那个模块

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

#!/usr/bin/env python
# -*- coding:utf-8 -*-
class C:

    def __init__(self):
        self.name = 'wupeiqi'
lib/aa.py
-----------------------------------------
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from lib.aa import C

obj = C()
print obj.__module__  # 输出 lib.aa,即:输出模块
print obj.__class__      # 输出 lib.aa.C,即:输出类
View Code

3. __init__

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

class Foo:

    def __init__(self, name):
        self.name = name
        self.age = 18


obj = Foo('kefeng') # 自动执行类中的 __init__ 方法
View Code

4. __del__

析构方法,当对象在内存中被释放时,自动触发执行。

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

5. __call__

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

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print '__call__'


obj = Foo() # 执行 __init__
obj()       # 执行 __call__
View Code

6. __dict__

类或对象中的所有成员

上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:

class Province:

    country = 'China'

    def __init__(self, name, count):
        self.name = name
        self.count = count

    def func(self, *args, **kwargs):
        print ('func')

// 获取类的成员,即:静态字段、方法、
print (Province.__dict__)
// 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}

obj1 = Province('HeBei',10000)
print (obj1.__dict__)
//获取 对象obj1 的成员
//输出:{'count': 10000, 'name': 'HeBei'}

obj2 = Province('HeNan', 3888)
print (obj2.__dict__)
// 获取 对象obj1 的成员
//输出:{'count': 3888, 'name': 'HeNan'}
View Code

 7. __str__

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

class Province:

    country = 'China'

    def __init__(self, name, count):
        self.name = name
        self.count = count

    def func(self, *args, **kwargs):
        print ('func')
    def __str__(self):
        return self.name
obj1 = Province('HeBei',10000)
print (obj1)
// hebei
View Code

8、__getitem__、__setitem__、__delitem__

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

class Foo(object):

    def __getitem__(self, key):
        print('__getitem__', key)

    def __setitem__(self, key, value):
        print('__setitem__', key, value)

    def __delitem__(self, key):
        print('__delitem__', key)


obj = Foo()

result = obj['k1']  # 自动触发执行 __getitem__
obj['k2'] = 'wupeiqi'  # 自动触发执行 __setitem__

# del obj['k1']
View Code

10. __iter__ 

用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__ 

#!/usr/bin/env python
# -*- coding:utf-8 -*-

class Foo(object):

    def __init__(self, sq):
        self.sq = sq

    def __iter__(self):
        return iter(self.sq)

obj = Foo([11,22,33,44])

for i in obj:
    print i

第三步
View Code

四、异常处理

一 异常基础

程序中难免会出现错误,而错误分为两种

1.语法错误:(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)

2.逻辑错误:(逻辑错误),比如用户输入的不合适等一系列错误

那什么是异常呢?

  异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下。异常发生之后,异常之后的代码就不执行了

 3 异常种类:在python中不同的异常可以用不同的类型(python中统一了类与类型,类型即类)去标识,

不同的类对象标识不同的异常,一个异常标识一种错误

AttributeError //试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError //输入/输出异常;基本上是无法打开文件
ImportError //无法引入模块或包;基本上是路径问题或名称错误
IndentationError// 语法错误(的子类) ;代码没有正确对齐
IndexError //下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError //试图访问字典里不存在的键
KeyboardInterrupt //Ctrl+C被按下
NameError //使用一个还未被赋予对象的变量
SyntaxError //Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError// 传入对象类型与要求的不符合
UnboundLocalError //试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError// 传入一个调用者不期望的值,即使值的类型是正确的

二、异常处理

1.什么是异常处理?      

python解释器检测到错误,触发异常(也允许程序员自己触发异常)

程序员编写特定的代码,专门用来捕捉这个异常(这段代码与程序逻辑无关,与异常处理有关)

如果捕捉成功则进入另外一个处理分支,执行你为其定制的逻辑,使程序不会崩溃,这就是异常处理

2.为何要进行异常处理?

python解析器去执行程序,检测到了一个错误时,触发异常,异常触发后且没被处理的情况下,程序就在当前异常处终止,后面的代码不会运行,谁会去用一个运行着突然就崩溃的软件。

所以你必须提供一种异常处理机制来增强你程序的健壮性与容错性 

 

3.如何进行异常处理

首先须知,异常是由程序的错误引起的,语法上的错误跟异常处理无关,必须在程序运行前就修正

1.语法:

try:
     //被检测的代码块
except 异常类型:
     //try中一旦检测到异常,就执行这个位置的逻辑

2.异常类只能用来处理指定的异常情况,如果非指定异常则无法处理

// 未捕获到异常,程序直接报错
 
s1 = 'hello'
try:
    int(s1)
except IndexError,e:
    print e

3 所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:多分枝

s1 = 'hello'
try:
    int(s1)
except IndexError,e:
    print e
except KeyError,e:
    print e
except ValueError,e:
    print e

4 万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:

s1 = 'hello'
try:
    int(s1)
except Exception,e:
    print e

5既然有这个万能异常,其他异常是不是就可以忽略了!

答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行

s1 = 'hello'
try:
    int(s1)
except KeyError as e:
    print ('键错误')
except IndexError as e:
    print ('索引错误')
except Exception as e:
    print ('错误')

6 主动触发异常

try:
    raise IndexError('错误了。。。')
except IndexError as e:
    print (e)

7 自定义异常

class lukefeng(Exception):

    def __init__(self, msg):
        self.message = msg

    def __str__(self):
        return self.message

try:
    raise lukefeng('我的异常')
except lukefeng as e:
    print (e)

8 断言

assert 1==12
if 1==2:
    print("123")
print('haha')

9异常其他结构

try:
    # 主代码块
    pass
except KeyError,e:
    # 异常时,执行该块
    pass
else:
    # 主代码块执行完,执行该块
    pass
finally:
    # 无论异常与否,最终执行该块
    pass
View Code

 

posted @ 2018-12-25 00:29  new边城  阅读(88)  评论(0)    收藏  举报