Python3学习笔记(7)—— 面向对象编程

来源:互联网 发布:adobe pdf mac版 编辑:程序博客网 时间:2024/05/29 09:25

1    面向对象编程

1.1   类

1.1.1   定义

命名:类名通常由大写字母打头,数据属性使用名词,方法使用谓词(动词加对象)。推荐使用下划线方式。

类是一个type的实例。如果定义一个类C,则type(C) 是type

可以定义一个空的类,仅用作名称空间容器,然后动态绑定实例属性。

Python 不支持纯虚函数,因此必须在子类中定义方法。

类的定义:

class Sample(baseClass):

'class documentation string'         #类文档字符串

    def __init__(self, val1, val2):    #子类最好定义它自己的构造器,否则基类的构造器会被调用

          baseClass.__init__(self,val1)#需显式传递self 实例对象给基类构造器,因为这不是在实例中调用方法。

          self.Val2=val2

1.1.2   类属性

①类属性仅与其被定义的类相绑定。类属性可通过类或实例来访问。非静态函数的类方法,只能通过实例访问。

class C(object):

foo = 100

def show():pass

def show1(self):pass 

    @staticmethod

    def show2():pass

    @classmethod

    def show3(cls):pass

 

类的数据属性,静态数据,相当于加上了static。调用时C.foo

参数为空。类的方法属性,静态方法,调用时C.show(),不能用实例调用。

self变量表示类实例,用于与实例绑定,通过实例来调用。

 

静态方法修饰符,下边的函数可以通过类名、实例直接访问。

 

类方法修饰符,下边函数可通过类名、实例直接访问。但有cls默认参数。

②可以使用一个静态成员(如起名为count)来记录实例的个数。

③访问一个类属性的时候,Python 解释器将会搜索字典以得到需要的属性。如果在__dict__中没有找到,将会在基类的字典中进行搜索,采用“深度优先搜索”顺序。

特殊的类属性

C.__name__

类C的名字(字符串)

C.__doc__

类C的文档字符串

C.__bases__

类C的所有父类构成的元组

C.__dict__

或内建函数vars(C)

类C的“属性:值”字典,字符串描述。不包含父类属性,

包括__dict__,__doc__,__module__,__weakref__以及自定义的属性;若未定义__init__(),则不会显示。不要修改__dict__的值。

而实例的__dict__仅存储与该实例相关的实例属性,未绑定属性则是空字典。

C.__module__

对类C定义所在的模块名(字符串)

C.__class__

对实例C对应的类(若对一个类求__class__,则得到“type”)的引用

1.2   实例化

1.2.1   __init__()初始化方法

在实例化时被自动调用,参数self把实例对象自动传入__init__()。

__init__()是解释器创建一个实例后,调用的第一个方法,因此严格意义上不是构造器。不应有非None返回值。

1.2.2   __new__()构造器方法

该方法必须返回一个实例,因此更像一个构造器。可以用于根据条件确定是否返回实例。

def __new__(cls, *args, **kwargs)   #cls是当前正在实例化的类名, 由Python解释器自动提供

       return object.__new__( cls, *args, **kwargs)  #可以return父类__new__()出来的实例

用于定制类

class RoundFloat(float):

def __new__(cls, val):

return super(RoundFloat, cls).__new__(cls, round(val, 2))

1.2.3   __del__()解构器方法

解构器是在类C 实例所有的引用都被清除掉后才被调用的,比如当引用计数已减少到0。

class C(P):

def __del__(self):         # "destructor" 解构器

P.__del__(self)   # 总是调用父类(或直接是object)的__del__方法

1.2.4   实例属性

给一个与类属性同名的实例属性赋值,会隐藏类属性。一旦删除了这个实例属性,类属性又可见。因此不要使用实例属性来修改类属性,而是使用类属性来修改自身。

1.2.5   type()和isinstance()内建函数

type()

       判断type(1)==int

       生成新类X=type('X', (object,), dict(a=1,b=2,c=2)) #类名;基类;类内变量

                     # <class'__main__.X'>

       import types;type(1)==types.IntType #减少函数使用次数

isinstance()

       判断是否为类的实例,与type()的区别是isinstance()会认为子类是一种父类类型,考虑继承关系

       isinstance (a,str)

       isinstance (a,(str,int,list))#若是元组中一个,则返回True

1.3   继承

①调用子类属性,会覆盖父类的同名属性,包括__init__()特殊方法。若子类定义了__init__(),子类不会自动调用父类的__init__()。可以使用super()内建函数实现。

②在子类中调用父类的同名方法:

class C(P):

       def __init__(self):

          super(C,self).__init__()

def foo(self):

        P.foo(self)

c=C()

 

super()会找到父类构造器方法。不必给出父类名称。

调用c.foo()

调用父类的未绑定方法,需传入一个实例。

1.4   访问限制

1.4.1   双下划线“__”

①实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

②如果在类中有一个__XXX 属性,它将不会被其子类中的__XXX属性覆盖。因为解释器将其改名为_ClassName__XXX。

③以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,用户不要定义。

1.4.2   单下划线“_”

①一个下划线开头的实例变量名,外部可以访问,但是按照约定不要随意访问。

②可以防止模块的属性被“fromMODULE import *”加载。

1.5   内建函数

issubclass(sub, sup)

判断是否是子类或子孙类。sup可以是元组,有任意一个是父类,则返回Ture。当sub==sup时,返回True

isinstance(obj1,obj2)

判断obj1是否是obj2的实例。obj2可以是元组

hasattr(obj, attr)

attr是字符串。返回布尔型。判断对象是否有attr属性

getattr(obj, attr [, default])

获取对象的某属性。若无则返回默认返回值default(未定义则返回AttributeError异常)

setattr(obj, attr)

设置或覆盖对象的某个属性

delattr(obj, attr)

从一个对象中删除属性

dir([object])

__dict__是dir()的子集。dir()会找到类对象或实例的全部属性,包括从父类继承的属性。不会显示定义在元中的类属性; 作用在模块上时,则显示模块的__dict__的内容;不带参数时,则显示调用者的局部变量.

vars(obj=None)

返回__dict__.。对象的属性及其值的一个字典;如果没有给出obj,vars()显示局部命名空间字典(locals())

super(type[, obj])

返回此type 的父类。传入type的实例obj,则绑定父类

1.6   包装与授权

包装:对一个已经存在的对象进行功能定制。

授权:包装类的实例可以直接访问被包装对象的属性,通过在包装类中重写__getattr__()方法。访问属性时先在实例属性中查找,然后在类属性中查找,最后通过__getattr__()查找属性,可以写做:

class Wrapper(object):

def __init__(self,obj):

    self. _wrappedObj=obj

def __getattr__(self, attr):

    return getattr(self._wrappedObj,attr)

wrappedComplex = Wrapper(3.5+4.2j)

wrappedComplex.real

1.7   高级特性

1.7.1   __slots__

动机:__dict__属性跟踪实例的所有属性,即inst.foo 等价于inst.__dict__['foo']。但是字典占用内存大,若类简单而实例多,可定义__slots__替代__dict__,带__slots__属性的类定义不会存在__dict__,以节约内存。

在定义class的时候,定义一个特殊的__slots__类变量,可以限制该class实例能添加的属性。

__slots__是一个序列对象(列表、元组、可迭代对象)。

__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

class C(object):

__slots__= ('attr1', 'attr2')

1.7.2   @property

property是getter setter deleter三者的集合。用于实现属性的get和set方法。

class C(object):

    @property

    defname(self):

       return self._name

   @name.setter

    defname(self,value):

        ifnot isinstance(value, str):

           raise TypeError('Expected a string')

       self._name = value

   @name.deleter

    defname(self):

        raiseAttributeError("Can't delete attribute")

1.7.3   描述符

描述符是创建托管属性的方法。描述符具有诸多用途:保护属性不受修改、属性类型检查和自动更新某个依赖属性的值等,是实现了__get__(),__set__()或__delete__()特殊方法的类,该类的实例对象通常是另一个类的类属性。

只实现__get__方法的对象是非数据描述符,只能被读取。而同时实现__get__和__set__的对象是数据描述符。

当使用实例对象访问属性时,都会调用__getattribute__()方法,该方法查找属性的优先级如下:

类属性à数据描述符à实例属性à非数据描述符à__getattr__()方法

①在类属性(包括祖先类)中查找数据描述符,如找到,则直接调用该数据描述符的__get__方法并将结果返回;

②若未找到,则在实例的__dict__中查找属性;

③在类(包括祖先类)的__dict__属性中查找非数据描述符

普通函数(包括函数、静态/类方法)都是非数据描述符,可被实例属性覆盖。

       class C(object):

           def __init__(self, name):

               self._name=name

           def __get__(self, obj, typ=None):

               return self.name

           def __set__(self, obj, value):

               self._name=value

       class Test(object):

           name=C()

 

test=Test()

test.name='123'  # 调用__set__()方法

1.7.4   枚举类

①Enum

from enum importEnum

       month=Enum('month',('JAY','FEB','MAR','APR'))

       print(month.JAY)      #返回month.JAY

       type(month.JAY)  # <enum 'month'>

       print(month.JAY.value)  #返回1。int,默认从1开始

       forname, member in Month.__members__.items(): #遍历

           print(name, '=>', member, ',',member.value) #第一个是JAY => month.JAY, 1

②@unique

检查保证没有重复值.

   @unique

class Weekday(Enum):

    Sun = 0 # Sun的value被设定为0

    Mon = 1

    Tue = 2

    Wed = 3

Weekday.Tue     #Weekday.Tue

Weekday['Tue']   #Weekday.Tue

Weekday(2)      #Weekday.Tue

1.7.5   定制类

__str__():

       在类中实现该方法,return一个自定义的显示字符串,调用print()和str()时将会显示该字符串。

__repr__():

       交互界面直接输入变量名,输出的结果是调用repr()的结果,用于调试服务。

       在类中可以直接写__repr__ = __str__

__iter__():

返回一个迭代对象,使对象可以用于iter()内建函数。不断调用该迭代对象的__next__()方法,返回下一个值,直到StopIteration错误时退出循环。对于自定义的迭代器,只需返回自身self。

__next__():

       实现该方法就是一个迭代器。

       def __next__(self):

        self.a, self.b =self.b, self.a + self.b # 计算下一个值

        if self.a > 100000:# 退出循环的条件

            raiseStopIteration()

        return self.a # 返回下一个值

__getitem__(self, n):

       使能够像list那样按照下标取出下标为n的元素。

__setitem__( self, n):

       把对象视作list或dict来对集合赋值。

__delitem__( self, n):

       用于删除某个元素。

__getattr__(self, attr):

当调用实例的不存在的属性,将尝试调用该方法,动态返回一个值。若尝试该函数和实例中未定义的其他属性,则会返回None。对于其他未定义的属性,可以抛出异常。raise AttributeError('xxxxxxxxxx').

__call__():

       使实例可以像函数一样,成为一个可调用callable对象。可以定义参数,调用时执行该特殊方法下的内容。

       如c=C(); c() #将执行__call__()。

       callable()内置函数可以判断是否是可调用对象。

__nonzero__(self):用于内建函数bool(), 定义转为布尔值的方法。

__len__(self):用于内建函数len(),求取对象“长度”。

数值定制用的特殊方法:__add__(self, other)、__mul__(self, num):
原创粉丝点击