day08面向对象(二)

Python 面向对象

 本章内容简介:

1. 类的成员:
    1) 字段 : 普通字段、静态字段;

    2) 方法 : 普通方法、静态方法、类方法;

    3) 属性 : 普通属性(获取、设置、删除);

2. 成员修饰符:

    1)公有的       任何 都可以调用;

    2)私有的       仅类自己内部可以调用;可以用一个另类的方法调用,就是 obj._类名__私有(字段等),好吧,知道能这么用就行了,最好忘了它。

3. 类的特殊成员:

    __init__      构造方法;  

    __dic__      注释文档查看,函数下加引号写的第一位置,会被此成员读取;

    __call__      变量加括号执行call方法;

    __str__      将内存地址的内容,读取成str内容;     

    __setitem__    

    ......

4. 面向对象的其它内容:

    -- isinstance    判断一个对象是否属于某个类;

    -- issubclass    判断一个类是否属于某个类的子类;

    -- 执行父类构造方法

    -- 应用:

        自定义类型,对字典进行补充,有序字典,源码的扩展;

5. 设计模式之单例模式;

6. 异常处理:

    try  ===  except === = finally

一. 类的成员

  • 字段

1. 普通字段,实例:

class Foo:
    def __init__(self,name):
        self.name = name

代码解析:

  name就是普通字段,当Foo函数,被实例化时,如:obj = Foo('hailong') ,对象obj 就使用了name普通字段,普通字典默认被对象使用,所以普通字段是保存在对象里的;

2. 静态字段,实例:

class Province:
    country = "中国" # 静态字段,保存在类里,节省内存空间;

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

country = Province.country
tj = Province("天津")

print(tj.country ,'	',country)

代码解析:

  country是静态字段,如上实例所示,静态字段,类可以调用,对象也可以调用,其它语言里是不允许的,之所以对象可以调用静态字段,是因为对象里的类对象指针(对象去数据时,是先从自己本身找,找不到,通过类对象指针到类里找)通过这种方式来访问的;通常情况下,我们要使用类来调用静态字段;

总结:

  普通字段,用对象来访问; 静态字段,使用类来访问,实在没办法时才用对象访问;

  当执行程序时,如果没创建对象时,普通字段不会加载到内存,但是静态字段默认会加载到内存;

  •  方法

1. 普通方法,实例:

class Province:
    country = "中国" 

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

    def show(self):  # 方法属于类,是由对象调用的
        print(self.name)

tj = Province("天津")
tj.show()

代码解析:

  方法属于类,普通方法存在类里,是由对象调用的;

2. 静态方法,实例:

class Province:
    country = "中国" # 静态字段,保存在类里,节省内存空间;

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

    @staticmethod    # 静态方法,是由类调用的
    def func(arg1,arg2):
        print(arg1,arg2)

Province.func(123,'qcc'

代码解析:

  静态方法是由类调用的,就是方法去掉self参数后,是用装饰器staticmethod,传参自定义,不需要创建对象,就可以执行的方法。用于一些不通用的方法,这样节省内存空间;

  相当于Python的函数;

3. 类方法,实例:

class Province:
    country = "中国" # 静态字段,保存在类里,节省内存空间;

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

    @classmethod
    def f1(cls):
        print(cls)

Province.f1()

代码解析:

  类方法是由类调用的,它有一个默认的形式参数cls,cls相当于类名;

  • 属性

1. 普通属性,实例:

class Pager:
    def __init__(self,count_pager):
        self.count_pager = count_pager

    @property  # 普通属性
    def all_pager(self):
        a1,a2=divmod(self.count_pager,10)
        if a2 == 0:
            return a1
        return a1+1

p = Pager(101)
print(p.all_pager)  # 执行普通属性,不用加括号了

代码解析:

  普通属性,具有方法的访问写形式,具有字段的访问形式。 相当于方法去掉括号,由对象调用;

2. 属性操作(设置)实例:

class Pager:
    def __init__(self,count_pager):
        self.count_pager = count_pager

    @property
    def all_pager(self):
        a1,a2=divmod(self.count_pager,10)
        if a2 == 0:
            return a1
        return a1+1

    @all_pager.setter
    def all_pager(self,value):
        print(value)

p = Pager(101)
p.count_pager = 211  # 设置属性,对属性的方法进行setter;
print(p.count_pager)

代码解析:

  对象生成后,count_pager 根据类参数定义一个值,当想要使用一个新值时,需要使用到设置属性,给字段count_pager重新赋值,使用普通属性方法setter装饰器,重新给字段赋值;

3. 属性操作(删除)实例:

class Pager:
    def __init__(self,count_pager):
        self.count_pager = count_pager

    @property
    def all_pager(self):
        a1,a2=divmod(self.count_pager,10)
        if a2 == 0:
            return a1
        return a1+1

    @all_pager.setter
    def all_pager(self,value):
        print(value)

    @all_pager.deleter
    def all_pager(self):
        print("del all_pager")

p = Pager(101)
p.count_pager = 211 #设置方法,会调用all_pager.setter下的方法;
print(p.count_pager)  
del p.all_pager # del 是个语法,会调用all_pager.deleter下的方法;

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

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

属性的另一种写法

class Pager:
    def __init__(self,name):
        self.name = name

    def f1(self):
        return 123

    def f2(self,value):
        print(value)

    def f3(self):
        print('del f1') # 还没弄明白,具体怎么用

    foo = property(fget=f1,fset=f2,fdel=f3)

obj = Pager('hailong')
res = obj.foo
print(res)
obj.foo = 456
del obj.foo

代码解析:

  不用加装饰器了,直接给静态字段赋值,使用property,来完成属性的功能; 

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

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

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

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

二.  成员修饰符

 1. 公有的,实例:

class Province(object):

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


hb = Province("河北")
print(hb.name)  #name是公有的,任何对象都可以调用;

代码解析:

  这个例子里,name就是公共的,任何基于Province创建的对象都能使用;

2. 私有修饰符,实例(一):

class Province(object):

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

    def f1(self):
        print(self.__name)

hb = Province("河北")
hb.f1()

# print(hb.__name) # 报错 AttributeError: 'Province' object has no attribute '__name'

代码解析:

  当把公有的,加上双下划线后,就变成私有的了,这时外部不能调用,只能是类里的方法可以调用;只有自己访问可以,不能被继承;

实例(二):

class Province(object):
    __paw = 123
    def __init__(self,name):
        self.__name = name

    def f1(self):
        print(Province.__paw)

    @staticmethod
    def f2():
        print(Province.__paw)

hb = Province("河北")
hb.f1()       # 通过变量调用使用了私有字段的方法;
Province.f2() #直接用类调用,静态方法里的私有字段;
hb.f2()  # 也可以成功,但是不建议这样使用;
Province.f1() # 不可以在外部直接使用类里的私有字段,报错 TypeError: f1() missing 1 required positional argument: 'self'

三. 特殊成员

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

1. del、call 和  str方法:

class Foo(object):

    instance = None
    def __init__(self,name,age):
        self.name=name
        self.age = age

    # 析构方法,系统垃圾回收之前执行这个方法;
    def __del__(self):
        pass

    #
    def __call__(self, *args, **kwargs):
        print("call")

    #
    def __str__(self):
        return "%s - %s" % (self.name,self.age)

obj = Foo("hailong",23)
obj1 = Foo("eric",23)
print(obj)       # 执行时,调用了str方法
res = str(obj1)  # 执行时,调用了str方法
obj()  # 变量加括号,执行call方法;
Foo("hailong",23)() # 类执行,加括号执行call方法;
print(obj1)

2. add 、 dict 方法:

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def __add__(self, other):
        temp = "%s - %d" % (self.name,other.age)
        return temp

obj1= Foo("hailong",23)
obj2= Foo('eric',19)
res = obj1 + obj2     # 执行add方法;
print(res)
print(obj1.__dict__)  # 返回obj1封装的内容,字典格式输出;

如果执行  类.__dict__ 会打印出类里封装的所有的成员,一般用于对象的封装查看;

3. getitem、setitem和delitem方法:

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def __getitem__(self, item):
        return 123

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

    def __delitem__(self, key):
        print("del %s" % key)

obj1= Foo("hailong",23)
res = obj1['abc']  # 执行getitem方法
print(res,"----")
obj1['k1'] = 122   # 执行了setitem方法 ,执行结果是k1 122
print(obj1.__dict__) # obj1没有任何改变;
del obj1['k1']      # 执行delitem方法,

对象后加括号执行call方法,加上中括号执行 getitem方法。。。

4. getitem 切片方法:

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def __getitem__(self, item):
        print(item.start)
        print(item.stop)
        print(item.step)
        return 123

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

obj1= Foo("hailong",23)
# res = obj1['abc']  # 字符串方法没有切片start等位置属性;
res1 = obj1[0:4:2]

5. iter 迭代 方法:

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

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def __iter__(self):   # iter方法
        return iter([11,22,33,44])  # 可迭代类型;

obj = Foo("hailong",23)
for item in obj:   
    print(item)

for循环,例子二:

class Foo:
    def __init__(self,name,age):
        self.name = name
        self.age  = age

    def __iter__(self):
        yield 1
        yield 2

obj = Foo("hailong",23)
for item in obj:
    print(item)

6.  __module__ 和  __class__ 

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

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

四. 面向对象的其它内容 

1. isinstance 和 issubclass 内置变量;

class Foo:
    pass

class Func(Foo):
    pass

obj = Foo()
res = isinstance(obj,Foo) # obj  是 基于Foo类创建的,返回True;
print(res)
ret = issubclass(Func,Foo) # Func 类是 Foo类的一个子类,返回True;
print(ret)

2.  执行父类构造方法;

如何执行,看实例:

class Foo:
    def f1(self):
        print("Foo.f1")

class Func(Foo):
    def f1(self):
        super(Func,self).f1()
        print('Func.f1')

obj = Func()
res = obj.f1() # obj 执行的了自己的f1方法也执行了父类里的f1方法,因为有super;

这个方法应用于:当想要使用其它程序的功能或框架里的方法时,继承框架或功能的类方法,使用super就能使用框架的功能了;

3. 有序字典:

class Mydict(dict):

    def __init__(self):
        self.li = []
        super(Mydict,self).__init__()

    def __setitem__(self, key, value):
        self.li.append(key)
        super(Mydict,self).__setitem__(key,value)

    def __str__(self):
        temp_li = []
        for key in self.li:
            value = self.get(key)
            temp_li.append("'%s':%s" %(key,value))
        temp_str = "{" + ",".join(temp_li) + "}"
        return temp_str


obj = Mydict()
obj['k1'] = 123
obj['k2'] = 456
print(obj)

代码解析:

  继承字典的类,将正常生成字典的key,添加到一个空列表,通过自定义类型对字典的生成过程重新定义,将无序存储的字典,写成一个列表,根据字符串拼接的方法,读取成有序的字典;

五. 设计模式之单例模式

用来创建单个实例,什么时候用?  不管获取多少个实例,他们的内存地址是一样的;

class Foo:
    instance = None
    def __init__(self,name):
        self.name = name

    @classmethod
    def get_instance(cls):
        if cls.instance:
            return cls.instance
        else:
            obj = cls('hailong')
            cls.instance = obj
            return obj

obj1 = Foo.get_instance()
obj2 = Foo.get_instance() # 不管获取多少个实例,他们的内存地址是一样的;
print(obj1,obj2) # 两个对象内存地址相同;

六. 异常处理

try --->except  try内容如果不报错,永远不会执行except的内容;

1、异常基础

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!

try:
    pass
except Exception,ex:
    pass

需求:将用户输入的两个数字相加

while True:
    num1 = input('input num1:')
    num2 = input('input num2:')
    try:
        num1 = int(num1)
        num2 = int(num2)
        result = num1 + num2
        try:
            print(result)
        except NameError as A:
            print(A)
    except Exception as E:
        print(E)

2、异常种类

python中的异常种类非常多,每个异常专门用于处理某一项异常!!!

1) 常用异常:

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

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

2)另一种结构的异常:

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

3) 主动抛出异常:

try:
    raise Exception('错误了。。。')
except Exception as ex:
    print(ex)

4) 自定义异常:

class WupeiqiException(Exception):
 
    def __init__(self, msg):
        self.message = msg
 
    def __str__(self):
        return self.message
 
try:
    raise WupeiqiException('我的异常')
except WupeiqiException as e:
    print(e)

5)断言

# assert 条件
 
assert 1 == 1
 
assert 1 == 2

条件成立执行,不成立就不执行;

________________________________________________________END____________________________________________________

原文地址:https://www.cnblogs.com/liuhailong-py-way/p/5624127.html