python面向对象高级编程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python面向对象高级编程相关的知识,希望对你有一定的参考价值。

python中属性和方法的动态绑定 

class Student(object):
    pass
 
# 实例化一个对象    
s = Student()
# 给这个对象绑定一个属性name
s.name = ‘John‘
 
print(s.name)
John
 
# 定义一个方法
def set_age(self, age):
    self.age = age
 
# 导入模块    
from types import MethodType
 
#给s这个对象绑定一个set_age的方法
s.set_age = MethodType(set_age, s)
 
s.set_age = 30
s.age
25
 
 
# 给实例对象绑定的方法只对该实例有效。
 
 
# 给所有的实例绑定方法的做法是给类绑定方法
def set_score(self, score):
    self.score = score
     
Student.set_score = MethodType(set_score, Student)
 
# 给类绑定方法后,所有实例均可调用

python中的__slots__变量

__slots__变量的作用就是限制该类实例能添加的属性:

class Student(object):
    __slots__ = (‘name‘, ‘age‘)

在创建Student实例的时候只能动态绑定name和age这两个属性。

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



python的@property装饰器

@property是python内置的装饰器,它的作用就是把一个方法变成属性访问。

class Student(object):
    @property
    def score(self):
        return self._score
    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError(‘score must be an integer!‘)
        if value<0 or value>100:
            raise ValueError(‘score must between 0 ~ 100!‘)
        self._score = value
s = Student()
s.score = 60 # 实际转化为s.set_score(60)
s.score # 实际转化为s.get_score()
60


只定义getter方法,不定义setter方法就是一个只读属性

class Student(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self, value):
        self._birth = value
    @property
    def age(self):
        return 2015 - self._birth

birth有读写,age是只读



python的多重继承

class Animal(object):
    pass
class Mammal(Animal):
    pass
class Bird(Animal):
    pass
class Dog(Mammal):
    pass
class Bat(Mammal):
    pass
class Parrot(Bird):
    pass
class Ostrich(Bird):
    pass
class Runnable(object):
    def run(self):
        print("Running...")
class Flyable(object):    
    def fly(self):        
        print("Flying...")

类的多继承

class Dog(Mammal, Runnable):
    pass
class Bat(Mammal, Flyable):
    pass


python中的MixIn

MixIn的作用就是为了更好地看出继承关系,目的就是给一个类增加多个功能,这样在设计类的时候,我们有限考虑通过多重继承来组合多个MixIn的功能 ,而不是设计多层次的复杂的继承关系。


python自带库使用MixIn的实例举例:

TCPSserver和UDPServer要同时服务多个用户就必须使用多进程或多线程模型。这两种模型由ForkingMixIn和ThreadingMixIn提供。


多进程的TCP服务:

class MyTCPServer(TCPServer, ForkingMixIn):
    pass


多线程的UDP服务:

class MyUDPServer(UDPServer, ThreadingMixIn):
    pass


更先进的协程模型,编写一个CoroutineMixIn:

class MyTCPServer(TCPServer, CoroutineMixIn):
    pass




python定制类

class Student(object):    
    def __init__(self, name):
        self.name = name
  def __str__(self):        
      return ‘Student object (name: %s)‘ % self.name
print(Student(‘Michael‘))
Student object (name: Michael)
s = Student(‘Michael‘)
s
0x345ldf05d


直接显示变量调用的不是__str__(),而是__repr__()。

__str__()和__repr__()的区别是:__str__()返回用户看到的字符串,__repr__()返回程序开发者看到的字符串__repr__()是为调试服务的。

class Student(object):    
    def __init__(self, name):        
        self.name = name
  def __str__(self):
    return ‘Student object (name=%s)‘ % self.name
    __repr__ = __str__


一个类想被用于for循环中,必须实现一个__iter__()方法,返回一个迭代对象,然后for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到StopIteration退出循环。

class Fib(object):    
    def __init__(self):
      self.a, self.b = 0, 1
  def __iter__(self):
    return self
  def __next__(self):
    self.a, self.b = self.b, self.a + self.b
    if self.a > 100000:
        raise StopIteration()
      return self.a
for n in Fib():
    print(n)
1
1
2
3
5
.
.
.
46368


如果想把一个类表现成list那样取出元素,需要实现__getitem__()方法:

class Fib(object):
    def __getitem__(self, n):
        a, b = 1, 1
        for x in range(n):
            a, b = b, a+b
        return a

如果这个类实现的__getitem__()方法,就可以把这个类当成list来操作,但是需要判断__getitem__()方法传入的参数的类型。 该参数可能是一个int,也可能是一个切片对象slice。 需要对该参数做判断。

class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a+b
            return a
        if isinstance(n, slice):
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a+b
            return L
 f = Fib()
 f[0:5]
 [1,1,2,3,5]
 f[:10]
 [1,1,2,3,5,8,13,21,34,55]

对一个__getitem__()方法的参数做判断。并对此进行做其他工作。对step的处理,对负数的处理,等等。


__getattr__():该方法动态返回一个属性。

当调用一个不存在的属性的时候,python会试图调用__getattr__(self, ‘score‘)来尝试获得属性。


__call__()方法直接在实例本身上调用,直接对实例调用。

class Student(object):
    def __init__(self, name):
        self.name = name
    def __call__(self):
        print("My name is %s." % self.name)
        
s = Student(‘Michael‘)
s()
My name is Michael.

__call__()定义参数。

判断一个变量是对象还是函数,更多的时候我们判断一个对象是否能被调用。能被调用的对象就是一个callable对象。



python的枚举类

定义一个枚举类:

from enum import Enum
Month = Enum(‘Month‘, (‘Jan‘, ‘Feb‘, ‘Mar‘, ‘Apr‘, ‘May‘, ‘Jun‘, ‘Jul‘, ‘Aug‘, ‘Sep‘, ‘Oct‘, ‘Nov‘, ‘Dec‘))

枚举类的使用:

直接使用Month.Jan来引用一个常量,或者枚举它的所有成员。

for name, member in Month.__members__.items():
    print(name, ‘=>‘, member, ‘,‘, member.value)
form enum import Enum, unique
@unique
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6

@unique装饰器保证没有重复值。



python使用元类

type()函数可以查看一个类型或变量的类型,还可以创建出新的类型。

通过type()函数创建一个class对象需传入3 个参数:

  1. class的名称。

  2. 继承的父类集合,注意python的多继承。

  3. class的方法名称与函数绑定,

def fn(self, name=‘world‘):
    print(‘Hello, %s.‘ % name)
    
Hello = type(‘Hello‘, (object,), dict(hello=fn))
h = Hello()
h.hello()

print(type(Hello))

print(type(h))


metaclass的作用就是控制类的创建行为。

我们想创建类就必须根据metaclass创建出类,先定义metaclass,再创建类。

metaclass允许你创建类或修改类

元类使用的实例:

# 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)

有了ListMetaclass,我们在定义类的时候还是要指示使用ListMetaclass来定制类,传入关键字参数metaclass:

class MyList(list, metaclass=ListMetaclass):
    pass

在创建MyList类的时候要通过ListMetaclass.__new__()来创建,我们可以修改类的定义,加上新的方法,返回修改后的定义。

__new__()方法接收到的参数依次是:

  1. 当前准备创建的类的对象

  2. 类的名字

  3. 类继承的父类集合

  4. 类的方法集合


一般情况下不会遇到metaclass,在使用ORM的时候总会遇到需要通过metaclass修改类定义的。

ORM--object relational mapping,对象-关系映射。就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样写代码更简单,不用直接操作sql语句。

要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。

一个简单的ORM框架实例:

class User(Model):
    # 定义类的属性到列的映射
    id = IntegerField(‘id‘)
    name = StringField(‘username‘)
    email = StringField(‘email‘)
    password = StringField(‘password‘)
    
# 创建一个实例
u = User(id = 123, name=‘Michael‘, email=‘[email protected]‘, password=‘my-pwd‘)
# 保存到数据库
u.save()

按上面的接口来实现该ORM

class Field(object):
    def __init__(self, name, column_type):
        self.name = name
        self.column_type = column_type
    def __str__(self):
        return ‘<%s:%s>‘ % (self.__class__.__name__, self.name)

定义各种类型的Field

class StringField(Field):
    def __init__(self, name):
        super(StringField, self).__init__(name, ‘varchar(100)‘)

class IntegerField(Field):
    def __init__(self, name):
        super(IntegerField, self).__init__(name, ‘bigint‘)








以上是关于python面向对象高级编程的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段9——JS中的面向对象编程

Python 面向对象之高级编程

python 面向对象编程(高级篇)

python面向对象高级编程

python 之面向对象高级编程

Python面向对象高级编程