Python之路【第6天】

来源:互联网 发布:skycc营销软件客服 编辑:程序博客网 时间:2024/05/13 05:02

目录

  1. 深入面向对象
  2. 类的成员
    2.1字段
    2.1方法
    2.3属性
  3. 类成员的修饰符
    3.1公有成员
    3.2私有成员
  4. 类的特殊成员
  5. 异常处理
  6. 反射

深入面向对象

  • 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用
  • 类 是一个模板,模板中包装了多个“函数”供使用(可以讲多函数中公用的变量封装到对象中)
  • 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
  • 面向对象三大特性:封装、继承和多态

类的成员

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

一、字段

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

class Province:    country="中国" #静态字段    def __init__(self,name):        self.name=name   #普通字段obj=Province("河北省")print(obj.name)  # 直接访问普通字段print(Province.country)  # 直接访问静态字段
  • 静态字段在内存中只保存一份
  • 普通字段在每个对象中都要保存一份

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

二、方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
•普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
•类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
•静态方法:由类调用;无默认参数;

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

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

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

三、属性

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

对于属性,有以下三个知识点:
•属性的基本使用
•属性的两种定义方式

1、属性的基本使用

class Foo:    def func(self):        print("调用了方法")        pass    @property  #定义属性    def prop(self):        print("prop方法")        passobj=Foo() #实例化obj.func()  #调用func方法obj.prop  #调用属性,无需加括号

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

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

2、属性的两种定义方式

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

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

我们知道Python中的类有经典类和新式类,新式类的属性比经典类的属性丰富。( 如果类继object,那么该类是新式类 )
经典类,具有一种@property装饰器

class Goods:    @property   #定义属性    def price(self):        return "1000"obj=Goods()  #实例化print(obj.price)  #调用属性

新式类,具有三种@property装饰器

class Goods(object):    @property   #定义属性    def price(self):        print("@property")    @price.setter   #可以设置属性赋值    def price(self,value):        self.value=value        print("@price.setter[%s]"%self.value)    @price.deleter   #可以执行删除操作    def price(self):        print("@price.deleter ")obj=Goods()obj.price   #调用price方法obj.price=123  #调用price方法,将 123赋值给方法的参数del obj.price#结果为:@property@price.setter[123]@price.deleter 

注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法

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

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

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,value):        del self.original_price    #分别将三个方法定义为对同一个属性:获取、修改、删除    price=property(get_price,set_price,del_price,"价格属性描述")obj=Goods()print(obj.price)    # 获取商品价格obj.price=200    # 修改商品原价print(obj.price)#del obj.price    # 删除商品原价

类成员的修饰符

每一个类的成员而言都有两种形式:

  • 公有成员,在任何地方都能访问
  • 私有成员,只有在类的内部才能方法

私有成员和公有成员的定义不同:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:initcalldict等)

class C:    def __init__(self):        self.name="public"        self.__foo="private"

私有成员和公有成员的访问限制不同:
静态字段

公有静态字段:类可以访问;类内部可以访问;派生类中可以访问
私有静态字段:仅类内部可以访问;

class C:    name="公有静态字段"    def func(self):        print(C.name)class D(C):    def show(self):        print(C.name)C.name  #类访问obj=C()  #实例化obj.func()  #类内部可以访问sub_obj=D()  #实例化sub_obj.show() #派生类中可以访问#结果为:公有静态字段公有静态字段

私有静态字段

class C:    __name="公有静态字段"    def func(self):        print(C.__name)class D(C):    def show(self):        print(C.__name)#C.__name  #类访问  ==>提示没有个属性,访问不了obj=C()  #实例化obj.func()   #内部访问  ==>正常访问sub_obj=D()  #实例化sub_obj.show()  #派生类访问  ==>提示没有个属性,访问不了

普通字段

公有普通字段:对象可以访问;类内部可以访问;派生类中可以访问
私有普通字段:仅类内部可以访问;

class C:    def __init__(self):        self.foo="公有字段(属性)"    def func(self):        print(self.foo)  #类内部访问class D(C):    def show(self):        print(self.foo)  #派生内中访问obj=C()  #实例化obj.foo  #通过对象访问   ==> 可以访问#print(obj.foo)obj.func()  #类内部访问  ==>可以访问obj_sub=D()  #实例化obj_sub.show()  #派生类可以访问  ==>可以访问

私有字段(属性)

class C:    def __init__(self):        self.__foo="私有字段"    def func(self):        print(self.__foo)  #类内部访问class D(C):    def show(self):        print(self.__foo)  #派生类访问obj=C() #实例化#obj.__foo   #通过对象访问   ==>提示无法访问obj.func()  #类内部访问  ==>可以访问obj_sub=D()  #实例化obj_sub.show()  #派生类访问  ==>提示无法访问

方法、属性的访问于上述方式相似,即:私有成员只能在类内部使用

类的特殊成员

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

  1. doc
    表示类的描述信息
class Foo:    """描述类信息,这里会被显示"""    def func(self):        passprint (Foo.__doc__)#结果为:描述类信息,这里会被显示
  1. moduleclass

module 表示当前操作的对象在那个模块
class 表示当前操作的对象的类是什么

__main__<class '__main__.C'>#结果为:__main__<class '__main__.C'>

3 call

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

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

4 dict
获取类的成员,即:静态字段、方法、

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

class Foo:    def __str__(self):        return "aa"obj=Foo()print (obj)  #打印得到的返回值print(Foo.__dict__)  # 获取类的成员#结果为:aa{'__module__': '__main__', '__str__': <function Foo.__str__ at 0x00000198EAC52620>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}

6 getitemsetitem_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"]="aa"  #自动触发执行   __setitem__del obj["k1"]   #自动触发执行  __delitem__

7 getslicesetslicedelslice

该三个方法用于分片操作,如:列表

异常处理

1、异常基础

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面
需求:将用户输入的两个数字相加

while True:    num1=input("num1:")    num2=input("num2:")    try:        num1=int(num1)        num2=num2  #故意不将字符串转化为数字型        ret=num1+num2        break    except Exception:        print("出现异常,信息如下:")        breakprint (ret)#结果为:num1:1num2:2出现异常,信息如下:

2、异常种类

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

主动触发异常

try:    raise Exception('错误了。。。')except Exception:    print("出现了错误")

自定义异常

class UserException(Exception):    def __init__(self,msg):        self.message=msg    def __str__(self):        return self.messagetry:    raise UserException("自定义异常")except UserException:    print("出现了错误")

反射

python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

class Foo(object):    def __init__(self):        self.name="aa"    def func(self):        return "func"obj=Foo()# #### 检查是否含有成员 ####print(hasattr(obj,"name"))print(hasattr(obj,"func"))# #### 获取成员 ####getattr(obj,"name")getattr(obj,"func")# #### 设置成员 ####setattr(obj,"age",18)setattr(obj,"show",lambda num:num+1)print(obj.age)print(obj.show(obj.age))# #### 删除成员 ####delattr(obj,"name")#delattr(obj,"func")#结果为:TrueTrue1819

结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

原创粉丝点击