Python 元类,MethodType,枚举类

元类

简介

  1. 类也是对象,你可以在运行时动态的创建它们,就像其他任何对象一样;当你使用class关键字时,Python解释器自动创建这个对象
  2. 元类就是用来创建类的“东西”;元类就是类的类
  3. Python中所有的东西,注意,我是指所有的东西——都是对象。这包括整数、字符串、函数以及类;它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type

使用type()函数查看类型信息

class Person:
    def eat(self):
        print('eat')


p = Person()

print(type(Person))
print(type(p))
print(type(p.eat))

输出信息

<class 'type'>
<class '__main__.Person'>
<class 'method'>

动态创建类

def choose_class(name):
    if name == 'foo':
        class Foo:
            def print_info(self):
                print('Foo info')

        return Foo
    elif name == 'bar':
        class Bar:
            def print_info(self):
                print('Bar info')

        return Bar


MyClass = choose_class('foo')
MyClass().print_info()

输出信息

Foo info

使用type创建类

  1. type() 函数可以查看对象类型
  2. type() 还可以创建新的类型
class Base:
    pass


def normal_method(self):
    print('这是一个普通方法')


@classmethod
def class_method(cls):
    print('这是一个类方法')


@staticmethod
def static_method():
    print('这是一个静态方法')


# 第一个参数是字符串:类名
# 第二个参数是元组:继承关系
# 第三个参数是字典:属性和方法
Test = type('Test', (Base,),
            {'attr01': True, 'normal_method': normal_method, 'class_method': class_method,
             'static_method': static_method})

print(dir(Test))

==使用dir() 函数查看对象所有属性和方法==

输出信息

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'attr01', 'class_method', 'normal_method', 'static_method']

创建一个对象测试

test = Test()
print(test.attr01)
test.normal_method()
Test.class_method()
Test.static_method()

输出信息

True
这是一个普通方法
这是一个类方法
这是一个静态方法

metaclass

除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass 先定义metaclass,就可以创建类,最后创建实例。 metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”

使用函数当做元类
# 遍历属性字典,把不是__开头的属性名字变为大写
def upper_attr(name, bases, attrs):
    new_attrs = {}
    for key, value in attrs.items():
        if not key.startswith("__"):
            new_attrs[key.upper()] = value

    # 调用type来创建一个类
    return type(name, bases, new_attrs)


class Foo(metaclass=upper_attr):  # 使用metaclass
    bar = '属性描述'


f = Foo()
print(f.BAR)
print(dir(f))

输出信息

属性描述
['BAR', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
使用class来当做元类
class MyMetaClass(type):
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: print('修改后数据', (value + 1))
        return type.__new__(cls, name, bases, attrs)


class Foo(metaclass=MyMetaClass):
    pass


f = Foo()
f.add(1)
print(dir(f))
修改后数据 2
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'add']

动态添加方法MethodType

将方法绑定到对象上

给一个实例绑定的方法,对另一个实例是不起作用的

from types import MethodType


class Person:
    pass


def print_name(self):
    print('name:%s' % self.name)


p1 = Person()
p2 = Person()

p1.print_name = MethodType(print_name, p1)

p1.name = 'Tom'
p2.name = 'Jake'

p1.print_name() # name:Tom
# p2.print_name() # 异常报错AttributeError
将方法绑定在类上

为了给所有实例都绑定方法,可以给class绑定方法

from types import MethodType


class Person:
    pass


def print_name(self):
    print('name:%s' % self.name)


Person.print_name = print_name

p1 = Person()
p2 = Person()
p1.name = 'Tom'
p2.name = 'Jim'
p1.print_name()
p2.print_name()

输出信息

name:Tom
name:Jim
使用__slots__
  1. Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性
  2. 使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
class Person:
    __slots__ = ('name', 'age')


p = Person()
p.name = 'Tom'
p.age = 20
print(p.name, p.age)

# p.address = 'beijing' # AttributeError异常

输出信息

Tom 20

枚举类

  1. 定义枚举时,成员名称不允许重复
  2. 如果要限制定义枚举时,不能定义相同值的成员。可以使用装饰器@unique【要导入unique模块】

当我们需要定义常量时,一个办法是用大写变量通过整数来定义,例如月份:

JAN = 1
FEB = 2
MAR = 3
...
NOV = 11
DEC = 12

好处是简单,缺点是类型是int,并且仍然是变量。

最好的方法是定义一个枚举类:

from enum import Enum, unique


@unique
class Money(Enum):
    ONE = 1
    # ONE2 = 1 #unique不允许重复值
    TWO = 2
    FHREE = 3


print(Money.ONE.name)
print(Money.ONE.value)

输出信息:

ONE
1

遍历枚举类

from enum import Enum, unique


@unique
class Money(Enum):
    ONE = 1
    TWO = 2
    FHREE = 3
    FOUR = 4
    FIVE = 5
    SIX = 6


for item in Money:
    print(item)
    print(item.value)

输出信息:

Money.ONE
1
Money.TWO
2
Money.FHREE
3
Money.FOUR
4
Money.FIVE
5
Money.SIX
6
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值