Python基础入门笔记:面向对象

2018-09-2010:16:11后端程序开发Comments1,798 views字数 10122阅读模式

面向对象

Python 对属性的访问控制是靠程序员自觉的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

我们也可以把方法看成是类的属性的,那么方法的访问控制也是跟属性是一样的,也是没有实质上的私有方法。一切都是靠程序员自觉遵守 Python 的编程规范。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.1 类

3.1.1 方法的装饰器

  • @classmethod:调用的时候直接使用类名类调用,而不是某个对象
  • @property:可以像访问属性一样调用方法
class UserInfo:

    ...

    @classmethod
    def get_name(cls):
        return cls.lv

    @property
    def get_age(self):
        return self._age

    if __name__ == '__main__':   
        ...

        # 直接使用类名类调用,而不是某个对象
        print(UserInfo.lv)
        # 像访问属性一样调用方法(注意看get_age是没有括号的)
        print(userInfo.get_age)
复制代码

3.1.2 继承

语法格式:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class ClassName(BaseClassName):
    <statement-1>
    .
    .
    .
    <statement-N>
复制代码

当然上面的是单继承,Python 也是支持多继承的(注意: Java 是单继承、多实现),具体的语法如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class ClassName(Base1,Base2,Base3):
    <statement-1>
    .
    .
    .
    <statement-N>
复制代码

多继承有一点需要注意的:若是父类中有相同的方法名,而在子类使用时未指定,Python 在圆括号中父类的顺序,从左至右搜索 , 即方法在子类中未找到时,从左到右查找父类中是否包含方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

继承的子类的好处:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

  • 会继承父类的属性和方法
  • 可以自己定义,覆盖父类的属性和方法

3.1.3 多态

看个例子就好了:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class User(object):
    def __init__(self, name):
        self.name = name

    def printUser(self):
        print('Hello !' + self.name)

class UserVip(User):
    def printUser(self):
        print('Hello ! 尊敬的Vip用户:' + self.name)

class UserGeneral(User):
    def printUser(self):
        print('Hello ! 尊敬的用户:' + self.name)

def printUserInfo(user):
    user.printUser()

if __name__ == '__main__':
    userVip = UserVip('大金主')
    printUserInfo(userVip)
    userGeneral = UserGeneral('水货')
    printUserInfo(userGeneral)
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Hello ! 尊敬的Vip用户:大金主
Hello ! 尊敬的用户:水货
复制代码

可以看到,userVip 和 userGeneral 是两个不同的对象,对它们调用 printUserInfo 方法,它们会自动调用实际类型的 printUser 方法,作出不同的响应。这就是多态的魅力。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

PS:有了继承,才有了多态,也会有不同类的对象对同一消息会作出不同的相应。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.1.4 Python中的魔法方法

在 Python 中,所有以 "**" 双下划线包起来的方法,都统称为"魔术方法"。比如我们接触最多的 init__ 。魔术方法有什么作用呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

使用这些魔术方法,我们可以构造出优美的代码,将复杂的逻辑封装成简单的方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

我们可以使用 Python 内置的方法 dir() 来列出类中所有的魔术方法。示例如下:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class User(object):
    pass


if __name__ == '__main__':
    print(dir(User()))
复制代码

输出的结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Python基础入门笔记:面向对象

可以看到,一个类的魔术方法还是挺多的,截图没有截全。不过我们只需要了解一些常见和常用的魔术方法就好了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

1、属性的访问控制文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Python 没有真正意义上的私有属性。然后这就导致了对 Python 类的封装性比较差。我们有时候会希望 Python 能够定义私有属性,然后提供公共可访问的 get 方法和 set 方法。Python 其实可以通过魔术方法来实现封装。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

方法说明
__getattr__(self, name)该方法定义了你试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向,或者对一些废弃的属性进行警告。
__setattr__(self, name, value)定义了对属性进行赋值和修改操作时的行为。不管对象的某个属性是否存在,都允许为该属性进行赋值。有一点需要注意,实现 __setattr__ 时要避免"无限递归"的错误
__delattr__(self, name)__delattr____setattr__ 很像,只是它定义的是你删除属性时的行为。实现 __delattr__ 是同时要避免"无限递归"的错误
__getattribute__(self, name)__getattribute__ 定义了你的属性被访问时的行为,相比较,__getattr__ 只有该属性不存在时才会起作用。因此,在支持 __getattribute__的 Python 版本,调用__getattr__ 前必定会调用 __getattribute____getattribute__ 同样要避免"无限递归"的错误。

2、对象的描述器文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

一般来说,一个描述器是一个有“绑定行为”的对象属性 (object attribute),它的访问控制被描述器协议方法重写。这些方法是 __get__()__set__()__delete__()。有这些方法的对象叫做描述器。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

默认对属性的访问控制是从对象的字典里面 (__dict__) 中获取 (get) , 设置 (set) 和删除 (delete) 。举例来说, a.x 的查找顺序是 a.__dict__['x'],然后 type(a).__dict__['x'],然后找 type(a) 的父类 ( 不包括元类 (metaclass) )。如果查找到的值是一个描述器,Python 就会调用描述器的方法来重写默认的控制行为。这个重写发生在这个查找环节的哪里取决于定义了哪个描述器方法。注意,只有在新式类中时描述器才会起作用。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

至于新式类最大的特点就是所有类都继承自 type 或者 object 的类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在 Django 的 ORM 中,models.Model 中的 InterField 等字段,就是通过描述器来实现功能的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

看一个例子:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class User(object):
    def __init__(self, name='小明', sex='男'):
        self.sex = sex
        self.name = name

    def __get__(self, obj, objtype):
        print('获取 name 值')
        return self.name

    def __set__(self, obj, val):
        print('设置 name 值')
        self.name = val

class MyClass(object):
    x = User('小明', '男')
    y = 5

if __name__ == '__main__':
    m = MyClass()
    print(m.x)

    print('\n')

    m.x = '大明'
    print(m.x)

    print('\n')

    print(m.x)

    print('\n')

    print(m.y)
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

获取 name 值
小明


设置 name 值
获取 name 值
大明


获取 name 值
大明


5
复制代码

3、自定义容器(Container)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

我们知道在 Python 中,常见的容器类型有:dict、tuple、list、string。其中也提到过可容器和不可变容器的概念。其中 tuple、string 是不可变容器,dict、list 是可变容器。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

那么这里先提出一个问题,这些数据结构就够我们开发使用吗?不够的时候,或者说有些特殊的需求不能单单只使用这些基本的容器解决的时候,该怎么办呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

这个时候就需要自定义容器了,那么具体我们该怎么做呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

功能说明
自定义不可变容器类型需要定义 __len____getitem__方法
自定义可变类型容器在不可变容器类型的基础上增加定义 __setitem____delitem__
自定义的数据类型需要迭代需定义 __iter__
返回自定义容器的长度需实现 __len__(self)
自定义容器可以调用 self[key],如果 key 类型错误,抛出 TypeError,如果没法返回 key对应的数值时,该方法应该抛出 ValueError需要实现 __getitem__(self, key)
当执行 self[key] = value调用是 __setitem__(self, key, value)这个方法
当执行 del self[key] 方法其实调用的方法是 __delitem__(self, key)
当你想你的容器可以执行 for x in container: 或者使用 iter(container)需要实现 __iter__(self) ,该方法返回的是一个迭代器

还有很多魔术方法,比如运算符相关的模式方法,就不在该文展开了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.2 枚举类

3.2.1 什么是枚举

举例,直接看代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

from enum import Enum

Month = Enum('Month1', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# 遍历枚举类型
for name, member in Month.__members__.items():
    print(name, '---------', member, '----------', member.value)

# 直接引用一个常量
print('\n', Month.Jan)
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Jan --------- Month1.Jan ---------- 1
Feb --------- Month1.Feb ---------- 2
Mar --------- Month1.Mar ---------- 3
Apr --------- Month1.Apr ---------- 4
May --------- Month1.May ---------- 5
Jun --------- Month1.Jun ---------- 6
Jul --------- Month1.Jul ---------- 7
Aug --------- Month1.Aug ---------- 8
Sep --------- Month1.Sep ---------- 9
Oct --------- Month1.Oct ---------- 10
Nov --------- Month1.Nov ---------- 11
Dec --------- Month1.Dec ---------- 12

Month.Jan
复制代码

可见,我们可以直接使用 Enum 来定义一个枚举类。上面的代码,我们创建了一个有关月份的枚举类型 Month,这里要注意的是构造参数,第一个参数 Month 表示的是该枚举类的类名,第二个 tuple 参数,表示的是枚举类的值; 当然,枚举类通过 __members__ 遍历它的所有成员的方法。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

注意的一点是 , member.value 是自动赋给成员的 int 类型的常量,默认是从 1 开始的。而且 Enum 的成员均为单例(Singleton),并且不可实例化,不可更改。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.2.2 自定义枚举类型

有时候我们需要控制枚举的类型,那么我们可以 Enum 派生出自定义类来满足这种需要。修改上面的例子:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

from enum import Enum, unique

Enum('Month1', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))

# @unique 装饰器可以帮助我们检查保证没有重复值
@unique
class Month1(Enum):
    Jan = 'January'
    Feb = 'February'
    Mar = 'March'
    Apr = 'April'
    May = 'May'
    Jun = 'June'
    Jul = 'July'
    Aug = 'August'
    Sep = 'September '
    Oct = 'October'
    Nov = 'November'
    Dec = 'December'

if __name__ == '__main__':
    print(Month1.Jan, '----------',
          Month1.Jan.name, '----------', Month1.Jan.value)
    for name, member in Month1.__members__.items():
        print(name, '----------', member, '----------', member.value)
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Month1.Jan ---------- Jan ---------- January
Jan ---------- Month1.Jan ---------- January
Feb ---------- Month1.Feb ---------- February
Mar ---------- Month1.Mar ---------- March
Apr ---------- Month1.Apr ---------- April
May ---------- Month1.May ---------- May
Jun ---------- Month1.Jun ---------- June
Jul ---------- Month1.Jul ---------- July
Aug ---------- Month1.Aug ---------- August
Sep ---------- Month1.Sep ---------- September 
Oct ---------- Month1.Oct ---------- October
Nov ---------- Month1.Nov ---------- November
Dec ---------- Month1.Dec ---------- December
复制代码

4.2.3 枚举类的比较

因为枚举成员不是有序的,所以它们只支持通过标识(identity) 和相等性 (equality) 进行比较。下面来看看 ==is 的使用:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

from enum import Enum

class User(Enum):
    Twowater = 98
    Liangdianshui = 30
    Tom = 12

Twowater = User.Twowater
Liangdianshui = User.Liangdianshui

print(Twowater == Liangdianshui, Twowater == User.Twowater)
print(Twowater is Liangdianshui, Twowater is User.Twowater)

try:
    print('\n'.join('  ' + s.name for s in sorted(User)))
except TypeError as err:
    print(' Error : {}'.format(err))
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

False True
False True
 Error : '<' not supported between instances of 'User' and 'User'
复制代码

可以看看最后的输出结果,报了个异常,那是因为大于和小于比较运算符引发 TypeError 异常。也就是 Enum 类的枚举是不支持大小运算符的比较的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

但是使用 IntEnum 类进行枚举,就支持比较功能。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

import enum

class User(enum.IntEnum):
    Twowater = 98
    Liangdianshui = 30
    Tom = 12
    
try:
    print('\n'.join(s.name for s in sorted(User)))
except TypeError as err:
    print(' Error : {}'.format(err))
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Tom
Liangdianshui
Twowater
复制代码

通过输出的结果可以看到,枚举类的成员通过其值得大小进行了排序。也就是说可以进行大小的比较。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.3 元类

3.3.1 Python 中类也是对象

在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在 Python 中这一点也是一样的。但是,Python 中的类有一点跟大多数的编程语言不同,在 Python 中,可以把类理解成也是一种对象。对的,这里没有写错,就是对象。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

因为只要使用关键字 class,Python 解释器在执行的时候就会创建一个对象。如:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class ObjectCreator(object):
    pass
复制代码

当程序运行这段代码的时候,就会在内存中创建一个对象,名字就是ObjectCreator。这个对象(类)自身拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.3.2 使用type()动态创建类

因为类也是对象,所以我们可以在程序运行的时候创建类。Python 是动态语言。动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。在之前,我们先了了解下 type() 函数。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class Hello(object):
    def hello(self, name='Py'):
        print('Hello,', name)
复制代码

然后再另外一个模块引用 hello 模块,输出相应信息。(其中 type() 函数的作用是可以查看一个类型和变量的类型。)文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

from com.strivebo.hello import Hello

h = Hello()
h.hello()

print(type(Hello))
print(type(h))
复制代码

输出信息:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Hello, Py
<class 'type'>
<class 'com.twowater.hello.Hello'>
复制代码

上面也提到过,type() 函数可以查看一个类型或变量的类型,Hello 是一个 class ,它的类型就是 type ,而 h 是一个实例,它的类型就是 com.strivebo.hello.Hello。前面的 com.strivebo 是我的包名,hello 模块在该包名下。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

在这里还要细想一下,上面的例子中,我们使用 type() 函数查看一个类型或者变量的类型。其中查看了一个 Hello class 的类型,打印的结果是: <class 'type'>。其实 type() 函数不仅可以返回一个对象的类型,也可以创建出新的类型。class 的定义是运行时动态创建的,而创建 class 的方法就是使用 type() 函数。比如我们可以通过 type() 函数创建出上面例子中的 Hello 类,具体看下面的代码:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

def printHello(self, name='Py'):
    # 定义一个打印 Hello 的函数
    print('Hello,', name)

# 创建一个 Hello 类
Hello = type('Hello', (object,), dict(hello=printHello))

# 实例化 Hello 类
h = Hello()
# 调用 Hello 类的方法
h.hello()
# 查看 Hello class 的类型
print(type(Hello))
# 查看实例 h 的类型
print(type(h))
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Hello, Py
<class 'type'>
<class '__main__.Hello'>
复制代码

在这里,需先了解下通过 type() 函数创建 class 对象的参数说明:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

  1. class 的名称,比如例子中的起名为 Hello
  2. 继承的父类集合,注意 Python 支持多重继承,如果只有一个父类,tuple 要使用单元素写法;例子中继承 object 类,因为是单元素的 tuple ,所以写成 (object,)
  3. class 的方法名称与函数绑定;例子中将函数 printHello 绑定在方法名 hello

具体的模式如下:type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

好了,了解完具体的参数使用之外,我们看看输出的结果,可以看到,通过 type() 函数创建的类和直接写 class 是完全一样的,因为 Python 解释器遇到 class 定义时,仅仅是扫描一下 class 定义的语法,然后调用 type() 函数创建出 class 的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.3.3 什么是元类

我们创建类的时候,大多数是为了创建类的实例对象。那么元类呢?元类就是用来创建类的。也可以换个理解方式就是:元类就是类的类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

通过上面 type() 函数的介绍,我们知道可以通过 type() 函数创建类:MyClass = type('MyClass', (), {})文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

实际上 type() 函数是一个元类。type() 就是 Python 在背后用来创建所有类的元类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

那么现在我们也可以猜到一下为什么 type() 函数是 type 而不是 Type呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

这可能是为了和 str 保持一致性,str 是用来创建字符串对象的类,而 int 是用来创建整数对象的类。type 就是创建类对象的类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

可以看到,上面的所有东西,也就是所有对象都是通过类来创建的,那么我们可能会好奇,__class____class__ 会是什么呢?换个说法就是,创建这些类的类是什么呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

print(age.__class__.__class__)
print(name.__class__.__class__)
print(fu.__class__.__class__)
print(mEat.__class__.__class__)
复制代码

输出结果:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
复制代码

可以看出,把他们类的类打印结果。发现打印出来的 class 都是 type 。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

一开始也提到了,元类就是类的类。也就是元类就是负责创建类的一种东西。你也可以理解为,元类就是负责生成类的。而 type 就是内建的元类。也就是 Python 自带的元类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.3.4 自定义元类

连接起来就是:先定义 metaclass,就可以创建类,最后创建实例。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

所以,metaclass 允许你创建类或者修改类。换句话说,你可以把类看成是 metaclass 创建出来的“实例”。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class MyObject(object):
    __metaclass__ = something…
[…]
复制代码

如果是这样写的话,Python 就会用元类来创建类 MyObject。当你写下 class MyObject(object),但是类对象 MyObject 还没有在内存中创建。Python 会在类的定义中寻找 __metaclass__ 属性,如果找到了,Python 就会用它来创建类 MyObject,如果没有找到,就会用内建的 type 函数来创建这个类。如果还不怎么理解,看下下面的流程图:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

Python基础入门笔记:面向对象

举个实例:文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

class Foo(Bar):
    pass
复制代码

它的流程是怎样的呢?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

首先判断 Foo 中是否有 __metaclass__ 这个属性?如果有,Python 会在内存中通过 __metaclass__ 创建一个名字为 Foo 的类对象(注意,这里是类对象)。如果 Python 没有找到__metaclass__ ,它会继续在 Bar(父类)中寻找__metaclass__ 属性,并尝试做和前面同样的操作。如果 Python在任何父类中都找不到 __metaclass__,它就会在模块层次中去寻找__metaclass__ ,并尝试做同样的操作。如果还是找不到__metaclass__ ,Python 就会用内置的 type 来创建这个类对象。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

其实 __metaclass__ 就是定义了 class 的行为。类似于 class 定义了 instance 的行为,metaclass 则定义了 class 的行为。可以说,class 是 metaclass 的 instance。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

现在,我们基本了解了 __metaclass__ 属性,但是,也没讲过如何使用这个属性,或者说这个属性可以放些什么?文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到 type 或者子类化 type 的东东都可以。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

3.4.5 元类的作用

元类的主要目的就是为了当创建类时能够自动地改变类。通常,你会为 API 做这样的事情,你希望可以创建符合当前上下文的类。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

假想一个很傻的例子,你决定在你的模块里所有的类的属性都应该是大写形式。有好几种方法可以办到,但其中一种就是通过在模块级别设定__metaclass__ 。采用这种方法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成大写形式就万事大吉了。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

总结:Python 中的一切都是对象,它们要么是类的实例,要么是元类的实例,除了 type。type 实际上是它自己的元类,在纯 Python 环境中这可不是你能够做到的,这是通过在实现层面耍一些小手段做到的。文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

作者:Jaybo文章源自菜鸟学院-https://www.cainiaoxueyuan.com/bc/5157.html

  • 本站内容整理自互联网,仅提供信息存储空间服务,以方便学习之用。如对文章、图片、字体等版权有疑问,请在下方留言,管理员看到后,将第一时间进行处理。
  • 转载请务必保留本文链接:https://www.cainiaoxueyuan.com/bc/5157.html

Comment

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定