高羊茅草子主要产地在哪里

小说:高羊茅草子主要产地在哪里作者:乙道更新时间:2019-04-26字数:45928

前言

在上一篇文章【python进阶】详解元类及其应用1中,我们提到了关于元类的一些前置知识,介绍了类对象,动态创建类,使用type创建类,这一节我们将继续接着上文来讲~~~

5.使⽤type创建带有⽅法的类

最终你会希望为你的类增加⽅法。只需要定义⼀个有着恰当签名的函数并将 其作为属性赋值就可以了。
添加实例⽅法

In [14]: def echo_bar(self):#定义了一个普通的函数
    ...:     print(self.bar)
    ...:

In [15]: FooChild = type("FooChild",(Foo,),{"echo_bar":echo_bar})

In [16]: hasattr(Foo,"echo_bar")#判断Foo类中,是否有echo_bar这个属性
Out[16]: False

In [17]: hasattr(FooChild,"echo_bar")#判断FooChild类中,是否有echo_bar这个属性
Out[17]: True

In [18]: my_foo=FooChild()
    ...:

In [19]: my_foo.echo_bar()
True

添加静态⽅法

In [20]: @staticmethod
    ...: def testStatic():
    ...:     print("static method ....")
    ...:

In [21]: Foochild=type("Foochild",(Foo,),{"echo_bar":echo_bar,"testStatic":testStatic})

In [22]: fooclid=Foochild()

In [23]: fooclid.testStatic
Out[23]: <function __main__.testStatic>

In [24]: fooclid.testStatic()
static method ....

In [25]: fooclid.echo_bar()
True

添加类⽅法

In [26]: @classmethod
    ...: def testClass(cls):
    ...:     print(cls.bar)
    ...:

In [27]: Foochild=type("Foochild",(Foo,),{"echo_bar":echo_bar,"testStatic":testStatic,"testClass":testClass})

In [28]: fooclid = Foochild()

In [29]: fooclid.testClass()
True

你可以看到,在Python中,类也是对象,你可以动态的创建类。这就是当你 使⽤关键字class时Python在幕后做的事情,⽽这就是通过元类来实现的。

6.到底什么是元类(终于到主题了)

元类就是⽤来创建类的“东⻄”。你创建类就是为了创建类的实例对象,不是吗?但是我们已经学习到了Python中的类也是对象。
元类就是⽤来创建这些类(对象)的,元类就是类的类,你可以这样理解为:

MyClass = MetaClass()#使⽤元类创建出⼀个对象,这个对象称为“类” 
MyObject = MyClass()#使⽤“类”来创建出实例对象

你已经看到了type可以让你像这样做:

MyClass=type("MyClass",(),{})

这是因为函数type实际上是⼀个元类。type就是Python在背后⽤来创建所有类的元类。现在你想知道那为什么type会全部采⽤⼩写形式⽽不是Type呢? 好吧,我猜这是为了和str保持⼀致性,str是⽤来创建字符串对象的类,⽽int 是⽤来创建整数对象的类。type就是创建类对象的类。你可以通过检查 __class__属性来看到这⼀点。Python中所有的东⻄,注意,我是指所有的东 ⻄——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象, ⽽且它们都是从⼀个类创建⽽来,这个类就是type。

In [30]: age = 35

In [31]: age.__class__
Out[31]: int

In [32]: name = "bob"

In [33]: name.__class__
Out[33]: str

In [34]: def foo():
    ...:     pass
    ...:

In [35]: foo.__class__
Out[35]: function

In [36]: class Bar(object):
    ...:     pass
    ...:

In [37]: b = Bar()

In [38]: b.__class__
Out[38]: __main__.Bar

现在,对于任何⼀个__class__的__class__属性⼜是什么呢?

In [40]: name.__class__.__class__
Out[40]: type

In [41]: age.__class__.__class__
Out[41]: type

In [42]: foo.__class__.__class__
Out[42]: type

In [43]: b.__class__.__class__
Out[43]: type

因此,元类就是创建类这种对象的东⻄。type就是Python的内建元类,当然 了,你也可以创建⾃⼰的元类。

7.__metaclass__属性

你可以在定义⼀个类的时候为其添加__metaclass__属性。

class Foo(object):
      __metaclass__ = something...
      ...省略...

如果你这么做了,Python就会⽤元类来创建类Foo。⼩⼼点,这⾥⾯有些技 巧。你⾸先写下class Foo(object),但是类Foo还没有在内存中创建。Python 会在类的定义中寻找__metaclass__属性,如果找到了,Python就会⽤它来创建类Foo,如果没有找到,就会⽤内建的type来创建这个类。把下⾯这段话反复读⼏次。当你写如下代码时 :

In [44]: class Foo(Bar):
    ...:     pass
    ...:

Python做了如下的操作:

  1. Foo中有__metaclass__这个属性吗?如果是,Python会通过 __metaclass__创建⼀个名字为Foo的类(对象) 
  2. 如果Python没有找到__metaclass__,它会继续在Bar(⽗类)中寻找 __metaclass__属性,并尝试做和前⾯同样的操作。
  3. 如果Python在任何⽗类中都找不到__metaclass__,它就会在模块层次 中去寻找__metaclass__,并尝试做同样的操作。

  4. 如果还是找不到__metaclass__,Python就会⽤内置的type来创建这个类对象。

现在的问题就是,你可以在__metaclass__中放置些什么代码呢?答案就 是:可以创建⼀个类的东⻄。那么什么可以⽤来创建⼀个类呢?type,或者任何使⽤到type或者⼦类化type的东东都可以。

8.⾃定义元类

元类的主要⽬的就是为了当创建类时能够⾃动地改变类。通常,你会为API做 这样的事情,你希望可以创建符合当前上下⽂的类。
假想⼀个很傻的例⼦,你决定在你的模块⾥所有的类的属性都应该是⼤写形 式。有好⼏种⽅法可以办到,但其中⼀种就是通过在模块级别设定 __metaclass__。采⽤这种⽅法,这个模块中的所有类都会通过这个元类来创建,我们只需要告诉元类把所有的属性都改成⼤写形式就万事⼤吉了。
幸运的是,__metaclass__实际上可以被任意调⽤,它并不需要是⼀个正式的类。所以,我们这⾥就先以⼀个简单的函数作为例⼦开始。

python3中

#-*-coding:utf-8-*-
def upper_attr(future_class_name,future_class_parents,future_class_attr):

    #遍历属性字典,把不是__开头的属性名字变为⼤写
    newAttr = {}
    for name,value in future_class_attr.items():
        if not name.startswith("__"):
            newAttr[name.upper()] = value

    #调⽤type来创建⼀个类
    return type(future_class_name,future_class_parents,newAttr)

class Foo(object,metaclass=upper_attr):
    bar = "bip"

print(hasattr(Foo,"bar"))
print(hasattr(Foo,"BAR"))
f = Foo()
print(f.BAR)

现在让我们再做⼀次,这⼀次⽤⼀个真正的class来当做元类。

#-*-coding:utf-8-*-
class UpperAttrMetaClass(type):

    #__new__是在__init__之前被调⽤的特殊⽅法
    #__new__是⽤来创建对象并返回之的⽅法
    #⽽__init__只是⽤来将传⼊的参数初始化给对象
    #你很少⽤到__new__,除⾮你希望能够控制对象的创建
    #这⾥,创建的对象是类,我们希望能够⾃定义它,所以我们这⾥改写__new__
    #如果你希望的话,你也可以在__init__中做些事情
    #还有⼀些⾼级的⽤法会涉及到改写__call__特殊⽅法,但是我们这⾥不⽤
    def __new__(cls,future_class_name,future_class_parents,future_class_attr):
        #遍历属性字典,把不是__开头的属性名字变为⼤写
        newAttr = {}
        for name,value in future_class_attr.items():
            if not name.startswith("__"):
                newAttr[name.upper()] = value

        #⽅法1:通过"type"来做类对象的创建
        #return type(future_class_name,future_class_parents,newAttr)
        
        #⽅法2:复⽤type.__new__⽅法
        #这就是基本的OOP编程,没什么魔法
        #return    type.__new__(cls,future_class_name,future_class_parents,future_class_attr)

        #⽅法3:使⽤super⽅法
        return super(UpperAttrMetaClass,cls).__new__(cls,future_class_name,future_class_parents,future_class_attr)

#python2的⽤法 
#class Foo(object):
#    __metaclass__ = upper_attr#设置Foo类的元类为upper_attr
#    bar = "bip"

#python3的⽤法
class Foo(object,metaclass=upper_attr):
    bar = "bip"

print(hasattr(Foo,"bar")) 
#输出:False 
print(hasattr(Foo,"BAR")) 
#输出:True
f = Foo()
print(f.BAR)
#输出:"bip"

就是这样,除此之外,关于元类真的没有别的可说的了。但就元类本身⽽ ⾔,它们其实是很简单的:

  1. 拦截类的创建 
  2. 修改类 
  3. 返回修改之后的类

究竟为什么要使⽤元类?

现在回到我们的⼤主题上来,究竟是为什么你会去使⽤这样⼀种容易出错且晦涩的特性?好吧,⼀般来说,你根本就⽤不上它:
“元类就是深度的魔法,99%的⽤户应该根本不必为此操⼼。如果你想搞清楚 究竟是否需要⽤到元类,那么你就不需要它。那些实际⽤到元类的⼈都⾮常 清楚地知道他们需要做什么,⽽且根本不需要解释为什么要⽤元类。” —— Python界的领袖 Tim Peters

 

当前文章:http://www.cnsdbtzg.com/yn549.html

发布时间:2019-04-26 04:28:11

八宝景天多少钱一棵? 长度300公分的木香苗哪里有批发的? 【多图】棣棠基地实拍图片 红梅适合南方种吗? 福建有种植黄玉兰的基地吗? 草皮早熟禾耐阴吗? 白三叶休眠期是什么时候? 秋英,格桑花,波斯菊的区别有哪些? 哪里有卖牧草巴西玉米? 籽粒苋种子哪有货?

31055 46428 43811 74139 72056 90243 40243 72110 70184 34903 15768 85429 41436 18409 37760 89401 90787 15231 96292 40526 71817 89020 31579

我要说两句: (0人参与)

发布