天天看点

Python学习系列:面向对象高级编程(二)

Python中的高级特性挺多的,在这里提到的只是微不足道的部分,只要是看起来比较好的特性,不管是新想到的,还是借鉴于其他语言的。只要好用,语言开发者都是可以加的。因为Python有自己的特性,它新加的一些功能看起来和其他语言有些不同,但是只要能明白这个特性能给我们的编程带来好处就行,能够优化我们的编程,为什么不用呢?

__slots__

python作为一门动态语言,给我的感觉,对于一个对象,感觉可以往对象上加入任何东西(属性、方法)一样。这个的好处就是扩展容易,极大的灵活,但是呢,越灵活,控制能力越低,有点不太安全。。在Python中,提供了一个特殊的变量:__slots__,它可以限制定义的变量。例子如下:

class A(object):
    #表示A的实例只能定义name,age,method1这三个变量,其他的会报错,当然了,直接通过类名A来定义其他变量是可以的
    __slots__ = ('name', 'age', 'method1')

    def __init__(self, name):
        self.name = name
#这里不能定义method1,提示和__slots__中的method1冲突
#   def method1(self):
#       print('i am method1')

    #method2方法中没有self,因此这个方法不能通过类的实例进行调用,但是可以直接通过类名进行调用。
    def method2():
        print('i am method2')

#下面看使用
a = A('jcw')
a.age =  #成功赋值
a.name = 'jxr' #成功赋值
a.score =  #出错了。。
A.score =  #成功赋值
def m():
    print('i am m')
a.method1 = m #成功赋值
a.method1() #返回: i am m
           

@property

装饰器模式,大家基本都听过吧,就算没有听过,也能猜出这种模式的作用。比如已经定义好了一个函数,我们想在函数执行之前或之后新增一些功能,给这个函数稍微的修饰一下,扩展一下。在Java中主要就是通过接口来实现装饰器模式的,而在python中,使用类似@property这个格式来实现的。例子如下:

class Student(object):

   #@property相当于装饰器
    @property
    def score(self):
        return self._score

    #@score.setter相当于装饰器
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value <  or value > :
            raise ValueError('score must between 0 ~ 100!')
        self._score = value


student = Student()
#上面两个装饰器是python中自带的,_score的调用和赋值通过上面的装饰器,其实间接的会调用上面的两个函数

#这个赋值语句会调用@score.setter修饰的函数
student.score = 

#@这个取值函数会调用@property修饰的函数
student.score
           

如何定制一个类?

在python中,class中有许多特殊用途的函数,通过重写这些函数,我们可以定制我们需要的类。

  • __len__():当我们在调用len()函数时,内部其实调用的就是__len__()函数
  • __str__():当我们调用print()等打印一个实例时,其实调用的就是__str__(),通过重写这个函数,可以打印比较容易读的格式。
  • __repr__():当直接在交互界面输入实例名时,调用的是__repr__()函数,为了显示美观,可以使__repr__ = __str__
  • __iter__():如果一个类想用于for…in循环,可以在类中实现这个函数,在循环过程中,会调用类中的__next__()函数,因此,也需要实现__next__()函数
  • __getitem__():实现这个方法,可以实现像list那样通过下标取元素
  • __getattr__():实现这个方法,当调用的属性不存在时,可以再调用这个函数。
  • __call__():可以实现在类本身上进行调用。即:s = Student(); s()写法会调用__call__()函数。

如何不通过class方式来定义一个类?

动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。

type()

使用type()来创建一个类,跟class方式一样,例子如下:

def f(self):
    print('hello, world')
#通过这种写法创建一个类,其中第一个参数表示类名,第二个参数表示父类构成的元组,第三个参数时一些变量构成的字典。
Hello = type('Hello', (object, ), dict(hello = f))
h = Hello()
h.hello() #输出hello, world
           

metaclass

metaclass感觉和Java中的Class类挺像的,Class类的实例相当于是我们定义的每一个类。

在使用中,先定义metaclass,就可以创建类,再创建实例。

这个东西比较复杂,也没仔细看,下面列举个简单的例子:

#先定义一个元类,元类都是从type类型进行派生的
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

#定义我们的类,指定metaclass为我们自己定义的。
#通过指定metaclass,表示MyList需要通过ListMetaclass.__new__()来创建。
#其中__new__()函数中的四个参数依次为:当前准备创建类的对象、类名、类的父类、类的方法的集合
class MyList(list, metaclass=ListMetaclass):
    pass

myList = MyList()
myList.add() #返回值为:[1]