metaclass,decorations

metaclass

在python2中可以对__metaclass__进行赋值来实现对你创造的类进行一些特殊的事情,比如你想规定限定你的类里方法名称全部要大写,真么奇怪的事情怎么做到?
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    """
      Return a class object, with the list of its attribute turned
      into uppercase.
    """

    # pick up any attribute that doesn't start with '__' and uppercase it
    uppercase_attr = {}
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

    # let `type` do the class creation
    return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr # this will affect all classes in the module

class Foo(): # global __metaclass__ won't work with "object" though
    # but we can define __metaclass__ here instead to affect only this class
    # and this will work with "object" children
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

最好还是在类里面给__metaclass__赋值,不然整个模块的类都带有这个特性

在python 3中这个神奇的变量被移除但是可以用另一种形式使用它
class Foo(object, metaclass=something, kwarg1=value1, kwarg2=value2):
    ...
对上面的例子在python3里重现就是如下代码
# the metaclass will automatically get passed the same argument
# that you usually pass to `type`
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    """
      Return a class object, with the list of its attribute turned
      into uppercase.
    """

    # pick up any attribute that doesn't start with '__' and uppercase it
    uppercase_attr = {}
    for name, val in future_class_attr.items():
        if not name.startswith('__'):
            uppercase_attr[name.upper()] = val
        else:
            uppercase_attr[name] = val

    # let `type` do the class creation
    return type(future_class_name, future_class_parents, uppercase_attr)

class Foo(metaclass=upper_attr): # global __metaclass__ won't work with "object" though
    bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

思考一下如何用类实现Meta?

这一切的一切的实现都基于type这个神奇的类,他不仅仅可以用来判别一个变量的类型,他还可以创建类,下面这两个创建类的方式其实是等价的

class Parent():
    pass

class MyClass(Parent):
	name = 'yang'

Eg_2 = type('MyClass',(Parent,),{'name':'yang'})

print(type(MyClass)) #<class 'type'>
print(type(Eg_2))	 #<class 'type'>

demo1 = MyClass()
demo2 = Eg_2()

print(type(demo1))	#<class '__main__.MyClass'>
print(type(demo2))	#<class '__main__.MyClass'>

这里另外举出可以带参数的例子,以及另一种改变继承子类创造过程的简便方法,顺带说一下None的理解

##########################################################################
import platform
print (platform.python_version())


class Meta(type):
    def __new__(cls,name,bases,attrs,**kwargs):
        print(name+"come into the Meta!")
        if kwargs:
            print(kwargs)
        return super().__new__(cls, name, bases, attrs)#这里不能加kwargs
        
class Demo(metaclass=Meta,private=True,key1=1,key2=2):
    pass
            


#########################################################################
#元模型太笨重,用下面的__init_subclass__方法来做点事吧~~~
class Hook:

    def __init_subclass__(cls, **kwargs):
        for k, v in kwargs.items():
            type.__setattr__(cls, k, v)


class A(Hook, name="satori", age=16):
    pass


print(A.name)  # satori
print(A.age)  # 16



# python None 类型理解
x=()
y=None
print(x is None)#false
print(y is None)#true
print(not x is None)#true x等于None,  False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()都会是true
print(not y is None)#false
print(not x)#true
print(not y)#true
print(x is not None)#true 





装饰器

非常方便~比如我有一个函数,我让这个函数执行前做不同的事情,并且通过不同的参数来控制,看下面的代码示例:
#假设这是我的一个打印消息的函数,并返回一个字符串
def recv():
	print("hello")
	
#最简洁的装饰器
def extend(func):
    def decorate():
        print("i will be printed before hello~")
        func()

    return decorate

decorate= extend(recv)
decorate()

python中有个语法糖可以让上面的代码变成这个样子,输出是等价的


#最简洁的装饰器
def extend(func):
    def decorate():
        print("i will be printed before hello~")
        func()

    return decorate
@extend
def recv():
	print("hello")
	
recv()

下面我的recv有参数有返回值怎么办


#最简洁的装饰器
def extend(func):
    def decorate(msg):
        print("i will be printed before hello~")
        return func(msg)
    return decorate
@extend
def recv(msg):
	print("hello")
	return msg
	
ret = recv("msg")
print(ret) #msg

传参更一般的形式你可以把msg替换成 *param,**kwargs 这种~
下面还有最后一种更复杂的情况,我想在语法糖里加参数来使我的装饰效果更灵活


#最简洁的装饰器
def extend(para):
    def decorate(func):
    	def real(msg):
        	print("i will be printed before hello~")
        	if para==2:
        		print("wow para:"+str(para))
        	elif para==1:
        		print("dodo para:"+str(para))
        	else
        		print("lalalallal~")
        	return func(msg)
        return real
    return decorate
    
@extend(2)
def recv(msg):
	print("hello")
	return msg
	
ret = recv("msg")
print(ret) #msg
###########################
i will be printed before hello~
wow para:2
hello
msg

把@extend后面的参数改成1就会有不一样的表现哦~
解释一下,上面的过程其实等价于

decorate = extend(2)
real = decorate(recv)	
ret = real("msg")
print(ret) #msg
###########################
i will be printed before hello~
wow para:2
hello
msg

最后,常常在最里面一层加上一个python自带的装饰器,来使装饰后函数名不变,而且最里面一层常常用wrapper来命名,我们的最终版本是这个样子

import functools


def extend(para):
    def decorate(func):
        @functools.wraps(func)
        def wrapper(msg):
            print("i will be printed before hello~")
            if para==2:
                print("wow para:"+str(para))
            elif para==1:
                print("dodo para:"+str(para))
            else:
                print("lalalallal~")
            return func(msg)
        return wrapper
    return decorate
    
@extend(2)
def recv(msg):
    print("hello")
    return msg

ret = recv("msg")
print(ret) #msg

#注释掉@functools.wraps(func)打印下面内容跟不注释有区别么~
print(recv.__name__)

猴子补丁

(一般情况不建议使用会弄乱代码,测试时可以用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值