zoukankan      html  css  js  c++  java
  • python元编程

    1. Meta Class的理解
      django:
      https://docs.djangoproject.com/en/dev/topics/db/models/#meta-options

    2. 元编程
      https://zhuanlan.zhihu.com/p/29849145
      https://zhuanlan.zhihu.com/p/40916705
      https://segmentfault.com/a/1190000023764901 # 非常好的文章

    3. 基础知识【new】【type】

    # 1.  __new__  方法可以用在下面二种情况
    
    # 1.1 继承不可变数据类型时需要用到
    class Inch(float):
        "Convert from inch to meter"
        def __new__(cls, arg=0.0):        # 注意这里的第一个参数
            return float.__new__(cls, arg*0.0254) # 变成传给float的第一个参数
    
    print(Inch(12))  
    # 0.3048
    
    # 1.1 补充 【__new__返回值】float.__new__,和 object.__new__,或者是源码的type.__new__ 返回的都是【类】
    class Foo(object):
        price = 50
    
        def __new__(cls, *agrs, **kwds):
            inst = object.__new__(cls, *agrs, **kwds)
            print(inst)                # <__main__.Foo object at 0x0000000002E229C8>
            return inst   # 【类】
    
        def how_much_of_book(self, n):
            print(self)       # <__main__.Foo object at 0x0000000002E229C8>
            return self.price * n
    
    foo = Foo()
    print(foo.how_much_of_book(8))
    
    
    
    # __new__参数 【参数:当前准备创建的类的对象,类的名字,类继承的父类集合,类的方法集合】
    # 1.2 用在元类(python2的例子)
    class MetaClass(type):
        def __new__(meta, name, bases, dct):     #【重点】【meta:类自己】,【name:真正的要实例化的类(Myclass)】,【bases:继承的基类(元祖类型,可以有多个,看另外一个例子)】,【dct:】
            print '-----------------------------------
            print "Allocating memory for class", name   # Myclass
            print meta                           # MetaClass
            print bases
            print dct
            return super(MetaClass, meta).__new__(meta, name, bases, dct)
    
        def __init__(cls, name, bases, dct):    #【重点】
            print '-----------------------------------'
            print "Initializing class", name         # Myclass
            print cls                         # Myclass
            print bases
            print dct
            super(MetaClass, cls).__init__(name, bases, dct)
    
    
    class Myclass(object):
        __metaclass__ = MetaClass
    
        def foo(self, param):
            print param
    
    
    p = Myclass()
    p.foo("hello")
    
    # -----------------------------------
    # Allocating memory for class Myclass
    # <class '__main__.MetaClass'>
    # (<type 'object'>,)
    # {'__module__': '__main__', 'foo': <function foo at 0x1007f6500>, '__metaclass__': <class '__main__.MetaClass'>}
    # -----------------------------------
    # Initializing class Myclass
    # <class '__main__.Myclass'>
    # (<type 'object'>,)
    # {'__module__': '__main__', 'foo': <function foo at 0x1007f6500>, '__metaclass__': <class '__main__.MetaClass'>}
    # hello
    
    
    
    # 2.  使用type函数可以创建【类】
    
    # 2.1 基础
    
    # 2.1.1 自动使用class关键字创建一个类
    class Student1(object):
        pass
    
    # 参数 【参数:类名称,继承的类,类的属性和方法】
    # 2.1.2 使用type函数手动创建一个类
    Student2 = type("Student2",(),{})
     
    s1 = Student1() #同样都可以创建实例
    s2 = Student2() #同样都可以创建实例
     
    print(type(Student1),type(Student2)) 
    print(type(s1),type(s2))
    
    #结果
    '''
    <class 'type'> <class 'type'>
    <class '__main__.Student1'> <class '__main__.Student2'>
    '''
    
    
    
    # 2.2 深入
    
    # 2.2.1.使用type创建带有属性的类,添加的属性是【类属性】,并不是实例属性
    Girl = type("Girl",(),{"country":"china","sex":"male"})
    
    # 2.2.2.使用type创建带有方法的类
    #python中方法有普通方法,类方法,静态方法。
    def speak(self): # 要带有参数self,因为类中方法默认带self参数。
        print("这是给类添加的普通方法")
     
    @classmethod
    def c_run(cls):
        print("这是给类添加的类方法")
     
    @staticmethod
    def s_eat():
        print("这是给类添加的静态方法")
     
    #创建类,给类添加静态方法,类方法,普通方法。跟添加类属性差不多.
    Boy = type("Boy",(),{"speak":speak,"c_run":c_run,"s_eat":s_eat,"sex":"female"})
    
    
    
    
    1. 进阶理解
    • 装饰器的核心思想,就是装饰【函数这个对象】、让函数自身代码不变的情况下、增添一些具有普适性的功能。
    • 元类的核心思想,就是捣鼓【类这个对象】、使你能对其有着最高程度的控制权。
    • 【重点】type是内置的元类,Mixture(type)是自定义的元类【所以参数要符合type类的格式】
    
    # 1. 引子
    
    # metaclass是类的模板,所以必须从`type`类型派生:
    class ListMetaclass(type):
        def __new__(cls, name, bases, attrs):
            attrs['add'] = lambda self, value: self.append(value)   #【巧妙:append是list的方法】
            return type.__new__(cls, name, bases, attrs)
    
    # 有了ListMetaclass,我们在定义类的时候还要指示使用ListMetaclass来定制类,传入关键字参数metaclass:
    class MyList(list, metaclass=ListMetaclass):
        pass
    
    # 当我们传入关键字参数metaclass时,魔术就生效了,它指示Python解释器在创建MyList时,要通过ListMetaclass.__new__()来创建,在此,我们可以修改类的定义,比如,加上新的方法,然后,返回修改后的定义。
    # 测试一下MyList是否可以调用add()方法,而普通的list没有add()方法:
    >>> L = MyList()
    >>> L.add(1)
    >> L
    [1]
    
    # 动态修改有什么意义?直接在MyList定义中写上add()方法不是更简单吗?正常情况下,确实应该直接写,通过metaclass修改纯属变态。但是,总会遇到需要通过metaclass修改类定义的。
    
    
    
    # 2. 需求
    '''
    什么叫做最高程度的控制权呢?一个比较简单的栗子就是实现如下需求:
    
    定义一个“人”(Person)类: 它有三个方法:吃饭、睡觉、续几秒
    定义 Person 的三个子类:  “小张”(Zhang)、“小王”(Wang)、“小江”(Jiang)
    定义“人”的子类“小红”(Hong), 要求他:
      吃饭像小张一样快
      睡觉像小王一样香
      续秒像小江一样熟练
    
    你会怎么去实现呢?
    如果再要求你把上面三个要求换一换顺序呢?
    '''
    class Person:
        def __init__(self):
            self.ability = 1
    
        def eat(self):
            print("Person Eat: ", self.ability)
    
        def sleep(self):
            print("Person Sleep: ", self.ability)
    
        def save_life(self):
            print("Person+ ", self.ability, " s")
    
    
    class Wang(Person):
        def eat(self):
            print("Wang Eat: ", self.ability * 2)
    
    class Zhang(Person):
        def sleep(self):
            print("Zhang Sleep: ", self.ability * 2)
    
    class Jiang(Person):
        def save_life(self):
            print("Jiang+ inf s")
    
    
    class Mixture(type):
        def __new__(mcs, *args, **kwargs):   #【重点】为什么是__new__,因为后面的class Hong(Wang, 是在__new__中传入函数的
            name, bases, attr = args[:3]     # class Hong(Wang, Zhang, Jiang, metaclass=Mixture):
            print(args)                      # ('Hong', (<class '__main__.Wang'>, <class '__main__.Zhang'>, <class '__main__.Jiang'>), {'__module__': '__main__', '__qualname__': 'Hong'})
            person1, person2, person3 = bases
    
            def eat(self):
                person1.eat(self)
    
            def sleep(self):
                person2.sleep(self)
    
            def save_life(self):
                person3.save_life(self)
    
            # 这种写法不好看
            # attr["eat"] = eat
            # attr["sleep"] = sleep
            # attr["save_life"] = save_life
    
            # print(locals().items())
            for key, value in locals().items():
                if str(value).find("function") >= 0:
                    attr[key] = value
    
            return type(name, bases, attr)    #【重点】type理解 ,对应后面的 【class Hong(Wang, Zhang, Jiang, metaclass=Mixture)】
    
    def test(person):
        person.eat()
        person.sleep()
        person.save_life()
    
    # 顺序1,带metaclass
    class Hong(Wang, Zhang, Jiang, metaclass=Mixture):
        pass
    print('*'*20)
    test(Hong())
    
    # 顺序2,带metaclass
    class Hong(Zhang, Wang, Jiang, metaclass=Mixture):
        pass
    print('*'*20)
    test(Hong())
    
    # 顺序1,不带
    class Hong(Wang, Zhang, Jiang):   # 继承,用最近的
        pass
    print('*'*20)
    test(Hong())
    
    # 顺序2,不带
    class Hong(Zhang, Wang, Jiang):  # 继承,用最近的
        pass
    print('*'*20)
    test(Hong())
    
    
    #结果
    '''
    ('Hong', (<class '__main__.Wang'>, <class '__main__.Zhang'>, <class '__main__.Jiang'>), {'__module__': '__main__', '__qualname__': 'Hong'})
    ********************
    Wang Eat:  2
    Zhang Sleep:  2
    Jiang+ inf s
    ('Hong', (<class '__main__.Zhang'>, <class '__main__.Wang'>, <class '__main__.Jiang'>), {'__module__': '__main__', '__qualname__': 'Hong'})
    ********************
    Person Eat:  1
    Person Sleep:  1
    Jiang+ inf s
    ********************
    Wang Eat:  2
    Zhang Sleep:  2
    Jiang+ inf s
    ********************
    Wang Eat:  2
    Zhang Sleep:  2
    Jiang+ inf s
    '''
    
    
    1. robot源码中
    
    # 1. 引子
    # 不用class Hong(Wang, Zhang, Jiang, metaclass=Mixture)中的metaclass=Mixture 参数
    # type 类创建对象方法1
    class SetterAwareType(type):    # 元类
        def __new__(cls, *args):
            print('in SetterAwareType __new__')
            return type.__new__(cls, *args)
    
        def __init__(cls,  *args):
            print('in SetterAwareType __init__')
            return type.__init__(cls, *args)   # TypeError: type.__init__() takes 1 or 3 arguments
    
    class ModelObject(SetterAwareType):
        def test(self):
            print('in ModelObject copy')
    
    a = ModelObject('name',(object,),{})
    a.test()
    
    
    # type 类创建对象方法2
    class SetterAwareType(type):    # 元类
        def __new__(cls, *args):
            print('in SetterAwareType __new__')
            return type.__new__(cls, 'name',(object,), {})  # 'name' 直接传入了
    
        def __init__(cls,  *args):
            print('in SetterAwareType __init__')
            return super(SetterAwareType, cls).__init__(cls,  *args)
            # return type.__init__(cls, *args)   # TypeError: type.__init__() takes 1 or 3 arguments
    
    
    class ModelObject(SetterAwareType):
        def test(self):
            print('in ModelObject copy')
    
    a = ModelObject()
    a.test()
    
    
    
    
    # 2. 源码
    def with_metaclass(meta, *bases):
        """Create a base class with a metaclass."""
        # This requires a bit of explanation: the basic idea is to make a
        # dummy metaclass for one level of class instantiation that replaces
        # itself with the actual metaclass.
        class metaclass(type):
            def __new__(cls, name, this_bases, d):
                return meta(name, bases, d)
        return type.__new__(metaclass, 'temporary_class', (), {})
    
    
    
    
    @py2to3
    class ModelObject(with_metaclass(SetterAwareType, object)):
        __slots__ = []
    
        def copy(self, **attributes):
            """Return shallow copy of this object.
    
            :param attributes: Attributes to be set for the returned copy
                automatically. For example, ``test.copy(name='New name')``.
    
            See also :meth:`deepcopy`. The difference between these two is the same
            as with the standard ``copy.copy`` and ``copy.deepcopy`` functions
            that these methods also use internally.
    
            New in Robot Framework 3.0.1.
            """
            copied = copy.copy(self)
            for name in attributes:
                setattr(copied, name, attributes[name])
            return copied
    
        def deepcopy(self, **attributes):
            """Return deep copy of this object.
    
            :param attributes: Attributes to be set for the returned copy
                automatically. For example, ``test.deepcopy(name='New name')``.
    
            See also :meth:`copy`. The difference between these two is the same
            as with the standard ``copy.copy`` and ``copy.deepcopy`` functions
            that these methods also use internally.
    
            New in Robot Framework 3.0.1.
            """
            copied = copy.deepcopy(self)
            for name in attributes:
                setattr(copied, name, attributes[name])
            return copied
    
        def __unicode__(self):
            return self.name
    
        def __repr__(self):
            return repr(str(self))
    
        def __setstate__(self, state):
            """Customize attribute updating when using the `copy` module.
    
            This may not be needed in the future if we fix the mess we have with
            different timeout types.
            """
            # We have __slots__ so state is always a two-tuple.
            # Refer to: https://www.python.org/dev/peps/pep-0307
            dictstate, slotstate = state
            if dictstate is not None:
                self.__dict__.update(dictstate)
            for name in slotstate:
                # If attribute is defined in __slots__ and overridden by @setter
                # (this is the case at least with 'timeout' of 'running.TestCase')
                # we must not set the "real" attribute value because that would run
                # the setter method and that would recreate the object when it
                # should not. With timeouts recreating object using the object
                # itself would also totally fail.
                setter_name = '_setter__' + name
                if setter_name not in slotstate:
                    setattr(self, name, slotstate[name])
    
    
  • 相关阅读:
    Android使用LocalSocket抓取数据
    求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}
    链表A和B的有序合并,合并过程不产生新的节点,合并后B消失
    Android中intent如何传递自定义数据类型
    字符串的排列组合问题
    android.net.LocalSocket
    [转]OWC生成柱图,线图,饼图
    利用C#对远程服务进行操作
    域备份&域还原
    ActiveReports for .NET 简单使用
  • 原文地址:https://www.cnblogs.com/amize/p/14599983.html
Copyright © 2011-2022 走看看