精华内容
下载资源
问答
  • 许多PHP软件使用标准mail()函数 – 我无法改变,因为客户想要使用它,故事结束…… – 但我需要重写它,如在chroot()’环境中,它不可能产生一个sendmail进程 – 我需要套接字级通信,这不是标准SMTP或btw)>...

    是否可以编写PHP扩展(UNIX,CGI SAPI),我可以:

    >重新定义PHP函数的实现(比如使用mail():许多PHP软件使用标准的mail()函数 – 我无法改变,因为客户想要使用它,故事结束…… – 但我需要重写它,如在chroot()’环境中,它不可能产生一个sendmail进程 – 我需要套接字级通信,这不是标准的SMTP或btw)

    >在执行PHP脚本的实际解析/执行之前,“停止”PHP解释器(所以我可以为我的其他事做),但是在完成所有初始化工作(扩展加载,ini文件解析等)之后,让我们调用它“在PHP脚本执行钩子之前”左右:)

    >强制解析INI文件(路径由我生成/定义),它可以重新定义之前设置的所有设置(如果它完全是)

    目前我已经修改了PHP源代码本身,但这很丑陋,也许很危险,如果我可以将它作为PHP扩展来做,那就好了,好吧,至少看起来像PHP扩展:)所以我不喜欢需要修改“核心PHP”……

    非常感谢提前!

    解决方法:

    网上有很多Howto文章和参考资料,解释了基本的Hello World及其他内容.

    祝好运.

    罗马

    标签:php,unix,c-3,cgi,php-extension

    来源: https://codeday.me/bug/20190621/1252415.html

    展开全文
  • 一个php请求完整流程: 浏览器用户--->web服务器(apache,nginx)--->Zend引擎从文件系统读取php代码文件--->Zend解释器工作 --->执行解释后代码-->Zend引擎注册函数接口-->内置模块或者各个...

    希望本文能对那些想把php带向更宽的边界的工程师有所帮助.

    一个php请求的完整流程:
       
    浏览器用户--->web服务器(apache,nginx)--->Zend引擎从文件系统读取php代码文件--->Zend解释器工作
       
    --->执行解释后的代码-->Zend引擎注册的函数接口-->内置模块或者各个需要的外部模块扩展-->数据库memcache等后端资源
       
       其中 
       Zend引擎注册的函数接口:就是php开发者经常接触的各种php函数.
       外部模块扩展:就是php编译的各个so文件(linux)或者dll文件(windwos).
       执行解释后的代码:浏览器的内容就是从这里返回的.
       内置模块:也就是php每次启动的时候会携带启动的模块.

    从上面的流程图看php可以从3个点进行扩展.1 外部模块扩展 2 Zend引擎 3 内置模块,下面将一一讨论.
       
       外部模块扩展.
             如果你使用过dl()你就接触过这些外部的扩展模块.外部的扩展模块文件就放在你的硬盘里,他在php脚本运行时被加载到内存中,而且只有需要的时候才被加载.
       当此次的脚本运行完之后他就会被内存释放掉,总的来说它运行的慢但是不占资源.不需要重新编译一个php.
       
       内置模块
             虽然也是Zend引擎之外的模块,但是与外部模块扩展有些不同,他已经在php里边了.他会使得你编译的php体积变大,如果有改变,必须重新编译php才行.内置模块会使得
       php内存变大,但是调用起来也会更加的快速.在我们的测试中一些模块运行在内置模式会有30%以上的速度提升.
       
       Zend引擎
             首先,我绝对不建议你去修改Zend引擎.一些php语言的特性只要在Zend引擎中才能够实现.比如要修改数组关键字的名字,可以在这里实现.
       在下载的php源代码里,以zend开头的都是zend引擎的相关代码.
       

       外部模块扩展是下面要扩展的方式。

       下面以一个简单的模块为例子说明如何编写PHP外部模块扩展:
       
       首先编写php模块有自己的一套标准命名方式,你需要遵守,不然可能会导致你的模块无法释放变量或者其他的问题,这些标准包括 宏定义,变量声明等.你可以到官方浏览详细的说明.

     

    /* 扩展的标准头 */
    #include "php.h"
    /* 声明这个so被导出的函数 */
    ZEND_FUNCTION(helloworld_module);
    /* Zend引擎注册的函数接口 */
    zend_function_entry helloworldmod_interfaces[] =
    {
        ZEND_FE(helloworld_module, NULL)
        {NULL, NULL, NULL}
    };
    /* 这是这个模块的声明实体,它的值对模块编译的时候起实际作用 */
    zend_module_entry helloworldmod_module_entry =
    {
        STANDARD_MODULE_HEADER,
        "Hello world",
        helloworldmod_interfaces,
        NULL, 
        NULL, 
        NULL, 
        NULL, 
        NULL,
        NO_VERSION_YET,
        STANDARD_MODULE_PROPERTIES
    };
    
    /* 向zend引擎声明一个备案,可以说明 helloworldmod_module_entry属于helloworldmod.so这个动态库*/
    #if COMPILE_DL_helloworld_module
    ZEND_GET_MODULE(helloworldmod)
    #endif
    
    /* 这就是我们新增的函数的真正代码 */
    ZEND_FUNCTION(helloworld_module)
    {
        return "Hello,world";
    }
    

       一般php源码目录结构类似下面:
       main php的主要源代码,
       ext php的扩展 
       sapi 与不同服务器的api交互层代码
       zend zend引擎部分
       TSRM 线程安全相关模块代码

     

      我们编写的模块需要放在ext目录下面,可以根据其他扩展的config.m4文件来修改成我们的必要编译配置信息。这里这个模块几乎是一个空的config.m4文件就行,
       
       然后利用phpize来生成configure文件然后是 ./configure && make && make install执行就能编译一份的动态库

      编写测试test.php

    <?php
    
    echo helloworld_module();
    ?>      
    

         输出:
          "Hello,world"

     

       切入PHP调用linux底层的过程

    在linux下面一个很给力的工具是LD_PRELOAD环境变量。
       
    LD_PRELOAD环境变量是编译器找到程序中所引用的函数或全局变量所存在的位置的一个过滤器,比如,在php的c代码里调用一个开始网络连接的方法connect,事实上就是通过动态链接
       
    去寻找linux的c库的函数connect,这些链接文件一般放在lib下面,这也就为影响php的代码执行提供了一个切入点。因为php程序在动态载入lib下面的函数connect之前会检查

    LD_PRELOAD提供的动态库里有没有这个connect函数,可以在这里对php的行为进行干涉。

       
       下面以一个简单的过滤网络访问的例子说明如何实现:
       
       先是一个准备作为LD_PRELOAD环境变量的值的so文件的代码。
       lp_demo.c

    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <dlfcn.h>
    
    
    //定义我们自己的connect函数
    int  connect(int  sockfd,  const  struct sockaddr *serv_addr, socklen_t
                 addrlen){
      static int (*connect_linuxc)(int, const  struct sockaddr*, socklen_t)=NULL;
      unsigned char *ip_char;
     
      //利用 lsym的RTLD_NEXT选项绕过LD_PRELOAD环境变量的connect方法找到c库的函数
      if (!connect_linuxc) connect_linuxc=dlsym(RTLD_NEXT,"connect");
     
        ip_char=serv_addr->sa_data;
        ip_char+=2;
     
        
         //192.168.2.3 找到了
        if ((*ip_char==192)&&(*(ip_char+1)==168)&&(*(ip_char+2)==2)&&(*(ip_char+3)==3)) {
        
             //简单返回一个权限错误的代码
                return EACCES;
        }
     
      
      // 调用真正的connect方法
       return connect_linuxc(sockfd,serv_addr,addrlen);
      
    }
    

      编译成so文件


    $ gcc -o lp_demo.so -shared lp_demo.c -ldl

    测试文件 test.php

    <?php
    file_get_contents("http://192.168.2.3/");
    ?>
    

      使用方法
    LD_PRELOAD=lp_demo.so php test.php


    这样他将不可能访问的到192.168.2.3这种我们内部的网址。起到一个很好的沙盒作用。

    除此之外我们还可以利用fwrite fopen等函数将php对文件系统的读写操作转移到mencache,nosql之类的后端资源当中。

    PS:在c库下面,还有一堆sys_开头的函数,它们才是内核空间里的真正的函数。

    转载于:https://www.cnblogs.com/NoSql/p/3223375.html

    展开全文
  • 如何用python编写collectdplugin

    千次阅读 2016-02-15 22:04:20
    collect的python plugin内嵌了一个python的解释器,可以方便我们用python自定义collectd的plugin,各个callback的函数定义可以参考collectd python plugin。比如自定义一个统计cpu利用率的plugin:

    collect的python plugin内嵌了一个python的解释器,可以方便我们用python自定义collectd的plugin,各个callback的函数定义可以参考collectd python plugin。比如自定义一个统计cpu利用率的plugin:

    cpu_usage_plugin.py

    #!/usr/bin/env python
    
    import subprocess
    import traceback
    
    
    def get_cpu_usage():
        cmd = "grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage}'"
        result = run(cmd)
        for line in result:
            try:
                usage = float(line)
                return usage
            except:
                raise Exception("Failed to parse cpu usage")
    
    
    def run(cmd):
        try:
            result = []
            proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, close_fds=True)
            (stdout, stderr) = proc.communicate()
            output = stdout.split("\n")
            for line in output:
                if line == '':
                    continue
                result.append(line)
            return result
        except Exception as err:
            raise Exception("failed to execute command: %s, reason: %s" % (' '.join(cmd), err.message))
    
    
    class CPUStatMon(object):
        def __init__(self):
            self.plugin_name = "cpu_stat"
            self.interval = 30
            self.hostname = None
            self.verbose_logging = False
    
        def log_verbose(self, msg):
            if not self.verbose_logging:
                return
            collectd.info('%s plugin [verbose]: %s' % (self.plugin_name, msg))
    
        '''
        to store/initialize the internal state like a socket connection
        def init(self):
            self.SOCKET_CONN = create_sockect_conn()
        '''
    
        def configure_callback(self, conf):
            for node in conf.children:
                val = str(node.values[0])
                if node.key == "HostName":
                    self.hostname = val
                elif node.key == 'Interval':
                    self.interval = int(float(val))
                elif node.key == 'Verbose':
                    self.verbose_logging = val in ['True', 'true']
                elif node.key == 'PluginName':
                    self.plugin_name = val
                else:
                    collectd.warning('[plugin] %s: unknown config key: %s' % (self.plugin_name, node.key))
    
        def dispatch_value(self, plugin, host, type, type_instance, value):
            self.log_verbose("Dispatching value plugin=%s, host=%s, type=%s, type_instance=%s, value=%s" %
                             (plugin, host, type, type_instance, str(value)))
            val = collectd.Values(type=type)
            val.plugin = plugin
            val.host = host
            val.type_instance = type_instance
            val.interval = self.interval
            val.values = [value]
            val.dispatch()
            self.log_verbose("Dispatched value plugin=%s, host=%s, type=%s, type_instance=%s, value=%s" %
                             (plugin, host, type, type_instance, str(value)))
    
        def read_callback(self):
            try:
                usage = get_cpu_usage()
                type = 'cpu_usage_percent'
                type_instance = "used"
                value = usage
                self.dispatch_value(self.plugin_name, self.hostname, type, type_instance, value)
    
            except Exception as exp:
                self.log_verbose(traceback.print_exc())
                self.log_verbose("plugin %s run into exception" % (self.plugin_name))
                self.log_verbose(exp.message)
    
    
    if __name__ == '__main__':
        result = get_cpu_usage()
        print result
    
    else:
        import collectd
        cpu_status_mon = CPUStatMon()
        collectd.register_config(cpu_status_mon.configure_callback)
        '''
        # register the init function
        collectd.register_init(cpu_status_mon.init)
        '''
        collectd.register_read(cpu_status_mon.read_callback)
    


    collectd.conf中enable python plugin并增加如下配置:

    <Plugin python>
        ModulePath "/opt/collectd/lib/collectd"
        Import "cpu_usage_plugin"
        <Module cpu_usage_plugin>
            Interval 30
            PluginName "cpu_usage"
            HostName "demo_host"
            Verbose false
        </Module>
    </Plugin>

    值得注意的是:

    • 对于dispatch_value函数中type参数的值,可以直接传入字符串gauge,derived,count等collectd的内建数据类型,也可以在types.db中对这些数据类型做一个map,看起来更有意义,如下所示:
    • types.db
      
      cpu_usage_percentage               value:GAUGE:0:U
    
    
    • 如果想维持某些变量的状态,可以把该通过regiseter_init来注册包含该变量的函数,如代码中被注释掉的地方。
    • 如果有多个自定义的python plugin,在<Plugin python></Plugin>片段中使用多个Import导入相应的模块,并定义多个<Module></Module>片段。
    • 默认情况下,collectd的log在syslog中。


    展开全文
  • 自定义查询1.一个简单查询示例1.1 具体步骤2.简单转换示例3.编写一个高效 abs__lt 查找4.Transformer 双向示例5.... 本文档解释如何编写自定义查找以及如何更改已有查找工作方式。 ...

    Django提供了各种各样的用于过滤的内置查询(例如,exacticontains)。 本文档解释了如何编写自定义查找以及如何更改已有查找的工作方式。 请参阅有关lookup的API参考

    1.一个简单的查询示例

    让我们从一个简单的自定义查找开始。我们编写一个自定义查找 ne ,它与 exact 相反。 Author.objects.filter(name__ne=‘Jack’) 将会转换成 SQL语句:

    "author"."name" <> 'Jack'
    

    SQL 会自动适配不同的后端, 所以我们不需要对使用不同的数据库担心.

    完成此工作需要两个步骤。第一首先我们需要实现查找,第二我们需要将它告知Django。 查找的实现非常简单:

    from django.db.models import Lookup
    
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params
    

    要注册NotEqual查找,我们只需要在我们希望查找可用的字段类上调用register_lookup方法。 在这种情况下,查找对所有Field子类都有意义,所以我们直接用Field注册它:

    from django.db.models.fields import Field
    Field.register_lookup(NotEqual)
    

    查找注册也可以用修饰模式来完成

    from django.db.models.fields import Field
    
    @Field.register_lookup
    class NotEqualLookup(Lookup):
        # ...
    

    现在我们可以用foo__ne来代表foo的任意字段。你需要确保在创建任意的queryset之前使用它。
    (1) 你可以在models.py文件内设置它
    (2) 或者在“AppConfig”内使用ready()方法注册它。

    1.1 具体步骤

    (1)定义 lookup_name 属性
    仔细观察实现过程,最开始我们需要“lookup_name”这个属性。这个可以保证ORM理解如何编译“name__ne”和使用“NotEqual”来建立结构化查询语言SQL。按照惯例,这些名字“name_ne”是小写字母字符串,但是很麻烦的是必须有“__”字符串
    (2)定义as_sql 方法
    之后我们需要定义一个“as_sql”方法。这方法需要一个“SQLCompiler” 对象, 被叫做编译器,和一个有效的数据库连接。“SQLCompller”对象没有文档,我们只需要知道它有一个compile()方法可以返回一个元组包括SQL字符串,和插入这个字符串的参数。大部分情况下,你不需要直接使用这个对象你可以把它传送给“process_lhs()”和“process_rhs()

    “Lookup”工作依靠两个值, “lhs”和“rhs”,代表左右两边,左边是一个字段参考,但它可以是实现了query expression API的任何东西。右边是一个用户给的数值。举个例子:Author.objects.filter(name__ne='Jack'),左边是一个引用Author模型的name字段的东西,“Jack”是右边。

    我们调用“process_lhs”和“process_rhs”转化他们成为我们想要的用来检索的值通过之前我们提到的“编译器”。这个方法返回一个元组包含SQL数据库和插入SQL数据库一些参数,刚好就是我们‘as_sql’需要返回的。使用前面的例子,“process_lhs”返回('"author"."name"', []) ,“process_rhs”返回('"%s"', ['Jack']).在这个例子里面没有左手边的参数,但是这需要看情况而定,我们还需要包括这些参数当我们返回的时候。

    最后,我们将这些部分组合成一个带有<>的SQL表达式,并提供查询的所有参数。 然后我们返回一个包含生成的SQL字符串和参数的元组。

    效果图
    (1)数据库:
    在这里插入图片描述
    (2)自定义Lookup 之后
    在这里插入图片描述

    2.简单的转换器示例

    上面的自定义查找没问题,但在某些情况下,您可能希望能够将一些查找链接在一起。 例如,假设我们正在构建一个我们想要制作一个带有abs()运算符的应用程序。 我们有一个Experiment模型,它记录start值,end值和change值(start - end)。 我们想找到所有在Experiment模型中change属性等于一定数量的(Experiment.objects.filter(change__abs=27)),或者在Experiment模型中change属性没有超过一定数量的(Experiment.objects.filter(change__abs__lt=27))。

    注意
    这个例子有点刻意,但它很好地演示了以数据库后端独立方式可能实现的功能范围,并且没有重复Django中的功能

    我们将从编写一个AbsoluteValue变换器开始。 这将使用SQL中的ABS()函数在比较进行之前首先转换值:

    from django.db.models import Transform
    class AbsoluteValue(Transform):
        lookup_name = 'abs'
        function = 'ABS'
    

    下一步, 让我们为其注册 IntrgerField:

    from django.db.models import IntegerField
    IntegerField.register_lookup(AbsoluteValue)
    

    我们现在可以运行之前的查询。 Experiment.objects.filter(change__abs = 27)将生成以下SQL

    SELECT ... WHERE ABS("experiments"."change") = 27
    

    译者注,效果图如下:
    (1)数据库
    在这里插入图片描述
    (2)调用Transform
    在这里插入图片描述


    通过使用Transform而不是Lookup,这意味着我们可以在之后链接进一步的查找。 所以Experiment.objects.filter(change__abs__lt = 27)将生成以下SQL

    SELECT ... WHERE ABS("experiments"."change") < 27
    

    请注意,如果没有指定其他查找定义,Django则会将change__abs = 27解析为change__abs__exact = 27

    这也允许结果用于ORDER BYDISTINCT ON子句。 例如Experiment.objects.order_by('change__abs')会生成:

    SELECT ... ORDER BY ABS("experiments"."change") ASC
    

    在支持字段去重的数据库(例如PostgreSQL)上,语句Experiment.objects.distinct('change__abs')会生成:

    SELECT ... DISTINCT ON ABS("experiments"."change")
    

    Django 2.1中的更改:
    上两段所提到的排序与去重的支持被加入了。↑

    当我们在应用Transform之后查找允许哪些查找执行时,Django使用output_field属性。 我们不需要在这里指定它,因为它没有改变,但假设我们将AbsoluteValue应用于某个字段,该字段表示更复杂的类型(例如,相对于原点的点或复数) 那么我们可能想要指定转换返回一个FloatField类型以进行进一步的查找。 这可以通过在变换中添加output_field属性来完成:

    from django.db.models import FloatField, Transform
    
    class AbsoluteValue(Transform):
        lookup_name = 'abs'
        function = 'ABS'
    
        @property
        def output_field(self):
            return FloatField()
    

    这确保了像abs__lte这样的进一步查找与对FloatField一致。

    3.编写一个高效的 abs__lt 查找

    当使用上面写的abs查找时,生成的SQL在某些情况下不会有效地使用索引。 特别是,当我们使用change__abs__lt = 27时,这相当于change__gt = -27change__lt = 27。 (对于lte情况,我们可以使用SQLBETWEEN)。

    因此, 我们希望 Experiment.objects.filter(change__abs__lt=27) 能生成以下 SQL:

    SELECT .. WHERE "experiments"."change" < 27 AND "experiments"."change" > -27
    

    实现方式是:

    from django.db.models import Lookup
    
    class AbsoluteValueLessThan(Lookup):
        lookup_name = 'lt'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = compiler.compile(self.lhs.lhs)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params + lhs_params + rhs_params
            return '%s < %s AND %s > -%s' % (lhs, rhs, lhs, rhs), params
    
    AbsoluteValue.register_lookup(AbsoluteValueLessThan)
    

    这里有几件值得注意的事情。 首先,AbsoluteValueLessThan没有调用process_lhs()。 相反,它会跳过由AbsoluteValue完成的lhs的转换,并使用原始的lhs。 也就是说,我们希望得到"experiments"."change"而不是ABS("experiments"."change")。 直接引用self.lhs.lhs是安全的,因为AbsoluteValueLessThan只能从AbsoluteValue查找访问,即lhs总是AbsoluteValue的实例。

    另请注意,由于在查询中多次使用双方,所以需要多次包含“lhs_params”和“rhs_params”的参数。

    最后的查询直接在数据库中进行反转(27到-27)。 这样做的原因是,如果self.rhs不是普通的整数值(例如F()引用),我们就不能在Python中进行转换。

    效果图
    在这里插入图片描述

    注解
    事实上,大多数查找可以实现为像__abs这样的范围查询,并且在大多数数据库后端,这样做可能更明智,因为您可以使用索引。但是对于PostgreSQL,您可能希望添加一个索引abs(change),以使这些查询非常高效。↑

    4.Transformer 双向示例

    我们之前讨论的AbsoluteValue示例是一个适用于查找左侧的转换。在某些情况下,您可能希望将转换应用于左侧和右侧。例如,如果要根据左侧和右侧的相等性对某个SQL函数进行不相等的过滤查询集。

    让我们来看一下这里不区分大小写的转换的简单示例。这种转换在实践中并不是很有用,因为Django已经带来了一堆内置的不区分大小写的查找,但它将以数据库无关的方式很好地演示双向转换。

    我们定义了一个UpperCase变换器,它使用SQL函数UPPER()在比较之前转换值。我们定义bilateral = True表明此转换应适用于lhs和rhs:

    from django.db.models import Transform
    
    class UpperCase(Transform):
        lookup_name = 'upper'
        function = 'UPPER'
        bilateral = True
    

    下一步,让我们注册它:

    from django.db.models import CharField, TextField
    CharField.register_lookup(UpperCase)
    TextField.register_lookup(UpperCase)
    

    现在,这个Author.objects.filter(name__upper =“doe”)查询集会生成一个像这样的不区分大小写的查询:

    SELECT ... WHERE UPPER("author"."name") = UPPER('doe')
    

    5.为现有查找的关系编写一个代替实现

    有时,不同的数据库供应商对同一操作需要不同的SQL。对于此示例,我们将为NotEqual运算符重写MySQL的自定义实现。我们将使用!= 运算符而不是<>。(请注意,实际上几乎所有数据库都支持这两种运算符,包括Django支持的所有官方数据库)。

    我们可以通过NotEqual使用as_mysql方法创建子类来更改特定后端的行为 :

    class MySQLNotEqual(NotEqual):
        def as_mysql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s != %s' % (lhs, rhs), params
    
    Field.register_lookup(MySQLNotEqual)
    

    然后我们可以注册它Field。它取代了原始 NotEqual类,因为它具有相同的功能lookup_name。

    在编译查询时,Django首先查找as_%s % connection.vendor方法,然后再回到as_sql。对于内置后端的vendor名称有sqlite,postgresql,mysql和oracle。

    6.Django如何确定使用Lookup还是Transforms

    在某些情况下,您可能希望根据传入的名称动态更改哪个Transform或 Lookup返回,而不是修复它。例如,您可以有一个存储坐标或任意维度的字段,并希望允许语法类似于.filter(coords__x7=4)返回第7个坐标值为4的对象。为此,您将覆盖以下get_lookup内容:

    class CoordinatesField(Field):
        def get_lookup(self, lookup_name):
            if lookup_name.startswith('x'):
                try:
                    dimension = int(lookup_name[1:])
                except ValueError:
                    pass
                else:
                    return get_coordinate_lookup(dimension)
            return super().get_lookup(lookup_name)
    

    然后,您将适当地定义get_coordinate_lookup以返回处理相关dimension值的Lookup子类。

    有一个类似命名的方法叫做get_transform()
    get_lookup() 应该总是返回一个Lookup子类或 get_transform()对应返回一个 Transform子类。重要的是要记住,Transform 可以进一步过滤对象,而Lookup对象则不能

    过滤时,如果只剩下一个要查找的查找名称,我们将寻找Lookup。如果有多个名称,它将寻找一个 Transform。在只有一个名称且Lookup 找不到的情况下,我们会查找 Transform然后在Transform上执行exact查找该名称 。所有的调用序列总是以Lookup结束。澄清:

    • .filter(myfield__mylookup)将会调用myfield.get_lookup(‘mylookup’)。
    • .filter(myfield__mytransform__mylookup)将会调用myfield.get_transform(‘mytransform’),接着调用mytransform.get_lookup(‘mylookup’)。
    • .filter(myfield__mytransform)将首先调用 myfield.get_lookup(‘mytransform’),这将失败,所以它将回到调用myfield.get_transform(‘mytransform’)然后 mytransform.get_lookup(‘exact’)。
    展开全文
  • 迷你ASM解释器。 注意之前 这是一个非常自定义,目的少,功能缺失和其他所有程序。 我们目标只是在C中玩乐。如果您愿意,可以提出这个项目并提出您改进建议,我很乐意为您服务。 如何安装 ? cmake . make ...
  • %~dpI - 仅将 %I 扩充到一个驱动号和路径 %~nxI - 仅将 %I 扩充到一个文件名和扩展名 %~fsI - 仅将 %I 扩充到一个带有短名完整路径名 %~dp$PATH:i - 查找列在路径环境变量目录,并将 %I 扩充 到找到...
  • 编写shell脚本

    2020-07-22 18:32:53
    有助于目录生成如何改变文本样式插入链接与图片如何插入一段漂亮代码片生成一个适合你列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少KaTeX数学...
  • 6.1.3 使用自定义的Car类 136 6.1.4 类和对象 139 6.1.5 源文件的存放 141 6.1.5 理解引用 143 6.1.7 null关键字 145 6.2 巧妙使用类中的属性 147 6.2.1 在类中给每个变量一个初始值 147 6.2.2 定义自己的...
  • 6.1.3 使用自定义的Car类 136 6.1.4 类和对象 139 6.1.5 源文件的存放 141 6.1.5 理解引用 143 6.1.7 null关键字 145 6.2 巧妙使用类中的属性 147 6.2.1 在类中给每个变量一个初始值 147 6.2.2 定义自己的...
  • 6.1.3 使用自定义的Car类 136 6.1.4 类和对象 139 6.1.5 源文件的存放 141 6.1.5 理解引用 143 6.1.7 null关键字 145 6.2 巧妙使用类中的属性 147 6.2.1 在类中给每个变量一个初始值 147 6.2.2 定义自己的...
  • 种方法实现了信号和槽函数关联,第一个按钮我们直接在设计中实现其关 联;第二个按钮我们自己写了槽函数语句,其实图形设计与直接写代码效果是 一样。 这个程序里我们实现了两类窗口打开方式,一个是自身...
  • 使用c编写并链接到python解释器的内置模块 已被编译为共享库或DLLC或C++扩展 模块三种来源: 自带模块 第三方模块 自定义模块 为何要用模块 (自带模块,第三方模块)->拿来注意,提升开发效率 自定义...
  • Java语言在刚刚诞生时候提出过句著名口号“编写,到处运行”,这句话充分表达了开发人员对于冲破平台界限渴望,也解释了Java语言跟平台无关设定。 、概述 类加载过程包括加载、连接和初始化,...
  • 在项目文件夹中,运行: ./numake bin/lip然后将在bin/lip创建一个解释器。 numake是我自己的自定义构建工具: : ./watch bin/lip将观看所有依赖bin/lip ,如果需要重建。 使用Visual Studio 2015 Visual ...
  • ③使用C编写并链接到Python解释器的内置模块。 ④已被编译为共享库或DLL的C或C++扩展。 2.模块的三种来源: ①Python解释器自带的(内置库、标准库) ②第三方库 ③自定义的库 二.为什么用模块? 1.拿来主义,提高开发...
  • 为 .NET 数据提供程序编写通用代码:提供有关如何使用 ADO.NET 所提供通用接口来编写一组对于任何 .NET 数据提供程序都将运行代码信息。 ADO.NET 示例应用程序:提供 ADO.NET 应用程序示例,该示例从数据库中...
  • 文章目录shell脚本概述shell是什么?shell脚本概念Shell脚本应用场景Shell脚本的编写编写脚本代码Shell脚本执行重定向和...Shell是一个特殊应用程序,它介于操作系统内核与用户之间,充当了一个“命令解释器
  • 规则编写十分容易,根据贝叶斯邮件检测原理,内置了一个规则解释器主要语法为 if [mail.field] <operator> "pattern" then SPAM_TF = HAM_TF = end [mail.field]主要有[mail.subject] , [mail.sender] , ...
  • finalize是Object类的一个方法,在垃圾收集执行时候会调用被回收对象此方法,可以覆盖此方法提供垃圾收集时其他资源回收,例如关闭文件等。 16、sleep() 和 wait() 有什么区别? sleep是线程类(Thread)...
  • Java目录监视源程序 9个目标文件 内容索引:JAVA源码,综合应用,目录监视 用JAVA开发的一个小型目录监视系统,系统会每5秒自动扫描一次需要监视目录,可以用来监视目录中文件大小及文件增减数目变化。...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    在有状态SessionBean中,用累加,以对话状态存储起来,创建EJB对象,并将当前计数器初始化,调用每一个EJB对象count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天...
  • antlr4权威指南

    2017-09-30 10:47:22
     本书读者对象本书尤其适用于对数据读取器、语言解释器和翻译器感兴趣开发者。虽然本书主要利用ANTLR来完成这些工作,你仍然可以学到很多有关词法分析器和语法分析器知识。初学者和专家都需要本书来高效地...
  • django-docs-2.2-zh-hans.zip

    2019-05-09 11:24:55
    进阶教程 : 如何编写可复用应用 | 提交你一个 Django 补丁 模型层 Django 提供了一个抽象模型 ("models") 层,为了构建和操纵你Web应用数据。阅读下面内容了解更多: 模型: 模型介绍 | 字段类型 | 索引...
  • asp.net知识库

    2015-06-18 08:45:45
    .NET关于string转换的一个小Bug Regular Expressions 完整在.net后台执行javascript脚本集合 ASP.NET 中正则表达式 常用匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎...
  • Visual Studio程序员箴言--详细书签版

    热门讨论 2012-10-16 20:37:39
    技巧2.22 打开文件时重用同一个编辑窗口 42 技巧2.23 在编辑中自动刷新已打开文档 42 技巧2.24 在Visual Studio中编辑只读文件 43 技巧2.25 自定义“文件”→“打开”→“文件”对话框打开目录 44 ...
  • Delphi5开发人员指南

    热门讨论 2012-07-18 16:51:14
    4.3.1 一个项目一个目录 82 4.3.2 共享代码单元 82 4.3.3 多项目管理 84 4.4 Delphi 5项目框架类 84 4.4.1 TForm类 84 4.4.2 TApplication类 89 4.4.3 TApplication方法 91 4.4.4 TApplication事件 92 4.4.5...

空空如也

空空如也

1 2 3 4 5 ... 7
收藏数 130
精华内容 52
关键字:

如何编写一个自定义的解释器