如果您对Python:metaclass感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于Python:metaclass的详细内容,并且为您提供关于Flask之面向对象补充m
如果您对Python: metaclass感兴趣,那么本文将是一篇不错的选择,我们将为您详在本文中,您将会了解到关于Python: metaclass的详细内容,并且为您提供关于Flask之面向对象补充 metaclass 和with .... as 的用法、groovy – metaClass.methods和metaClass.metaMethods有什么区别?、Groovy 基础 ——MetaClass 详解、groovy——运行方式、基本语法、引入方式、metaClass的有价值信息。
本文目录一览:- Python: metaclass
- Flask之面向对象补充 metaclass 和with .... as 的用法
- groovy – metaClass.methods和metaClass.metaMethods有什么区别?
- Groovy 基础 ——MetaClass 详解
- groovy——运行方式、基本语法、引入方式、metaClass
Python: metaclass
http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
http://stackoverflow.com/questions/11948555/python-how-can-a-class-inherit-from-a-function
http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained
http://stackoverflow.com/questions/739654/understanding-python-decorators
Flask之面向对象补充 metaclass 和with .... as 的用法
创建类的两种方式
方式一
class Foo(object):#这里不指定metaclass时,默认metaclass=type
city=''北京''
def func(self,x):
return x+1
方式二
type()函数不仅可以查看数据的类型还可以创建类
Fool=type(''Fool'',(object,),{"city":"北京",''func'':lambda x:x+1},)
f=Fool()
oo=Fool.func(3)
print(f)
要创建一个class对象,type()
函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了元组的单元素写法;
- class的方法名称与函数绑定。
元类
元类就是创建类的类,我们知道在python中一切皆为对象. type也是一个元类,所有的类都直接和间接的是type类的实例对象. 我们又知道object是所有类的父类,同时object又是type类的实例对象,在这里是不是很晕.
在标准库中除了type是元类外,还有ABCMeta等,而Iterable这个类继承了object,同时是ABCMeta的实例对象,然而ABCMteta又继承了type类同时又是type类的实例对象
from collections import Iterable
print(Iterable.mro())
print(Iterable.__class__)
[<class ''collections.abc.Iterable''>, <class ''object''>] #父类是
<class ''abc.ABCMeta''> #元类是
一个类继承了type类,这个类就是元类
创建类的流程
class Mytype(type):
def __init__(self,*args,**kwargs): #1.程序刚启动的时候执行,因为程序启动的时候Foo类就创建了,既然创建了,那么Mytype下的__init__就执行了
print("创建类之前")
super(Mytype, self).__init__(*args,**kwargs)
print("创建类之后")
def __call__(cls, *args, **kwargs): #实例化的时候先执行mytype的call方法,为什么? 因为Foo是由Mytype创建的类也就是对象,加括号后,会执行Mytype类的__call__方法
print("call")
obj=cls.__new__(cls,*args,**kwargs)
print("__new__")
cls.__init__(obj,*args,**kwargs)
print("init")
return obj
class Foo(object,metaclass=Mytype): #当前类是由type类创建,metaclass可以指定当前类是由哪个type创建的
# __metaclsss__=type #python 2的写法
city=''北京''
def __init__(self,name):
self.name=name
def __new__(cls, *args, **kwargs):
return object.__new__(cls)
def func(self,x):
return x+1
f=Foo("小红")
执行步骤:
1.执行Mytype的__init__()方法
2.执行Mytype的__call__(),
3.然后执行Foo的__new__方法,
4.最后执行Foo的init方法
metaclass
metaclass用来指定当前类是由哪个类创建的
元类就是用来创建这些类(对象)的类,
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。
如果一个类没有指定metaclass,但是它的父类指定了metaclass,那么这个也是由metaclass指定的类创建的
在wtforms的源码中用到了metaclass的知识,如果想了解就去了解metaclass源码
应用:在wtfroms中第一次看到了metaclass这个属性.
class Form(with_metaclass(FormMeta, BaseForm)):
def with_metaclass(meta, base=object):
return meta("NewBase", (base,), {})
其实这里就相当于:
class FormMeta(type):
pass
class BaseForm:
pass
class NewBase(BaseForm,metaclass=FormMeta):
pass
class Form(NewBase):
pass
#FormMeta继承了type相当于元类
注意:
python原编程大师建议我们在实际生产中,不要定义元类.
面向对象中的with... as...
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭/线程中锁的自动获取和释放等。
如果一个对象能被with 说明这个对象所对应的类一定有__enter__和__exit__方法,
应用:这个在flask中的离线脚本中用到了.
还有我们的文件操作的时候, with open as f ,当时只记得说用这种方法,就不需要写.f.close() 了,其实我猜里边也是实现了 __enter__ 和__exit__方法.
class Test:
def __enter__(self):
print ("In __enter__()")
return "test_with"
def __exit__(self, type, value, trace):
print("In __exit__()")
def get_example():
print(''get_example'')
return Test() #调用类Test 生成对象
with get_example() as example:
print ("example:", example)
结果:
get_example
In __enter__()
example: test_with
In __exit__()
工作原理
- 紧跟with后面的语句执行后,返回对象中__enter__方法被调用,__enter__方法的返回值会赋给as 后边的变量,
- with后面的语句执行完后,会自动调用__exit__方法
关于__exit__详情参考https://www.ibm.com/developerworks/cn/opensource/os-cn-pythonwith/
groovy – metaClass.methods和metaClass.metaMethods有什么区别?
class Example { def realFoo() { "foo" } } Example.MetaClass.MetaFoo = { -> "foo" } def reals = Example.MetaClass.methods*.name.grep{it.contains("Foo")} def Metas = Example.MetaClass.MetaMethods*.name.grep{it.contains("Foo")} println "reals = $reals,Metas = $Metas"
我希望reals的输出= [realFoo],Metas = [MetaFoo],但实际上我得到的是reals = [realFoo,MetaFoo],Metas = [].
看起来新的元方法存储在方法中,而不是MetaMethods.那么,MetaClass.methods和MetaClass.MetaMethods有什么区别?
解决方法
这些在DefaultGroovyMethods类中定义.
根据您要实例化的对象类型,它主要是迭代器,如每个,收集,查找等.
对代码的这种修改显示了仅限元,仅“真实”和共享的方法:
class Example { def realFoo() { "foo" } } Example.MetaClass.MetaFoo = { -> "foo" } def reals = Example.MetaClass.methods.name.sort().unique() def Metas = Example.MetaClass.MetaMethods.name.sort().unique() def MetaOnly = Metas - reals def realOnly = reals - Metas def shared = reals.findAll { Metas.contains(it) } println """ MetaOnly = $MetaOnly realOnly = $realOnly shared = $shared """
结果:
MetaOnly = [addShutdownHook,any,asBoolean,asType,collect,dump,each,eachWithIndex,every,find,findAll,findindexOf,findindexValues,findLastIndexOf,findResult,getAt,getMetaPropertyValues,getProperties,grep,hasProperty,identity,inject,inspect,is,isCase,iterator,MetaClass,print,printf,println,putAt,respondsTo,sleep,split,sprintf,use,with] realOnly = [equals,getClass,getProperty,hashCode,MetaFoo,notify,notifyAll,realFoo,setProperty,wait] shared = [getMetaClass,invokeMethod,setMetaClass,toString]
所有MetaOnly和shared方法都在DefaultGroovyMethods中.所有“真正的”方法都在类本身上,或者在它的父类(在本例中为Object)上,加上一些直接与MetaClass相关的groovy事物来获取/设置MetaClass以及getProperty / setProperty和invokeMethod它允许您覆盖方法行为.
如果你想搜索所有方法以查看存在的内容,我会使用以下内容:
def allMethods = (Example.MetaClass.methods + Example.MetaClass.MetaMethods).name.sort().unique()
Groovy 基础 ——MetaClass 详解
一、拦截方法调用和参数获取
示例 1:
class MyClass{
def hello(){
''invoked hello directly''
}
def invokeMethod(String name, Object args){
return "unknown method $name(${args.join('', '')})"
}
}
def mine= new MyClass()
assert mine.hello() == ''invoked hello directly''
assert mine.foo("Mark", 19) == ''unknown method foo(Mark, 19)''
首先我们在 groovy 脚本中定义了一个 Myclass 对象,在 groovy 中任何的对象都是实现 GroovyObject 并且继承 GroovyObjectSupport 的,在 GroovyObject 的接口中,我们可以看到几个方法首先是 getMetaClass 方法和 setMetaClass 方法,metaClass 用来支持动态方法和动态参数的调用。另一组方法是 getProperty 和 setProperty 方法,这组方法是用来支持动态参数的设定与赋值的。最后还有一个 invokeMethod 方法,该方法则是用于调用动态方法的。在了解了上述概念后,我们可以理解为 MyClass 的 invokeMethod 方法覆盖了 GroovyObjectSupport 中对应的方法,所以调用未预先定义的 foo 方法就会进入 invokeMethod 的实现。而 hello 方法预先定义则照旧。
示例 2:
class MyClass implements GroovyInterceptable{
def hello(){
''invoked hello() directly''
}
def invokeMethod(String name, Object args){
"invoked method $name(${args.join('', '')})"
}
}
def mine = new MyClass()
assert mine.hello() == ''invoked method hello()''
assert mine.foo(''Mark'',19) == ''invoked method foo(Mark, 19)''
assert mine.&hello() == ''invoked hello() directly''
该例子和示例 1 的不同在于实现了一个 GroovyInterceptable 接口,仔细看下这个接口的描述,可知道实现该接口的类被调用方法时都是默认使用 invokeMethod 方法,而不管该方法时动态生成或时静态生成;第 2 点不同是如果要再此情况下调用原有定义号的方法,需要变通的使用 ''.&'' 操作符。
示例 3:
class MyClass{
def greeting = ''accessed greeting directly''
Object getProperty(String property){
"read from property $property"
}
void setProperty(String property, Object newVlaue){
throw new Exception("wrote to property $property")
}
}
def mine = new MyClass()
assert mine.greeting == ''read from property greeting''
try{
mine.greeting = ''hi''
}catch(e){
assert e.message == ''wrote to property greeting''
}
assert mine.@greeting == ''accessed greeting directly''
该示例描述了属性的获取特性,在示例 1 中已经描述设置和获取属性的方法时继承来的,这里不做赘述。默认的通过 Gpath (见 Gpath 具体概念) 来处理属性的值,都是通过调用 getProperty 和 SetProperty 来代劳的。同样的如果你真希望直接访问参数的值,可以变通的使用''.@'' 操作符来达成。
通过 Gpath 来获得属性值。无论该属性在类中是否有,都是不会出错的执行那 2 个方法。但是对于类中不存在的属性,忌使用 ''.@'' 操作符,会抛出 MissingFieldException。
示例 4:
class MyClass implements GroovyInterceptable{
def greeting = ''accessed greeting''
def id =''White: ''
Object getProperty(String property){
try{
return this.@id + //access field directly
''indirectly '' +
this.@"$property"
}catch(e){
return "no such property $property"
}
}
def hello(Object[] args){"invoked hello with (${args.join('', '')})"}
def id(){''Green: ''}
def invokeMethod(String name, Object args){
try{
return this.&id() + //call method directly
''indirectly '' +
this.&"$name"(args)
}catch(e){
return "no such method $name"
}
}
}
def mine = new MyClass()
assert mine.greeting == ''White: indirectly accessed greeting''
assert mine.farewell == ''no such property farewell''
assert mine.hello(1, ''b'', 3) == ''Green: indirectly invoked hello with (1, b, 3)''
assert mine.foo(''Mark'', 19) == ''no such method foo''
该示例是对示例 2,3 的一个合并,同时他告诉我们我们可以通过操作符 ''.@'' 或者 ''.&'' 后使用双引号中定义变量的方法来动态的获取参数或者动态的方法。
二、MetaClass (描述类的类)
示例 5:
public class MyMetaClass extends DelegatingMetaClass{
MyMetaClass(Class thisClass){
super(thisClass)
}
Object invokeMethod(Object object, String methodName, Object[] arguments){
"MyMetaClass: ${super.invokeMethod(object, methodName, arguments)}"
}
}
class A{
def bark(){''A: invoked bark()''}
def invokeMethod(String name, Object args){
"A: missing $name(${args.join('', '')})"
}
}
def amc = new MyMetaClass(A)
amc.initialize()
def a = new A()
a.metaClass = amc
assert a.bark() == ''MyMetaClass: A: invoked bark()''
Thread.start {
assert a.bark() == ''MyMetaClass: A: invoked bark()''
}
assert new A().bark() == ''A: invoked bark()''
assert a.bleet() == ''A: missing bleet()''
该示例的代码较长,主要的意思是我们可以通过任意 Groovy 对象中的 metaClass 属性来为改变该对象的方法调用的行为。Groovy 为我们提供了
DelegatingMetaClass 来让我们实现该功能。
具体的做法是:首先创建一个自定义的 MetaClass 类继承于 DelegatingMetaClass,同时实现构造方法,以及自定义的方法调用行为(以后的内容将介绍,我们不仅可以改变方法行为)。然后我们可以通过自己创建的 metaClass 子类来包装你想改变行为的目标类。此处为类 A。然后再创建目标类实例,对目标类中得 metaClass 属性进行设置。随后在该实例上的方法调用将会按照该实例的 metaClass 属性所对应的处理器,进行处理,该例中是再完成本身方法调用后在前面添加 MyMetaClass 字符串。
但是值得注意的是,1. 对于另外新创建的 A 实例,如果没有进行 metaClass 属性赋值将按照原方法定义执行;2. 动态定义的
方法不受 metaClass 方法行为改变的影响。见该示例的最后一行。3. 上述的特性在新线程内同样有效。
示例 6:
InvokerHelper.instance.metaRegistry.setMetaClass(A, amc)
该示例只是对示例 5 的补充,我们曾提到,我们可以通过为目标类实例设置 metaClass 属性来让 metaClass 的行为对该实例生效。但是如果要在类范围内生效的话,就需要通过上面的代码进行注册。这样注册过后,将对目标类的所有,任何时候创建的示例,都赋予 metaClass 的行为。
这个示例还有一点需要注意。试想这么一种情况,先创建了一个目标类实例,再用示例 6 的语句注册,再创建一个目标类的实例。metaClass 的行为将在哪个对象上生效呢。答案是两者都生效。这点非常关键。一旦进行了类范围 metaClass 注册,那对于已创建和新创建的对象都生效。
注:对于高版本的 groovy InvokerHelper 的 instance 不存在。可以直接调用 metaRegistry。
示例 7:
import org.codehaus.groovy.runtime.InvokerHelper;
public class MyMetaClass extends DelegatingMetaClass{
MyMetaClass(Class theClass){
super(theClass)
}
Object invokeConstructor(Object[] arguments){
[]
}
}
class A{}
def amc = new MyMetaClass(A)
amc.initialize()
InvokerHelper.metaRegistry.setMetaClass(A,amc)
def a = new A()
assert a.class == ArrayList
assert (a<<1<<2<<3).size() == 3
在之前的示例已经略有提过 metaClass 不仅可以改变预定义的方法行为。在该示例中就以改变构造行为为例。该 metaClass 将构造行为变成创建一个数组对象。随后的操作是一目了然的。
在此值得一提的是,invokeConstructor 方法时从 metaClass 的接口 MetaObjectProtocol 继承过来,其他的方法可能
是从不同的继承树而来的,所以可以参见 DelegatingMetaClass 中得方法签名。我们可以发现有很多 invokeXXX 和 getXXX 的方法,也就是说我们可以对这些 metaClass 行为做更改。主要的我们可以看到有 getProperty 方法 invokeConstructor 方法,当然我很兴奋的发现还有一个 invokeMissingMethod 方法,这个方法似乎就是对我们示例 5 中不能处理动态定义方法的 metaClass 行为的一个有用的补充了。
三、ExpandoMetaClass
下面这个示例内容较多,在给出例子之前,需要先澄清一些细节,你可能会想我们之前人为的为 groovyobject 设置 metaClass 来改变类实例的行为,那默认不设置情况下这个 metaClass 是什么呢? 其实无论是你设置或者没有设置 metaClass 它的 metaClass 都是 HandleMetaClass 类型的,但是区别在于,里面有一个 getAdaptee 方法返回的是 DelegatingMetaClass 中的 MetaClass 类型的 delegate 属性,默认情况下,这个 delegate 会事 MetaClassImpl 类型的,但是一旦你自己设置了目标类实例的 metaClass 属性那这个 delegate 属性就是你设置的了。我们下面要将的这个话题,也就是这一章的标题 ExpandoMetaClass(MetaClassImpl 的一个子类)正是又一个与 MetaClassImpl 以及自定义的 MetaClass 平行的 delegate 只是这个 delegate,支持动态创建方法等等的特性。接着我们先引入示例
示例 8:
class A{
String text
}
def a1= new A(text: ''aBCdefG'')
assert a1.metaClass.adaptee.class == MetaClassImpl
A.metaClass.inSameCase = {-> text.toUpperCase()}
//triggers conversion of MetaClass of A to ExpandoMetaClass
//then adds new instance method ''inUpperCase'' to class
//A.metaClass { }
//
def a2 = new A(text:''hiJKLmnOp'')
assert a2.metaClass.adaptee.class == ExpandoMetaClass
//MetaClass of A changed for instances created after conversion trigger only
assert a2.inSameCase() == ''HIJKLMNOP''
//new method not available
assert a1.metaClass.adaptee.class == MetaClassImpl
try{ println a1.inSameCase();}
catch(e){assert e in MissingMethodException}
A.metaClass.inLowerCase = {-> text.toLowerCase()}
assert a2.inLowerCase() == ''hijklmnop''
//replace the method definition with another
A.metaClass.inSameCase = {-> text.toLowerCase()}
assert a2.inSameCase() == ''hijklmnop''
//add static methods
A.metaClass.''static''.inSameCase = {it.toLowerCase()}
assert A.inSameCase(''qRStuVwXyz'') == ''qrstuvwxyz''
代码的前几行印证了,默认的 delegate (即 HandleMetaClass 中得 metaClass 属性) 是 MetaClassImpl。然后我们调用了
A.metaClass { } 方法(该方法位于 DefaultGroovyMethods 中)使得返回的 HandleMetaClass 中得 delegate 是
ExpandoMetaClass 类型的。这样我们就能够利用该类型的 metaClass 为我们做事了。同样的
A.metaClass.inSameCase = {-> text.toUpperCase ()} 方法只是在注册 metaClass 为 ExpandoMetaClass 的同时
为其动态添加一个实例方法。同时我们可以在最后几行的代码中获知,动态添加静态方法也是可行的。
几点需要注意的:1. 只有在切换 delegate 为 ExpandoMetaClass 后创建的目标对象才能支持切换时所提供的动态方法。2. 动态方法的添加存在覆盖关系。
示例 9:
class A{
}
A.metaClass.character = ''Cat in the Hat''
def a1 = new A()
assert a1.character == ''Cat in the Hat''
def ourProperties = Collections.synchronizedMap([:])
A.metaClass.setType = {String value -> ourProperties["${delegate}Type"] = value }
A.metaClass.getType = { -> ourProperties["${delegate}Type"]}
a1.type = ''Hatted Cat''
assert a1.type == ''Hatted Cat''
def a2 = new A()
A.metaClass.constructor = { -> new A()}
try{
a2 = new A()
}catch(Error e){
assert e in StackOverflowError
}
A.metaClass.constructor = {String s -> new A(character :s)}
a2 = new A("Thing One")
A.metaClass.''changeCharacterToThingTwo''= {-> delegate.character = ''Thing Two'' }
a2.character= ''Cat in the Hat''
a2.changeCharacterToThingTwo()
assert a2.character == ''Thing Two''
[''Hatted Cat'', ''Thing'', ''Boy'', ''Girl'', ''Mother''].each{p->
A.metaClass."changeTypeTo${p}"= {-> delegate.type= p}
}
a2.changeTypeToBoy()
assert a2.type == ''Boy''
a2.''changeTypeToHatted Cat''()
assert a2.type == ''Hatted Cat''
该示例的内容只要是示例 8 的一个补充,我们不仅可以动态添加方法,同时还可以动态添加属性和构造方法。
示例 10:
ExpandoMetaClass.enableGlobally()
//call ''enableGlobally'' method before adding to supplied class
List.metaClass.sizeDoubled = {-> delegate.size() * 2 }
//add method to an interface
def list = [] << 1 << 2
assert list.sizeDoubled() == 4
该示例比较简介,旨在告诉我们我们不仅可以对自定义的 groovy 对象进行属性方法等的动态添加,同样的我们可以对非自定义的 Groovy 提供的对象进行动态处理。处理方法和自定义对象的方法时完全一样的,唯一的区别在于,我们需要额外定义
ExpandoMetaClass.enableGlobally (),然而笔者发现笔者使用的 1.8.1 版的 groovy 如果去掉了该声明也是可以工作
所以请各位读者按照个人版本做尝试。
示例 11:
class Bird{
def name = ''Tweety''
def twirp(){ ''i taught i saw a puddy cat'' }
}
Bird.metaClass.invokeMethod = {name, args->
def metaMethod = Bird.metaClass.getMetaMethod(name, args)
metaMethod?metaMethod.invoke(delegate,args): ''no such method''
}
def a = new Bird()
assert a.twirp() == ''i taught i saw a puddy cat''
assert a.bleet() ==''no such method''
Bird.metaClass.getProperty = {name->
def metaProperty = Bird.metaClass.getMetaProperty(name)
metaProperty?metaProperty.getProperty(delegate): ''no such property''
}
def b = new Bird()
assert b.name == ''Tweety''
assert b.filling == ''no such property''
该示例主要说明的是我们不仅可以用 Expando 特性来添加方法属性和构造方法,同样的我们可以对已经存在的方法进行覆盖。最后还要强调一下 Bird.metaClass 返回的是 ExpandoMetaClass 我们这里覆盖的 getMetaMethod 和
getProperty 以及 invokeMethod 和 getProperty 方法都是对 ExpandoMetaClass 类和它父类对应的方法进行覆盖。
至此,Groovy 的 MetaClass 内容已经介绍完了。该部分内容在 groovy 中非常重要。谨此记录下来作为日后参考,同时希望对大家有帮助。
groovy——运行方式、基本语法、引入方式、metaClass
jvm运行groovy类有两种方式:
1.使用groovyc编译所有的*.groovy为java的*.class文件,把这些*.class文件放在java类路径中,通过java类加载器来加载这些类。
2.通过groovy的类加载器在运行时直接加载*.groovy文件并且生成对象,在这种方式下,没有生成任何*.class,但是生成了一个java.lang.Class对象的实例,也就是说,当groovy代码中包括一个new MyClass()的表达式时,并且也有一个MyClass.groovy的文件,这个文件将被解释,一个MyClass的类型将被产生并且增加到类加载器中,在代码中将像从*.class一样获取到MyClass对象。
没有生成.class文件也可以用生成class对象的实例?
没错,实际上只要有符合虚拟机规范的二进制字节流被解析成方法区的数据结构就可以生成class对象,具体可以看一下类的加载过程。
https://blog.csdn.net/iteye_7617/article/details/82474191
https://www.cnblogs.com/amosli/p/3970810.html
groovy基本语法:
https://www.cnblogs.com/amosli/p/3970810.html
引入方式:
https://www.jianshu.com/p/e8dec95c4326
1.GroovyClassLoader:运行时加载groovy代码,生成.class对象
GroovyClassLoader groovyClassLoader = new GroovyClassLoader();
String scriptText = "class Hello { void hello() { println ''hello'' } }";
//将Groovy脚本解析为Class对象
Class clazz = groovyClassLoader.parseClass(scriptText);
//Class clazz = groovyClassLoader.parseClass(new File("script.groovy"));
assertEquals(clazz.getName(),"Hello");
clazz.getMethod("hello").invoke(clazz.newInstance());
2.GroovyScriptEngine:运行时加载脚本,并监听脚本变化,当脚本发生变化时重新加载,这个厉害了啊
groovy.util.GroovyScriptEngine 类为 GroovyClassLoader 其上再增添一个能够处理脚本依赖及重新加载的功能层, GroovyScriptEngine可以从指定的位置(文件系统,URL,数据库,等等)加载Groovy脚本
可以使用一个CLASSPATH集合(url或者路径名称)初始化GroovyScriptEngine,之后便可以让它根据要求去执行这些路径中的Groovy脚本了.GroovyScriptEngine同样可以跟踪相互依赖的脚本,如果其中一个被依赖的脚本发生变更,则整个脚本树都会被重新编译和加载。
//script/groovy/hello.groovy
println "hello $name"
GroovyScriptEngine scriptEngine = new GroovyScriptEngine("script/groovy");
Binding binding = new Binding();
binding.setVariable("name", "groovy");
while (true){
scriptEngine.run("hello.groovy", binding);
TimeUnit.SECONDS.sleep(1);
}
3.GroovyShell:这种看起来不是很实用...
GroovyShell shell = new GroovyShell();
//可以绑定更多变量
shell.setVariable("age",22);
//直接求值
shell.evaluate("if(age < 18){''未成年''}else{''成年''}");
//解析为脚本,延迟执行或者缓存起来
Script script = shell.parse("if(age < 18){''未成年''}else{''成年''}");
assertEquals(script.run(), "成年");
//可以从更多位置加载/执行脚本
//shell.evaluate(new File("script.groovy"));
//shell.evaluate(new URI("http://wwww.a.com/script.groovy"));
还可以这样:
GroovyShell shell = new GroovyShell();
Script scrpt = shell.parse("script.groovy");
Binding binding = new Binding();
binding.setVariable("str1", "value1");
binding.setVariable("str2", "value2");
scrpt.setBinding(binding);
System.out.println(scrpt.evaluate("customConcat(str1, str2)"));
script.groovy:
def customConcat(def str1, def str2) {
str1.concat(str2)
}
4.Eval:这种是对GroovyShell的封装
Binding binding = new Binding();
GroovyShell shell = new GroovyShell(binding);
Script scrpt = shell.parse("script.groovy");
binding.setVariable("str1", "value1");
binding.setVariable("str2", "value2");
binding.setVariable("newConcat", scrpt);
System.out.println(scrpt.evaluate("newConcat.customConcat(str1, str2)"));
metaClass:
运行期添加静态方法和普通方法
https://blog.csdn.net/walkcode/article/details/24587457
groovy代码和class文件的对应关系:
https://blog.csdn.net/jiangqian6481/article/details/83717442
1.对于没有任何类定义
如果Groovy脚本文件里只有执行代码,没有定义任何类(class),则编译器会生成一个Script的子类,类名和脚本文件的文件名一样,而脚本的代码会被包含在一个名为run的方法中,同时还会生成一个main方法,作为整个脚本的入口。
2.对于仅有一个类
如果Groovy脚本文件里仅含有一个类,而这个类的名字又和脚本文件的名字一致,这种情况下就和Java是一样的,即生成与所定义的类一致的class文件, Groovy类都会实现groovy.lang.GroovyObject接口。
3.对于多个类
如果Groovy脚本文件含有一个或多个类,groovy编译器会很乐意地为每个类生成一个对应的class文件。如果想直接执行这个脚本,则脚本里的第一个类必须有一个static的main方法。
4.对于有定义类的脚本
如果Groovy脚本文件有执行代码, 并且有定义类, 那么所定义的类会生成对应的class文件, 同时, 脚本本身也会被编译成一个Script的子类,类名和脚本文件的文件名一样
如何使用groovyc 和 groovy:
https://blog.csdn.net/Leon1509/article/details/83681907
我们今天的关于Python: metaclass的分享已经告一段落,感谢您的关注,如果您想了解更多关于Flask之面向对象补充 metaclass 和with .... as 的用法、groovy – metaClass.methods和metaClass.metaMethods有什么区别?、Groovy 基础 ——MetaClass 详解、groovy——运行方式、基本语法、引入方式、metaClass的相关信息,请在本站查询。
本文标签: