首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Protobuf 入门

IDEA中的Protobuf的插件的使用 首先File->setting中找到plugins 然后安装插件 安装完成后重启IDEA就可以了 测试: 在src/main/下建立proto文件夹,并在其中建立以proto为后缀文件 然后将如下的proto协议写进去 syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; } 然后maven中添加 <properties> <grpc.version>1.6.1</grpc.version> <protobuf.version>3.3.0</protobuf.version> </properties> <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpc.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>${grpc.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>${grpc.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>${protobuf.version}</version> </dependency> </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 等待下载完成后,然后点击maven中的compile插件,运行完,如果配置正确,在项目的target的目录下就生成了我们需要的类文件了 好了介绍到这里,IDEA中使用protobuf插件就完成了,下面是关于protobuf的简介和一些详细内容 简介 Google Protocol Buffer 简称Protobuf是Google公司内部的开源项目,可用于RPC系统和持续数据存储系统 是一种轻便高效的结构化数据存储格式,可用于结构化数据串行化,或者序列化,非常适合数据存储或RPC数据交换格式,可用于通讯协议,数据存储等领域,并且是平台无关的 定义数据类型 如上在IDEA中运行的protobuf文件,我们拿这个来说 syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; } syntax 指定protobuf的版本,必须是文件的第一行 message 代表这是一个消息,SearchRequest消息中指定了三个字段,每一个字段对应于要包含在这种类型的消息中的数据,每一个字段都有一个名称和类型,比如上面的int32 page_number = 2;,名称就是page_number,而类型就是int32,注意等号后面的不是默认值,而可以认为他是此page_number字段的身份证,不可重复,这些数字用于以二进制格式标识您的字段,一旦消息类型被使用就不应该被更改,需要注意的是1到15范围内的字段编号需要一个字节来编码,而16到2047范围内的字段编号需要两个字节,所以经常使用的应该为其编码为1到15之间,这些数字的范围是[1, 536870911],其中19000~19999是为协议缓冲区实现而保留的,不可以使用,否则报错 标量值类型 即int32 page_number = 2;中的int32叫做标量值类型 下面是标量值类型以及生成的java中的对应类型 类型 说明 对应类型 double null double float null float int32 使用可变长度编码,编码负数效率低下,如果你的字段可能有负值,请改用sint32 int int64 使用可变长度编码,编码负数效率低下,如果你的字段可能有负值,请改用sint64 long uint32 使用可变长度编码 int uint64 使用可变长度编码 long sint32 使用可变长度编码,符号整型值,这些比常规int32编码负数更有效 int sint64 使用可变长度编码,有符号的int值,这些比常规int64编码负数更有效 long fixed32 总是四字节,如果值经常大于2^28,则比uint32更有效 int fixed64 总是八字节,如果值经常大于2^56,则比uint64更有效 long sfixed32 总是四字节 int sfixed64 总是八字节 long bool null boolean string 字符串必须始终包含UTF8编码或7位ASCII文本 string bytes 可以包含任意字节序列 byteString 如果你使用的是别的语言,那么还有一张对照图,在下面 修饰符 如果一个字段被repeated修饰,则表示它是一个列表类型的字段 如果你现在不确定是否某个值或者变量是否以后会使用的到为了不误写,那么可以保留 message Foo { reserved 2, 15, 9 to 11; reserved "foo", "bar"; string foo = 3 // 编译报错,因为‘foo’已经被标为保留字段 } 缺省值:默认值 string类型的默认值是空字符串 bytes类型的默认值是空字节 bool类型的默认值是false 数字类型的默认值是0 enum类型的默认值是第一个定义的枚举值 message类型(对象,如上文的SearchRequest就是message类型)的默认值与 语言 相关 repeated修饰的字段默认值是空列表,比如repeated string query = 1; = java.util.List<java.lang.String> 如果一个字段的值等于默认值(如bool类型的字段设为false),那么它将不会被序列化,这样的设计是为了节省流量 枚举 之前的都是简单类型,比如int32之类的,那么在message中还可以定义复杂类型 每个枚举值有对应的数值,数值不一定是连续的.第一个枚举值的 数值必须是0且至少有一个枚举值 ,否则编译报错.编译后编译器会为你生成对应语言的枚举类,零值必须为第一个元素,以便与proto 2语义兼容,其中第一个枚举值总是默认的 由于编码原因,出于效率考虑,不推荐使用负数作为枚举值的数值 如下就在之前的基础上添加到了春夏秋冬四个枚举常量值,当然里面的数字标识不用按顺序来 syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; Groups groups = 4; enum Groups{ SPRING = 0; SUMMER = 1; Autumn = 2; WINTER = 3; } } 如果个别的枚举值的标识是相同的,需要用option allow_alias = true;来声明一下,比如 enum Groups{ option allow_alias = true; SPRING = 0; SUMMER = 2; Autumn = 2; WINTER = 3; } 如果去掉option allow_alias = true;,那么编译会出现错误, 并且注意枚举数常量必须在32位整数的范围内 可以使用messageName.enum的形式,在其他message中引用,比如 message Others { SearchRequest.Groups groups = 1; } 其生成的类中方法定义的返回值就是Mes.SearchRequest.Groups getGroups(); 使用其它的message类型 第一种使用方法如下 syntax = "proto3"; message First { repeated string query = 1; Second second = 2; //引用其他message类型 } message Second { int32 num = 1; } 第二种即import导入使用 syntax = "proto3"; import "second.proto"; //首先导入 message First { repeated string query = 1; Second second = 2; //引用其他message类型 } 上面这种导入如果测试,需要将second.proto移到相同目录下,并且First和Second消息是两个proto文件 嵌套 可以在一个message类型中定义另一个message类型,并且可以一直嵌套下去,类似Java的内部类 message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; } 可以使用Parent.Type的形式引用嵌套的message message SomeOtherMessage { SearchResponse.Result result = 1; } 更新message 当proto不能满足要求的情况下,那么我们就需要按照要求更新message 不要更改任何已有的字段的数值标识 如果增加新的字段,使用旧格式的字段仍然可以被新产生的代码所解析.相似的,通过新代码产生的消息也可以被旧代码解析:只不过新的字段会被忽视掉.注意:未被识别的字段会在反序列化的过程中丢弃掉,所以如果消息再被传递给新的代码,新的字段依然是不可用的 非required的字段可以移除,只要它们的标识号在新的消息类型中不再使用,但是更好的做法是将此字段重命名,保证其标识号不被其他变量误用 nt32, uint32, int64, uint64,和bool是全部兼容的,如果转换的时候发生不符合的情况,那么会强制类型转换 sint32和sint64是互相兼容的,但是它们与其他整数类型不兼容 string和bytes是兼容的,只要bytes是有效的UTF-8编码 嵌套消息与bytes是兼容的,只要bytes包含该消息的一个编码过的版本 fixed32与sfixed32是兼容的,fixed64与sfixed64是兼容的 枚举类型与int32,uint32,int64和uint64相兼容,,如果转换的时候发生不符合的情况,那么会强制类型转换 Any Any允许包装任意的message类型 ,一个Any类型包括一个可以被序列化bytes类型的任意消息,以及一个URL作为一个全局标识符和解析消息类型.为了使用Any类型,你需要导入import google/protobuf/any.proto import "google/protobuf/any.proto"; message Response { google.protobuf.Any data = 1; } 如上会被解析成private java.util.List<com.google.protobuf.Any> details_; 类型 对于给定的消息类型的默认类型URL是type.googleapis.com/packagename.messagename 不同语言的实现会支持动态库以线程安全的方式去帮助封装或者解封装Any值,例如在java中,Any类型会有特殊的pack()和unpack()访问器 实例 //People.proto syntax = "proto3"; message Get{ string name = 1; } //First.proto syntax = "proto3"; import "google/protobuf/any.proto"; message Response { google.protobuf.Any data = 1; } public class Tests { public static void main(String[] args) throws InvalidProtocolBufferException { People.Get wangziqiang = People.Get.newBuilder().setName("wangziqiang").build(); First.Response build = First.Response.newBuilder().setData(Any.pack(wangziqiang)).build(); System.out.println(build.getData()); System.out.println(build.getData().unpack(People.Get.class).getName()); } /** * 输出结果 * type_url: "type.googleapis.com/Get" * value: "\n\vwangziqiang" * wangziqiang */ } 如上我们就看到了,Any可以包含任何的message,也就是进行pack动作,而unpack是进行解包得到内容,这是我自己的理解 Oneof 用于几个参数只能初始化其中一个的情况,设置其中一个字段会清除其它字段,repeated不可以在其中被使用 syntax = "proto3"; message Name{ oneof set_name{ string first_name = 1; string last_name = 2; } } public class Tests { public static void main(String[] args) { People.Name wangziqiang = People.Name.newBuilder().setFirstName("nn").setLastName("wangziqiang").build(); System.out.println("getFirstName -> " + wangziqiang.getFirstName()); System.out.println("getLastName -> " + wangziqiang.getLastName()); System.out.println(wangziqiang.getFirstName().isEmpty()); System.out.println(wangziqiang.getLastName().isEmpty()); } /** * getFirstName -> wangziqiang * getLastName -> * true * false * 也就可以看出来,只有最后一次设置的字段有值. */ } Map 其实是一种语法糖,如下 message xx{ int32 i = 1; string j = 2; } message ss { xx x = 1; //map<int32,string> = 1 } 需要注意的是key除了floating和bytes的任意标量类型都是可以的,value可以是任意类型 map的顺序不一定 map类型字段不支持repeated 当为.proto文件产生生成文本格式的时候,map会按照key 的顺序排序,数值化的key会按照数值排序 如果有重复的key则后一个key不会被使用 实例 syntax = "proto3"; message Name{ map<int32,string> names = 1; } public class Tests { public static void main(String[] args) throws InvalidProtocolBufferException { People.Name.Builder builder = People.Name.newBuilder(); builder.putNames(1,"one"); builder.putNames(3,"three"); builder.putNames(2,"two"); People.Name name = builder.build(); System.out.println(name); } /** * names { * key: 1 * value: "one" * } * names { * key: 3 * value: "three" * } * names { * key: 2 * value: "two" * } */ } 包 使用方法 syntax = "proto3"; package qidai; message Name{ map<int32,string> names = 1; } 定义服务 如果想要将消息类型用在RPC系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffer编译器将会根据所选择的不同语言生成服务接口代码 syntax = "proto3"; package qidai; message NameRequest{ string name = 1; } message NameResponse{ int32 name_hash = 1; } service rpc_name { rpc getName(NameRequest) returns(NameResponse); } 上面的表示,rpc的参数为NameRequest,而返回值为NameResponse,对于java应用protobuf实现简单的rpc,之后再说 JSON映射 在protobuf中支持使用JSON,那么对于protobuf中的类型和JSON中的类型的对应表如下 proto3 JSON JSON示例 注意 message object {"fBar": v, "g": null, …} 产生JSON对象,消息字段名可以被映射成lowerCamelCase形式,并且成为JSON对象键,null被接受并成为对应字段的默认值 enum string "FOO_BAR" 枚举值的名字在proto文件中被指定 map object {"k": v, …} 所有的键都被转换成string repeated V array [v, …] null被视为空列表 bool true, false true, false string string "Hello World!" bytes base64 string "YWJjMTIzIT8kKiYoKSctPUB+" int32,fixed32,uint32 number 1, -10, 0 JSON值会是一个十进制数,数值型或者string类型都会接受 int64,fixed64,uint64 string "1", "-10" JSON值会是一个十进制数,数值型或者string类型都会接受 float,double number 1.1, -10.0, 0, "NaN", "Infinity" JSON值会是一个数字或者一个指定的字符串如”NaN”,”infinity”或者”-Infinity”,数值型或者字符串都是可接受的,指数符号也可以接受 Any object {"@type": "url", "f": v, … } 如果一个Any保留一个特上述的JSON映射,则它会转换成一个如下形式:{"@type": xxx, "value": yyy}否则,该值会被转换成一个JSON对象,@type字段会被插入所指定的确定的值 Timestamp string "1972-01-01T10:00:20.021Z" 使用RFC 339,其中生成的输出将始终是Z-归一化啊的,并且使用0,3,6或者9位小数 Duration string "1.000340012s", "1s" 生成的输出总是0,3,6或者9位小数,具体依赖于所需要的精度,接受所有可以转换为纳秒级的精度 Struct object { … } 任意的JSON对象,见struct.proto Wrapper types various types 2, "2", "foo", true, "true", null, 0, ... 包装器在JSON中的表示方式类似于基本类型,但是允许nulll,并且在转换的过程中保留null FieldMask string "f.fooBar,h" 见fieldmask.proto ListValue array [foo, bar, …] Value value 任意JSON值 NullValue null JSON null 下面也是对照表 选项 在定义.proto文件时能够标注一系列的options.Options并不改变整个文件声明的含义,但却能够影响特定环境下处理方式.完整的可用选项可以在google/protobuf/descriptor.proto找到,在IDEA中直接搜索descriptor.proto就行 一些选项是文件级别的,意味着它可以作用于最外范围,不包含在任何消息内部、enum或服务定义中.一些选项是消息级别的,意味着它可以用在消息定义的内部.当然有些选项可以作用在域、enum类型、enum值、服务类型及服务方法中 常用的选择 java_package:文件选项,即指定包名,如下,但是自己感觉好像与package com.qidai;一样的作用 syntax = "proto3"; option java_package = "com.qidai"; message NameRequest{ string name = 1; } java_outer_classname:文件选项,即指定外部类类名,如果不指定,那么默认的类名是以proto文件的名字作为类名的 syntax = "proto3"; option java_outer_classname = "Peoples"; //然后编译完成后就是生成的Peoples的类名,而不是以proto文件名作为类名了 message NameRequest{ string name = 1; } optimize_for:文件选项,可以被设置为 SPEED, CODE_SIZE,或者LITE_RUNTIME,这些值将影响代码的生成 SPEED:默认protocol buffer编译器将通过在消息类型上执行序列化、语法分析及其他通用的操作.这种代码是最优的. CODE_SIZE:protocol buffer编译器将会产生最少量的类,通过共享或基于反射的代码来实现序列化、语法分析及各种其它操作.采用该方式产生的代码将比SPEED要少得多, 但是操作要相对慢些,但是生成的代码的访问方式和SPEED是一样的 LITE_RUNTIMEprotocol buffer编译器依赖于运行时核心类库来生成代码(即采用libprotobuf-lite 替代libprotobuf).这种核心类库由于忽略了一 些描述符及反射,要比全类库小得多.这种模式经常在移动手机平台应用多一些 syntax = "proto3"; option optimize_for = SPEED; message NameRequest{ string name = 1; } deprecated:表示废弃了 syntax = "proto3"; message NameRequest{ string name = 1 [deprecated = true]; } 生成访问类 如上我们都是在IDEA插件的帮助下,自动完成编译的,自己接触的是Java,所以在这里列一下Java的生成类的方式,如果你是别的语言,那么请参考给出的参考博文 protoc --proto_path=IMPORT_PATH --java_out=DST_DIR path/to/file.proto IMPORT_PATH声明了一个.proto文件所在的解析import具体目录,如果忽略该值,则使用当前目录,如果有多个目录则可以多次调用--proto_path,-I=IMPORT_PATH是--proto_path的简化形式 --java_out 在目标目录DST_DIR中产生Java代码 作为一个方便的拓展,如果DST_DIR以.zip或者.jar结尾,编译器会将输出写到一个ZIP格式文件或者符合JAR标准的.jar文件中.注意如果输出已经存在则会被覆盖 好了到这就是Protobuf的基本用法,本文参考网上的博文,链接如下,如果本文有什么错误请及时指出 , 谢谢咯 开发学院简书CSDN

优秀的个人博客,低调大师

Lambda入门

Lambda 来源于微积分数学中的 λ,其涵义是声明为了表达一个函数具体需要什么. Table of contents Introduction 使用 Introduction 什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个“值”。 如果你想把“一块代码”赋给一个Java变量,应该怎么做呢? 比如,我想把右边那块代码,赋给一个叫做aBlockOfCode的Java变量: 在Java 8之前,这个是做不到的。但是Java 8问世之后,利用Lambda特性,就可以做到了。 当然,这个并不是一个很简洁的写法。所以,为了使这个赋值操作更加elegant, 我们可以移除一些没用的声明。 这样,我们就成功的非常优雅的把“一块代码”赋给了一个变量。而“这块代码”,或者说“这个被赋给一个变量的函数”,就是一个Lambda表达式。 但是这里仍然有一个问题,就是变量aBlockOfCode的类型应该是什么? 在Java 8里面,所有的Lambda的类型都是一个接口,而Lambda表达式本身,也就是”那段代码“,需要是这个接口的实现。这是我认为理解Lambda的一个关键所在,简而言之就是,Lambda表达式本身就是一个接口的实现。直接这样说可能还是有点让人困扰,我们继续看看例子。我们给上面的aBlockOfCode加上一个类型: 这种只有一个接口函数需要被实现的接口类型,我们叫它”函数式接口“。为了避免后来的人在这个接口中增加接口函数导致其有多个接口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接口函数了: 这样,我们就得到了一个完整的Lambda表达式声明: 使用 Lambda表达式有什么作用? 最直观的作用就是使得代码变得异常简洁。 我们可以对比一下Lambda表达式和传统的Java对同一个接口的实现: 这两种写法本质上是等价的。但是显然,Java 8中的写法更加优雅简洁。并且,由于Lambda可以直接赋值给一个变量,我们就可以直接把Lambda作为参数传给函数, 而传统的Java必须有明确的接口实现的定义,初始化才行: 有些情况下,这个接口实现只需要用到一次。传统的Java 7必须要求你定义一个“污染环境”的接口实现MyInterfaceImpl,而相较之下Java 8的Lambda, 就显得干净很多。 Lambda结合FunctionalInterface Lib, forEach, stream(),method reference等新特性可以使代码变的更加简洁! 直接上例子。 假设Person的定义和List的值都给定。 该注解见lombok 现在需要你打印出guiltyPersons List里面所有LastName以"Z"开头的人的FirstName。 原生态Lambda写法:定义两个函数式接口,定义一个静态函数,调用静态函数并给参数赋值Lambda表达式。 这个代码实际上已经比较简洁了,但是我们还可以更简洁么? 当然可以。在Java 8中有一个函数式接口的包,里面定义了大量可能用到的函数式接口(java.util.function (Java Platform SE 8 ))。所以,我们在这里压根都不需要定义NameChecker和Executor这两个函数式接口,直接用Java 8函数式接口包里的Predicate和Consumer就可以了——因为他们这一对的接口定义和NameChecker/Executor其实是一样的。 第一步简化 - 利用函数式接口包: 静态函数里面的for each循环其实是非常碍眼的。这里可以利用Iterable自带的forEach()来替代。forEach()本身可以接受一个Consumer 参数。 第二步简化 - 用Iterable.forEach()取代foreach loop: 由于静态函数其实只是对List进行了一通操作,这里我们可以甩掉静态函数,直接使用stream()特性来完成。stream()的几个方法都是接受Predicate,Consumer等参数的(java.util.stream (Java Platform SE 8 ))。你理解了上面的内容,stream()这里就非常好理解了,并不需要多做解释。 第三步简化 - 利用stream()替代静态函数: 对比最开始的Lambda写法,这里已经非常非常简洁了。但是如果,我们的要求变一下,变成print这个人的全部信息,及p -> System.out.println(p); 那么还可以利用Method reference来继续简化。所谓Method reference, 就是用已经写好的别的Object/Class的method来代替Lambda expression。格式如下: 第四步简化 - 如果是println(p),则可以利用Method reference代替forEach中的Lambda表达式: 这基本上就是能写的最简洁的版本了 Lambda配合Optional可以使Java对于null的处理变的异常优雅 这里假设我们有一个person object,以及一个person object的Optional wrapper: Optional如果不结合Lambda使用的话,并不能使原来繁琐的null check变的简单。 只有当Optional结合Lambda一起使用的时候,才能发挥出其真正的威力! 我们现在就来对比一下下面四种常见的null处理中,Java 8的Lambda+Optional和传统Java两者之间对于null的处理差异。 情况一 - 存在则开干 情况二 - 存在则返回,无则返回屁 情况三 - 存在则返回,无则由函数产生 情况四 - 夺命连环null检查 由上述四种情况可以清楚地看到,Optional+Lambda可以让我们少写很多ifElse块。尤其是对于情况四那种夺命连环null检查,传统java的写法显得冗长难懂,而新的Optional+Lambda则清新脱俗,清楚简洁 关于Java的Lambda, 还有东西需要讨论和学习。比如如何handle lambda exception,如何利用Lambda的特性来进行parallel processing等。总之,我只是一如既往地介绍个大概,让你大概知道,哦!原来是这样子就OK了。网上关于Lambda有很多相关的教程,多看多练。假以时日,必定有所精益。 转载自知乎用户Sevenvidia,来自Amazon,Lambda 表达式有何用处?如何使用?

优秀的个人博客,低调大师

Numpy入门

标题中的英文首字母大写比较规范,但在python实际使用中均为小写。 2018年7月23日笔记 0. 学习内容: Python科学计算库:Numpy需要掌握的知识: 1.Numpy简介;2.Numpy程序包;3.简单的Numpy程序;4.为什么使用Numpy; 5.Numpy是什么;6.Numpy数据溢出; 1. Numpy简介 Numpy是python语言中的科学计算库。 下文主要介绍数据科学工具包Numpy的基本用法,内容包括: 1.Numpy的ndarray多维数组创建 2.Numpy的ndarray多维数组索引切片访问 3.Numpy的ndarray多维数组的组合分割 2. Numpy程序包 集成开发环境为Jupyter notebook 语言及其版本为python3.6 安装numpy在cmd中运行命令:pip install numpy,如果电脑安装了最新版的anaconda,则自带jupyter notebook和numpy库。 集成开发环境如下图所示: image_1cj3s95tl1rsg1hlm1fatkhl12bj9.png-24kB 3.简单的Numpy程序 两个一维矩阵做加法 matrix1 = [0,1,4] matrix2 = [0,1,8] matrix3 = [0,2,12] #使用python原有的列表和推导式 matrix1 = [0,1,4] matrix2 = [0,1,8] matrix3 = [a+b for a,b in zip(matrix1,matrix2)] print(matrix3,type(matrix3)) #使用numpy库计算 import numpy matrix1 = numpy.arange(3) ** 2 matrix2 = numpy.arange(3) ** 3 matrix3 = matrix1 + matrix2 print(matrix3,type(matrix3)) 代码及其运行结果如下图所示: image_1cj3sskqr1t6p19dm1so8aodibh13.png-31.5kB 4.为什么使用Numpy 原因有以下3点: 1.对于同样的数值计算任务,由于Numpy能够直接对数组和矩阵进行操作,可以省略很多循环语句使用Numpy要比直接编写Python代码便捷得多; 2.Numpy中数组的存储效率和输入输出性能均远远优于Python中等价的数据结构; 3.Numpy的大部分代码都是用C语言写的,这使得Numpy比纯Python代码高效得多。 5.Numpy是什么 Numpy的全名为Numeric Python,是一个开源的科学计算库,它包括: 1.一个强大的N维数组对象ndarray;2.比较成熟的函数库; 3.用于整合C/C++和Fortran代码的工具包;4.实用的线性代数、傅里叶变换和随机生成函数。 Numpy支持高维度数组计算和矩阵计算,此外也针对了数组提供了大量的科学函数库。 6.Numpy数据溢出 import numpy as np matrix = np.arange(1292) ** 3 print(matrix.dtype) print(matrix[-3:]) print(2 ** 32 - 1291 ** 3) 代码及其运行结果如下图: image_1cj3u1bb713t11jlkjsp1tmjih41t.png-15.8kB 从上面一段代码可以看出:1.np.arange方法产生的一个ndarray对象,对象中的元素默认为int32类型。 2^31 - 1的值为2147483647,如果int32类型超过这个值则算越界,越界后所得值为负数。 越界所得负数的绝对值 + 原本值 = 2 ** 32。 练习 利用Numpy实现两个向量相乘的结果 有两种解答方法:1.利用np.dot方法,需要2个参数,1个参数数据类型为ndarray,长度要相同。 2.利用ndarray对象的dot方法,需要1个参数,参数数据类型为ndarray,长度要相同。 下面代码中有两种解答方法的示例。 import numpy as np matrix1 = np.arange(10) print(matrix1) matrix2 = np.arange(10,20) print(matrix2) print(np.dot(matrix1,matrix2)) print(matrix1.dot(matrix2)) image_1cja6gt6rp7orhr1rq712jff899.png-41.1kB

优秀的个人博客,低调大师

MongoDB入门

2018年7月5日笔记 1.MongoDB简介 1.1 NoSQL数据库是什么 NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同的传统的关系型数据库的数据库管理系统的统称。 NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。 主要解决: 1.对数据库高并发的需求 2.对海量数据的高效率存储和访问的需求 3.对数据库的高扩展性和高可用性的需求 1.2 什么是MongoDB 取自“humongous”(海量),是由10gen团队2007年10月开发并维护的开源,高性能,可扩展,无模式,面向文档(document-oriented)的数据库。其内存储的一种-like结构化数据。它介于关系数据库和非关系数据库之间,是非关系数据库中最像关系数据库的。是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储方案。 官网:http://www.mongodb.com 最新版本:3.6.3(3/20/2018) 支持操作系统:OSX/linux/Windows 1.3 MongoDB数据库的特点 高性能、易部署、易使用、存储数据数据非常方便。主要功能特性有: 1.面向集合存储,易存储对象类型的数据 2.模式自由(没有行,列,关系等概念) 3.支持完全索引,包含内部对象。 4.支持查询 5.支持复制和故障恢复 6.使用高效的二进制数据存储,包括大型对象 7.自动处理碎片,以支持云计算层次的扩展性 8.支持C#、Python、Ruby、Java、C、Javascript、Perl以及C++语言的驱动程序,社区中也提供了对Erlang以及.NET及平台的扩展程序。 9.文件存储格式为BSON(一种JSON的扩展) 10.可通过网络访问 优点:弱一致性、文档结构的存储方式、内置GridFS(分布式文件系统)缺点:不支持事务、空间占用大 1.4 MongoDB数据库的适用场合 适用场景: 1.网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。 2.缓存。由于性能很高,他适合作为信息基础建设的缓存层。在系统重启之后,由它搭建的数据持久化存储层可以避免下层的数据源过载。 3.高伸缩性的场合。非常适合由数十或者数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。不适用场景: 1.类似银行或会计系统这种高事务性的系统。 2.传统的商业智能应用 3.复杂的跨文档级联查询 1.5 MongoDB 视觉中国、大众点评、淘宝、优酷、淘宝 2.MongoDB的基本使用 MongoDB的软件安装教程:Windows 平台安装 MongoDB教程 下面的命令能够正确运行的前提是已经启动MongoDB服务 进入MongoDB的Shell.png-26.3kB 2.1 显示已有的数据库 命令:show dbs 图片.png-1kB 2.2 创建库 使用use runoob就已经创建一个名为runoob的数据库,但必须要往runoob数据库中的一个集合中插入一条数据才能用show dbs命令看到runoob数据库,db.mycoll.insert({name:'runoob'})这一句就是往mycoll这个集合中插入一条name字段值为runoob的数据。 在MongoDB中,数据库和集合不需要提前创建,只要使用就自动创建。 命令: use runoob db.mycoll.insert({name:'runoob'}) show dbs 2.3 删除数据库 命令:db.dropDatabase() 图片.png-3.5kB 2.4 创建集合 命令:db.createCollection(name,options) name参数的数据类型是字符串,意义是要创建的集合名称 options参数的数据类型是json格式的文本,意义是制定有关内存大小和索引选项 options可以是如下参数: 图片.png-16.1kB 从下图中可以看出,一开始使用 show collections显示没有集合,创建第一个简单的集合 mycoll,第二个带参数的集合 mycoll2,创建两个集合后,可以用 show collections可以显示这两个集合的存在。 图片.png-4.5kB 2.5 删除集合 命令:db.{}.drop(),大括号中的要填入的内容是要删除的集合的名称。 图片.png-1.6kB 3.MongoDB进阶 3.1 MongoDB常见数据类型 1.String:这是最常见的数据类型来存储数据,在MongoDB中的字符串必须是有效的UTF-8 2.Integer:这种类型是用来存储一个数值。整数可以是32位或64位,这取决与运行软件的机器。 3.Boolean:用来存储布尔值(true/false) 4.Double:用来存储浮点值 5.Min/Max Keys: 用来对BSON元素的最低和最高值比较 6.Arrays:使用此类型的数组或列表存储到一个键 7.Timestamp:时间戳,这可以方便记录的文件已被修改或添加 8.Object:此类型嵌入式的文件中 9.Null:这种类型是用来存储一个Null的 10.Symbol:用于字符串相同,但它通常是保留给特定符号类型的语言使用。 11.Date:用于存储当前时间或日期的Unix时间格式,可以指定自己的日期和时间。 12.ObjectID:用于存储文档的ID 13.Binary data:用于存储二进制数据 14.Regular expression:用于存储正则表达式 3.2 MongoDB插入文档 命令语法:db.{}.insert({}),第一个大括号填入集合名,第二个大括号填入要插入的文档。 图片.png-7.3kB 3.3 MongoDB更新文档 命令语法:db.{}.update({},{}),第一个大括号填入集合名,第二个大括号填入json格式的文本,第三个括号填入两层json格式文本,第一层的第一个元素的键为$set 图片.png 从上图中可以看到集中mycoll中的第一个文档中的第一个元素title的值从MongoDB overview改为了MongoDB。 3.4 MongoDB Save()方法 命令语法: db.{}.save({}),第一个大括号填入集合名,第二个大括号填入json格式的文本 图片.png 3.5 MongoDB删除文档 命令语法: db.{}.remove({},{}),第一个大括号填入集合名,第二个大括号填入json格式的文本,用于选择被删除的文档,成对大括号内可以为空,第三个括号内为非0整数或true时,删除一条满足判断语句的文档。 图片.png 第三个括号内为0或false或者不填时,删除所有满足判断语句的文档,如下图所示。 图片.png 4.MongoDB查询文档 4.1 find()方法 从MongoDB中查询集合数据,需要使用MongoDB的find()方法。 命令语法:db.{}.find({}),第一个大括号填入集合名,第二个大括号填入json格式的文本 如下图所示,find()函数没有参数时,显示这个集合当中的所有文档;find()函数有参数,但是没有找到满足判断条件的语句时,没有打印结果 图片.png-5.4kB 使用pretty()方法可以使在命令行中的数据打印更整齐。 图片.png-6.4kB 4.2 limit()方法 图片.png-10.4kB 作业 创建数据库 school 用来存放一些班级学生信息; use school db.createCollection("students") 你要为学校下的各个年级、班级建立集合;创建集合可以是显式的,也可以是隐式的;在这路你需要显式地创建“一年级一班的”集合grade_1_1; use school db.createCollection("grades") db.createCollection("classes") db.createCollection("grade_1_1") 隐式创建“一年级二班”:grade_1_2创建的同时为“一年级二班”加入一个学生:"name": 'zhangsan', "age": '7', "sex": "0" use school db.grade_1_2.insert({name:"zhangsan",age:7,sex:0}) 因为一些特殊原因,要解散一年级二班,删除一年级二班的信息 use school school.grade_1_2.drop() 使用循环创建一年级的3个班,并随机添加 10 名学生 for(grade_index in (grade = ['grade_1_1', 'grade_1_2', 'grade_1_3'])) { for (var i = 1; i <= 10; i++) { db[grade[grade_index]].insert({ "name": "zhangsan" + i, "sex": Math.round(Math.random() * 10) % 2, "age": Math.round(Math.random() * 6) + 3, "hobby": [] }); } } 6.查看一年级二班grade_1_2中的所有学生 db.grade_1_2.find() 7.查看一年级二班grade_1_2中所有年龄是 4 岁的学生 db.grade_1_2.find({age:4}) 8.查看一年级二班grade_1_2中所有年龄大于 4 岁的学生 db.grade_1_2.find({age:{$gt:4}}) 9.查看一年级二班grade_1_2中所有年龄大于 4 岁并且小于 7 岁的学生 db.grade_1_2.find({age:{gt:4,lt:7}}) 10.查看一年级二班grade_1_2中所有年龄是 4 岁或 6 岁的学生 db.grade_1_2.find({$or:[{age:4},{age:6}]}) 11.查看一年级二班grade_1_2中所有姓名带zhangsan1的学生 db.grade_1_2.find({name:{$regex:"zhangsan1"}}) 12.查看一年级二班grade_1_2中所有姓名带zhangsan1和zhangsan2的学生 db.grade_1_2.find({$or:[{name:"zhangsan1"},{name:"zhangsan2"}]}) 13.查看一年级二班grade_1_2中所有兴趣爱好有三项的学生 db.grade_1_2.find({hobby:{$size:3}}) 14.查看一年级二班grade_1_2中所有兴趣爱好包括画画的学生 db.grade_1_2.find({hobby:"drawing"}) 15.查看一年级二班grade_1_2中所有兴趣爱好既包括画画又包括跳舞的学生 db.grade_1_2.find({hobby:{$all:{"drawing","dance"}}}) 16.查看一年级二班grade_1_2中所有兴趣爱好有三项的学生的 学生数目 db.grade_1_2.find({hobby:{$size:3}}).count() 17.查看一年级二班的第二位学生 db.grade_1_2.find().limit(1).skip(1) 18.查看一年级二班的学生,按年纪升序 db.grade_1_2.find().sort({age:1}) 19.查看一年级二班的学生,按年纪降序 db.grade_1_2.find().sort({age:-1}) 20.查看一年级二班的学生,年龄值有哪些 db.grade_1_2.distinct('age') 21.查看一年级二班的学生,兴趣覆盖范围有哪些 db.grade_1_2.distinct('hobby') 22.查看一年级二班的学生,男生(sex为 0)年龄值有哪些 db.grade_1_2.distinct('age',{'sex':0}) 23.一年级二班grade_1_2, 删除所有 4 岁的学生 db.grade_1_2.remove({age:4}) 24.一年级二班grade_1_2, 删除第一位 6 岁的学生 db.grade_1_2.remove({age:4},1) 25.一年级二班grade_1_2中,修改名为zhangsan7的学生,年龄为 8 岁,兴趣爱好为 跳舞和画画; db.grade_1_2.update({name:"zhangsan7"},{$set:{age:8,hobby:["dance","drawing"]}}) 26.一年级二班grade_1_2中,追加zhangsan7学生兴趣爱好唱歌; db.grade_1_2.update({name:"zhangsan7"},{$push:{hobby:"sing"}}) 27.一年级二班grade_1_2中,追加zhangsan7学生兴趣爱好吹牛和打篮球; db.grade_1_2.update({"name": "zhangsan7"},{$push: {"hobby": {$each: ["brag","basketball"]}}}) 28.一年级二班grade_1_2中,追加zhangsan7学生兴趣爱好唱歌和打篮球,要保证hobby数组不重复; db.grade_1_2.update({"name": "zhangsan7"},{$addToSet: {"hobby": {$each: ["sing","basketball"]}}}) 29.新学年,给一年级二班所有学生的年龄都增加一岁 db.grade_1_2.update({},{$inc:{"age":1}},{multi:true}) 30.一年级二班grade_1_2中,删除zhangsan7学生的sex属性 db.grade_1_2.update({name:"zhangsan7"},{$unset:{sex:1}}) 31.一年级二班grade_1_2中,删除zhangsan7学生的hobby数组中的头元素 db.grade_1_2.update({name:"zhangsan7"},{$pop:{hobby:-1}}) 32.一年级二班grade_1_2中,删除zhangsan7学生的hobby数组中的尾元素 db.grade_1_2.update({name:"zhangsan7"},{$pop:{hobby:1}}) 33.一年级二班grade_1_2中,删除zhangsan7学生的hobby数组中的sing元素 db.grade_1_2.update({name:"zhangsan7"},{$pull:{hobby:"sing"}})

优秀的个人博客,低调大师

spring入门

ioc:https://www.jianshu.com/p/695b2a25a6ff 教学视频:https://www.bilibili.com/video/av14839030/ 在eclipse里面遇到的问题 ① .遇到红色波浪线就把鼠标放在上面,导入jar包用在crtl+shift+M ②.The constructor ClassPathXmlApplicationContext(String) refers to the missing type出现此问题可能是jar包没有导入成功,将jar包再导入一次 ioc底层原理 IOC:控制反转,把对象创建交给spring进行配置 DI:依赖注入,向类里面的属性设置值依赖注入不能单独存在,需在ioc基础上完成操作。 1.png 2.png 四个最基本的jar包 beans core context expression common-logging//日志 xml文件限制 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans> 测试文件 package cn.itcast.ioc; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.itcast.property.PropertyDemo1; public class TestIOC { @Test public void testUser() { ApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml"); PropertyDemo1 demo1 = (PropertyDemo1) context.getBean("demo"); demo1.test1(); } } Bean标签常用属性 ①.id 起名称,可以任意命名 不能包含特殊符号 根据id得到配置对象 ②.class属性 创建对象所在类的全路径 ③.name属性 功能和id属性一样,name可以包含特殊字符 ④.scope属性 在测试文件中调用两次函数: 4.png singleton 默认值,单例 运行结果: 3.png prototype 多例 5.png 运行结果: request 创建对象并把对象放到request里面 session 创建对象并把对象放到session里面 globalSession 创建对象并把对象放到globalSession里面 属性注入:(spring里面只支持前两种) 3.png set方法注入 package cn.itcast.property; public class Book { private String bookname; public void setBookname(String bookname) { this.bookname=bookname; } public void demobook() { System.out.println("book...."+bookname); } } 然后在applicationContext.xml文件中使用以下方法给bookname赋值 1.png 有参数构造注入 package cn.itcast.property; public class PropertyDemo1 { private String username; public PropertyDemo1(String username) { this.username=username; } public void test1() { System.out.println("demo1........"+username); } } 然后在applicationContext.xml文件中使用以下方法给username赋值 1.png 注入对象类型属性 通过set方法在UserService.java调用UserDao.java中的add函数 UserService.java package cn.itcast.ioc; public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao= userDao; } public void add() { System.out.println("Service........"); userDao.add(); } } UserDao.java package cn.itcast.ioc; public class UserDao { public void add() { System.out.println("Dao........"); } } 然后在applicationContext.xml文件中使用以下方法给调用 1.png

优秀的个人博客,低调大师

Maven入门

1. Maven概念模型 图1.png 项目对象模型(Project Object Mobel) 通过pom.xml定义项目的坐标、项目依赖、项目信息、插件目标等。每个maven工程中都有一个pom.xml文件(核心配置文件),该文件里面定义了工程所依赖的jar包、本工程的坐标、打包运行方式等。 依赖管理系统(Dependency Management System) maven的基础核心,通过定义项目所依赖组件的坐标由maven进行依赖管理。也即maven通过坐标对项目工程所依赖的jar包进行统一规范的管理。 比如:项目依赖Struts2.3.24,通过在pom.xml中定义依赖即可将Struts2的jar包自动加入到工程中,pom.xml中定义依赖如下: <dependency> <groundId>org.apache.struts</groundId> <artifactId>struts2-core</artifactId> <version>2.3.24</version> </dependency> 一个项目生命周期(Project Lifecycle) 一个软件开发人员每天都在完成项目的生命周期:清理、编译、测试、部署,有的手工完成,有的通过Ant(也是一个项目构建工具)脚本自动完成,maven将项目的生命周期抽象统一为:清理、初始化、编译、测试、报告、打包、部署、站点生成等。 图2.png maven就是要保证一致的项目构建流程,通过执行一些简单命令即可实现上边生命周期的各个过程。 一组标准集合 maven将整个项目管理过程定义一组标准,比如:通过maven构建工程有标准的目录结构,有标准的生命周期阶段、依赖管理有标准的坐标定义等。 我在这儿还是强调一遍:maven工程有自己标准的工程目录结构、有标准的坐标定义。 插件(plugin)目标(goal) maven管理项目生命周期过程都是基于插件完成的。 2. maven的仓库 maven工作需要配置仓库,本地的项目A、项目B等通过maven从远程仓库(可以理解为互联网上的仓库)下载jar包并保存在本地仓库,本地仓库就是本地文件夹,当第二次需要此jar包时则不再从远程仓库下载,因为本地仓库已经存在了。可以将本地仓库理解为缓存,有了本地仓库就不用每次从远程仓库下载了。 下面描述了maven中仓库的类型: 图3.png 本地仓库:用来存储从远程仓库或中央仓库下载的插件和jar包,项目使用一些插件或jar包,优先从本地仓库查找。 远程仓库:如果本地需要插件或者jar包,本地仓库没有,默认从远程仓库下载。 中央仓库:在maven环境内部内置一个远程仓库地址:http://repo1.maven.org/maven2,它是中央仓库(即特殊的远程仓库),服务于整个互联网,它是由maven团队自己维护的,里面由大量的常用类库,并包含了世界上大部分流行的开源项目构件。 3. 安装 1). 下载和安装--下载地址 图4.png bin目录:mvn.bat(以run方式运行项目)、mvnDebug.bat(以debug方式运行项目) boot目录:maven运行需要的类加载器 conf目录:settings.xml,整个maven工具的核心配置文件 lib目录:maven运行依赖的jar包 2). 配置环境变量 I. 新建环境变量 图5.png II. 将 %MAVEN_HOME%\bin添加到path环境变量中 图6.png III. 测试 在命令提示符中输入命令-- mvn -v 图7.png 3). 本地仓库配置 本地仓库是用来存放联网下载的maven插件和jar包,maven本地仓库有的jar包将不再从互联网下载,所以本地仓库就相当于一个缓存。 在maven的安装目录中的conf目录下有一个settings.xml文件,在这个文件中可配置本地仓库 图8.png 如果本地仓库不配置(那么就会从互联网上下载jar包,而且下载速度贼慢),那么默认的本地仓库的位置就是{user.home}表示windows用户目录,在win7系统下如下: 图9.png 全局settings配置文件:就是maven的安装目录中的conf目录下的settings.xml文件。该文件里面的所有配置可应用于所有项目。 用户settings配置文件:在${user.home}/.m2/repository目录下。如果某些用户需要对maven特殊设置,用户可以自定义settings文件 4). eclipse配置maven安装程序 高版本的eclipse默认已经集成了maven的插件,但其实还内置了maven程序,Window->Preferences,搜索maven如下: 图10.png 注意:我们一般不用内置的maven程序,原因是为了在项目中统一maven版本 5). 选择指定的maven程序 点击Add...->>然后选择自己电脑中的maven程序->>点击Finish。 图11.png 然后勾选新增的一项。 图12.png 6). 指定User Settings 点击User Settings->点击Browse...选择settings.xml文件->点击Update Settings,在Local Repository一项会自动填充仓库位置->点击Apply->OK。 图13.png 7). Eclipse浏览本地仓库 Window->Show View->Other->Maven->Maven Repositories. 图14.png 4. 测试项目 1). 新建项目 I. File->Other->Maven->Maven Project->Next 图15.png II. 勾选Use default Workspace location是将工程创建在默认的路径下 图16.png III. 点击最后一项->Next 图17.png maven-archetype-quickstart: 普通Java工程 maven-archetype-webapp: Web工程 IV. 配置信息->点击Finish. 图18.png Group Id:项目的名称,项目名称以域名的倒序命名(类似java包名),比如我们要创建一个CRM的项目,可写为cn.itcast.crm。 Artifact Id:模块名称(子项目名称)。 Version:项目当中模块的版本,snapshot(快照版或测试版,没有正式发行)、release(正式发行版本)。 Package:包名。Group Id + Artifact Id. V. 解决错误 图19.png 错误原因:未Server Runtime.解决办法:邮件项目->Build Path->Configure Build Path...->Libraries->Add Library...->Next->apply.. 图20.png 图21.png VI. 项目结构 图21.png *注意:新创建的maven工程的目录结构不是一个完整的目录结构。 maven工程的一个完整的目录结构为: project /src/main/java 主体程序的java源文件(不要放配置文件) /src/main/resources 主体程序所需要的配置文件(不要放java文件) /src/test/java 单元测试程序的java源文件 /src/test/resources 单元测试程序所用的配置文件 /target 编译输出目录 /pom.xml 2). 配置 I. 设置maven的编译版本,由于我使用的是JDK1.8,所以要设置maven的编译版本为1.8,即要在maven工程的pom.xml文件中添加如下配置: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mazaiting.cmp</groupId> <artifactId>MavenTest</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>MavenTest Maven Webapp</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>MavenTest</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> </plugins> </build> </project> maven运行的时候都是依赖于插件的,包括编译也是需要通过插件——org.apache.maven.plugins(该插件就在你的本地仓库)来完成。 II. 添加完如上配置之后,可发现我们的maven工程上面有一个红叉,如下所示: 图22.png III. 更新项目。右键项目->Maven->Update Project... 图23.png

优秀的个人博客,低调大师

JSON入门

什么是JSON JSON:JavaScript Object Notation【JavaScript 对象表示法】 JSON 是存储和交换文本信息的语法。类似 XML。 JSON采用完全独立于任何程序语言的文本格式,使JSON成为理想的数据交换语言S 为什么需要JSON 提到JSON,我们就应该和XML来进行对比。XML也是一种存储和交换文本信息的手段。那么JSON好在哪里呢?? JSON 比 XML 更小、更快,更易解析。 javaScript原生支持JSON,解析速度会很快 XML解析成DOM对象的时候,浏览器【IE和fireFox】会有差异 使用JSON会更简单 更加容易创建JavaScript对象 var p = {'city':['北京','上海','广州','深圳']}; for(var i=0;i<p.city.length;i++){ document.write(p.city[i]+"<br/>"); } JSON语法 客户端与服务端的交互数据无非就是两种 数组 对象 于是乎,JSON所表示的数据要么就是对象,要么就是数组 JSON语法是javaScript语法的子集,javaScript用[]中括号来表示数组,用{}大括号来表示对象,JSON亦是如此 JSON数组: var employees = [ { "firstName":"Bill" , "lastName":"Gates" }, { "firstName":"George" , "lastName":"Bush" }, { "firstName":"Thomas" , "lastName": "Carter" } ]; JSON对象 var obj = { age: 20, str: "zhongfucheng", method: function () { alert("我爱学习"); } }; 当然啦,数组可以包含对象,在对象中也可以包含数组 解析JSON javaScript原生支持JSON的,我们可以使用eval()函数来解析JSON,把JSON文本数据转换成一个JavaScript对象。 function test() { //在写JOSN的时候,记得把带上逗号 var txt = "{a:123," + "b:'zhongfucheng'}"; //使用eval解析JSON字符串,需要增添() var aa = eval("(" + txt + ")"); alert(aa); } 效果 不用框架时将JavaBean转成JSON 使用Strus2的时候,Struts2自带了组件能够让JavaBean对象、集合转成是JSON,不用我们自己拼接...这是非常方便的。 使用SpringMVC的时候,SpringMVC也支持将JavaBean转成JSON 但是,我们不一定使用框架来做开发呀。因此,我们还得学习使用第三方库来将JavaBean对象、集合转成JSON 导入开发包 commons-io-2.0.1.jar commons-lang-2.5.jar commons-collections-3.1.jar commons-beanutils-1.7.0.jar ezmorph-1.0.3.jar json-lib-2.1-jdk15.jar 事例代码 package cn.itcast.javaee.js.bean2json; import net.sf.json.JSONArray; import java.util.*; /** * 使用第三方工具,将JavaBean对象/List或Set或Map对象转成JSON * @author AdminTC */ public class TestBean2Json { private static void javabean2json() { City city = new City(1,"广州"); JSONArray jSONArray = JSONArray.fromObject(city); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"}] } private static void list2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"广州")); cityList.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(cityList); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void set2json() { Set<City> citySet = new LinkedHashSet<City>(); citySet.add(new City(1,"广州")); citySet.add(new City(2,"珠海")); JSONArray jSONArray = JSONArray.fromObject(citySet); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"id":1,"name":"广州"},{"id":2,"name":"珠海"}] } private static void javabeanlist2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Province province = new Province(1,"广东",cityList); JSONArray jSONArray = JSONArray.fromObject(province); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); /* [ { "id":1, "name":"广东" "cityList":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}], } ] */ } private static void map2json() { List<City> cityList = new ArrayList<City>(); cityList.add(new City(1,"中山")); cityList.add(new City(2,"佛山")); Map<String,Object> map = new LinkedHashMap<String,Object>(); map.put("total",cityList.size());//表示集合的长度 map.put("rows",cityList);//rows表示集合 JSONArray jSONArray = JSONArray.fromObject(map); String jsonJAVA = jSONArray.toString(); System.out.println(jsonJAVA); //[{"total":2,"rows":[{"id":1,"name":"中山"},{"id":2,"name":"佛山"}]}] jsonJAVA = jsonJAVA.substring(1,jsonJAVA.length()-1); System.out.println(jsonJAVA); } } 把要解析成JSON 的javaBena对象、集合放进下面这段代码即可! JSONArray jSONArray = JSONArray.fromObject(map); 无论放进去什么,返回的都是数组 总结 作者:阿笨 官方QQ一群(已满):422315558 官方QQ二群(加入):574187616 个人讲师课堂主页:http://study.163.com/instructor/2544628.htm 个人微信公众号课程主页:http://dwz.cn/ABenNET

优秀的个人博客,低调大师

Gradle(入门

目录 Gradle 安装配置 SDKMAN方式 Chocolate 命令行选项 守护进程 构建依赖 dependency 常用插件 测试 第一个 build.gradle - 配置Gradle包管理器 Wrapper Gradle进阶知识 Gradle 构建块 task的依赖关系 终结器 task Groovy的POGO类管理配置文件上的版本号 增量式构建特性 task 的inputs 和 outputs 编写和使用自定义task 声明task规则 代码目录结构 Gradle 自动测试 自动化测试理论 测试java应用程序 项目布局,目录树 单元测试 使用JUnit 使用其他框架 TestNG Spock 配置测试执行 打包 War包 Jar包 集成测试 多模块构建 功能测试 Gradle插件 多语言编程 处理javascript 压缩javascript Java 和 Groovy的联合编译 Java 和 Scala Jenkin 使用 下载安装和配置 Gradle 安装配置 SDKMAN方式 先安装sdkman 使用Bash运行curl -s "https://get.sdkman.io" | bash sdk install gradle 即可安装 Chocolate windows 上安装 chocolate PowerShell中运行 wr https://chocolatey.org/install.ps1 -UseBasicParsing | iex 若操作系统默认禁止执行脚本,执行一次set-executionpolicy remotesigned后脚本顺利执行 Chocolatey在安装包的时候,默认路径是按照系统的默认路径来的,如果想修改安装路径可以这样处理: 执行“开始/运行”命令(或者WIN + R),输入“regedit”,打开注册表。 展开注册表到下面的分支[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion],在右侧窗口中找到名为“ProgramFilesDir”的字符串,双击把数值“C:\Program Files”修改为“D:\ProgramFiles”,确定退出后,即可更改常用软件的安装路径了。 命令行选项 gradle 构建文件中的task名: 直接运行task -b,--build-file test.gradle 指定运行脚本文件 --offline 离线模式 -P ,--project-prop:配置参数 -Pmyprop=value -i,--info : 打印info级别的输出 -s,--stacktrace: 输出错误栈 -q,--quiet:减少构建出错时打印的错误信息 tasks : 输出所有建立的task properties : 输出所有可用的配置属性 守护进程 命令加上 --daemon就会开启一个守护进程,只会开启一次, 守护进程会在空闲3小时后销毁 手动关闭 gadle --stop 构建时不采用守护进程 --no--daemon 构建依赖 dependency 和Maven用的是同一种方式 三个基本坐标 本地依赖 compile files('lib/ojdbc-14.jar') 相对的根目录是src同级目录 常用插件 lombok compile 'org.projectlombok:lombok:1.16.16' 测试 凡是依赖于本地环境的测试,使用完就注释Test注解,还有那些会CRUD,影响到数据的测试方法也是 以防以后线上测试通不过 第一个 build.gradle task helloworld{ doLast { printf 'Hello World!' } } 或者是 使用 << 代表doLast: task helloworld<<{ println 'Hello world!' } 运行:gradle -q helloworld 配置Gradle包管理器 Wrapper 在使用IDE生成项目的时候,可以选择gradle的执行目录,可以选gradle wrapper 也可以选自己下载解压的完整包 如果使用的不是这个wrapper,那么别人在下载项目后,运行gradle命令就要先安装gradle,使用wrapper更好 task wrapper(type: Wrapper){ gradleVersion = '1.7' distributionUrl = '限定访问内网的URL' distributionPath = '包装器被解压缩放的相对路径' } 运行 gradle wrapper 一次即可开始使用包装器的脚本来构建项目了 生成gradle包管理器:gradle wrapper --gradle-version 2.0 Gradle进阶知识 Gradle 构建块 三个基本块 project task property, 使用DDD(领域驱动设计) 一个真实的项目包含多个project 而 Project又包含多个task ,task之间通过依赖来确保执行顺序 build.gradle 和 pom.xml 作用是一致的,但是gradle可以使用一份源码 构建出多种想要的目标程序 gradle 也方便构建多模块项目 task的依赖关系 version = '0.1-SNAPSHOT' task first { println 'First Run !' } task second { println 'Second Run !' } task printVersion (dependsOn:[second,first]){ doLast { println "Version : $version" logger.quiet "Version : $version" } } task third <<{ println 'Third Run!' } third.dependsOn('printVersion') 如果把second的定义放在First前面,就会先运行second 这个例子就说明了,被依赖方的运行,不是按照声明的顺序,而是定义的顺序 (因为依赖是只要被依赖方执行即可,和顺序关系不是很大) 还可以使用SLF4J的logger实现 日志级别 DEBUG,ERROR,INFO,TRACE,WARN ,还有QUIET… 如果 是 gradle -b tasksL.gradle -q third 就会运行所有的task,因为这是最后一层依赖 如果 是gradle -b tasksL.gradle -q printVersion 就会只运行 printVersion 如果整个文件有编译错误也是不运行的 终结器 task task f<<{println 'first'} task s<<{println 'second'} f.finalizedBy s //当运行 gradle f 就会自动触发 s //如果gradle s 就和f没有任何关系了 Groovy的POGO类管理配置文件上的版本号 taskL.gradle gradle -b tasksL.gradle -q printVersion 虽然只是 运行了这个task 但是读取文件的task也被自动调用了 因为Gradle的构建生命周期阶段如下: 初始化、配置和执行 读取文件就属于配置阶段 注意 : 项目的每一次构建都会运行属于配置阶段的代码,即使你只是运行了 gradle tasks 增量式构建特性 如果Java源文件与最后一次运行的构建不同的话,运行 compileJava task 将充分提高构建的性能 task 的inputs 和 outputs 流程 : inputs -> |task| -> outputs gradle通过比较两个task的inputs和outputs来决定task是否最新 如果inputs和outputs没有改变 就不会执行该task 输入和输出可以是,一个文件,多个文件,一个目录,一个property属性 示例代码:turnVersion.gradle makeRealeseVersion : 将一个项目的版本切换为发布版本 IOReleaseVersion : 通过inputs/outputs来添加增量式构建支持 发现并不能得到书上的预期效果,书上是说改动了properties文件才会让这个task运行,没有改就会说 up-to-date 但是实际得到的是,改动了properties或者是构建文件都会引起task运行,两者都不改动就不会运行task,而且不会有输出提示up-to-date,要自己手动logger 编写和使用自定义task 自定义task包含两个组件: 自定义的task类,封装了逻辑行为,也被称为任务类型 真实的task 提供了用于配置行为的task类所暴露的属性值 这个task就是做到了改配置文件,确保是RELEASE版本 //先要实例化version属性对象的存在 version = new ProjectVersion(0,1,true) //继承DefaultTask类型的自定义task类 class ReleaseVersionTask extends DefaultTask{ @Input Boolean release @OutputFile File destFile ReleaseVersionTask(){ group = 'versioning' description = 'Make Project a release version' } //task的行为逻辑 @TaskAction void start (){ project.version.release = true; ant.propertyfile(file:destFile){ entry(key:'release',type:'string',operation:'=',value:'true') } println "$project.version" } } //version的POGO类 class ProjectVersion{ Integer major Integer minor Boolean release ProjectVersion (Integer major ,Integer minor){ this.major = major this.minor = minor } ProjectVersion (Integer major ,Integer minor,Boolean release){ this(major,minor) this.release = release } @Override String toString(){ "$major.$minor${release?'-RELEASE':'-SNAPSHOT'}" } } //真实的task,用来操作自定义类暴露的几个属性 //使用命令来运行,本质是运行真实的task但是行为逻辑在自定义类中编写 //gradle -b UserDefineTask.gradle -q makeReleaseVersion //如果要改动一些数据可以直接更改暴露的task而不用去改自定义的task类 task makeReleaseVersion(type:ReleaseVersionTask){ release = 'true' destFile = file('version.properties') } 书上写的不完全,调试要死人 声明task规则 //All used property must define and initial first version = new ProjectVersion(0,1,true) ext.versionFile = file('version.properties') class ProjectVersion{ Integer major Integer minor Boolean release ProjectVersion (Integer major ,Integer minor){ this.major = major this.minor = minor } ProjectVersion (Integer major ,Integer minor,Boolean release){ this(major,minor) this.release = release } @Override String toString(){ "$major.$minor${release?'-RELEASE':'-SNAPSHOT'}" } } // task规则的定义 tasks.addRule("Pattern: increment<Classifier>Version - Increment the project version classifier." ){ //根据预定义模式来检查task的名称 String taskName -> if(taskName.startsWith('increment') && taskName.endsWith('Version')){ //根据符合命名模式的task动态添加一个doLast的方法 task(taskName)<<{ //从完整的task名称中提取类型字符串, //字面意思是将字符串中increment和Version两个串去除掉然后转小写再赋值 String classifier = (taskName - 'increment' - 'Version').toLowerCase() String currentVersion = version.toString() switch (classifier){ case 'major':++version.major break case 'minor':++version.minor break default : throw new GradleException("Invalid version type '$classifier' . Allow types :['Major','Minor']") } String newVersion = version.toString() logger.info "Increment $classifier project version: $currentVersion -> $newVersion" ant.propertyfile(file:versionFile){ entry(key:classifier,type:'int',operation:'+',value:1) } } } } 运行 gradle -b RulesTask.gradle -q incrementMinorVersion就可以增加版本号了,就是一个动态的执行命令的机制 使用 incrementMajorVersion就可以增加主版本号 如果运行 gradle -b RulesTask.gradle -q tasks 就会得到一个具体的tasks的组Rules 代码目录结构 groovy 在以下目录,Java在main.java的目录下,一般别人直接放在src下,buildSrc好像没有普及使用 - build.gradle - buildSrc - src - main - groovy - com - myth - test - ProjectVersion.groovy - java - src - version.properties 测试优于业务逻辑实行 Gradle 自动测试 自动化测试理论 测试java应用程序 项目布局,目录树 单元测试 使用JUnit 使用其他框架 TestNG Spock 配置测试执行 打包 War包 Jar包 Gradle默认是只会打包源码,并不会打包依赖(为了更方便依赖的作用) shadow插件官网文档 集成测试 多模块构建 树级结构的多模块项目就这样配置 - RedisClient - Core - Website rootProject.name = 'RedisClient' include 'Core','Website' 如果只是同级的目录,就直接新建,无需配置,引用类时添加下依赖即可,但是这样只能运行,不能打包构建 有关多模块的构建详情参考这里 参考更为规范的多项目构建 统一一个文件管理依赖 依赖另一个模块的代码 compile project(":redis_core") 功能测试 Gradle插件 shadowJar 多语言编程 处理javascript 压缩javascript 调用Google Closure Compiler 的task 来压缩javascript文件 将所有的javascript压缩成一个javascript文件 执行该task gradle :web :taskname 执行之后就能得到一个优化的js文件,现在就要在页面中修改原来的js引用 Java 和 Groovy的联合编译 src 下 main 下 java 和groovy 的一个目录结构,直接编译就会发生Java无法依赖groovy的类 错误:需要配置 sourceSets.main.java.srcDirs=[] sourceSets.main.groovy.srcDirs=['src/main/java','src/main/groovy'] 正确: sourceSets.main.java.srcDirs=['src/main/java','src/main/groovy'] 上面的会报错 配置好后就能把groovy当普通Java类直接使用了 Java 和 Scala 联合双向编译 Java和scala sourceSets.main.scala.srcDirs sourceSets.main.groovy.srcDirs=['src/main/java','src/main/scala'] 那么问题来了,如果是有了java groovy scala 呢怎么配置编译,直接就加上就好了嘛? Jenkin 使用 下载安装和配置 官网下载war包后,直接使用Java命令运行 或者放在web容器中运行 配置下载插件(位置在C盘用户目录下, 其实第一次运行后也是会解压在.jenkin 目录下 插件就在plugin目录下)

优秀的个人博客,低调大师

Python入门

Python 简介 关于Python2.x与3.x的使用 摘自 Python核心编程 第三版 Wesley Chun著 print 变为 print() 默认字符的编码是 Unicode 增加单类 类型 更新异常的语法 更新了整数 迭代无处不在 【基础数据类型】 数值类型 整数 各种进制 0 八 0x 十六 0b 二 浮点数 1.2e2 13.34e-2 复数 3+4j 0.1-0.5j 布尔型 0或0.0 :看成false "" '' :false () [] {} :false 字符串 单引号 双引号: 单行字符串 三引号 多行字符串 空值 None 运算符 算术运算符 加减一样,* 乘,不仅可以用于数字,还可以用于字符串 ,/ 除,和Java不一样,整数相除也会得到浮点数 // 取整除,得到商的整数部分 ,% 取余数 ,** 幂运算 可以用来开根 关系运算符 都是和Java一致 逻辑运算符 and or not 身份运算符 is : a is b 就是比较 id(a) id(b) 相同则是返回1 is not 比较id 不相同返回1 位运算符 << >> 左右移 & |按位与或 ^ ~ 按位异或 按位翻转 算术运算符优先级 ** / // % + // 取整数部分除法 ** 幂运算 转义字符: \a 响铃 \b 退格 backspace \000 空 \f 换页 \ 续行符(行尾) 【基础语法】 单行注释:# 多行注释:”’ ”’ 空行的重要性,代码段之间有空行,Python之禅 【import】 参考博客 关于同级,子级目录是比较方便的,涉及到上级目录的就麻烦点了 【输入输出】 读取命令行参数 参考博客 只有输入参数,没有选项 import sys print("脚本名:", sys.argv[0]) for i in range(1, len(sys.argv)): print("参数", i, sys.argv[i]) python tree.py hi op 顺序是python,第一个参数是文件,之后才是别的参数 结果>> 脚本名 tree.py 参数1 hi 参数2 op 有选项 getopt.getopt(args, options[, long_options]) import sys, getopt opts, args = getopt.getopt(sys.argv[1:], "hi:o:") for op, value in opts: sys.argv[1:]为要处理的参数列表,sys.argv[0]为脚本名,所以用sys.argv[1:]过滤掉脚本名。 "hi:o:": 当一个选项只是表示开关状态时,即后面不带附加参数时,在分析串中写入选项字符。当选项后面是带一个附加参数时,在分析串中写入选项字符同时后面加一个”:”号。 所以”hi:o:”就表示”h”是一个开关选项(单单的-h);”i:”和”o:”则表示后面应该带一个参数。 调用getopt函数。函数返回两个列表:opts和args。opts为分析出的格式信息。args为不属于格式信息的剩余的命令行参数。 opts是一个两元组的列表。每个元素为:(选项串,附加参数)。如果没有附加参数则为空串”。 getopt函数的第三个参数[, long_options]为可选的长选项参数,上面例子中的都为短选项(如-i -o) 长选项格式举例: --version --file=error.txt 让一个脚本同时支持短选项和长选项 getopt.getopt(sys.argv[1:], "hi:o:", ["version", "file="]) 【序列】 序列通用操作(包含:字符串,列表,元组) - ​索引,从左至右:0,1,2...n 从右至左:-1,-2...-n - 切片(截取序列的部分) temp[:] 返回一个副本 - temp[2:4]就是[2,4) - temp[1:]1到最后 temp[-3:] [-3,-1] - temp[:4] [0,4) temp[:-3] [0,-3] - 加:lista+listb 直接连接 - 乘:lista*4 - 判断是否存在:in not int - len() - min() max() sum() 要求元素全是数值 【列表】 元素可包含 字符串,浮点,整型,列表,布尔 操作: 增加 + ,append()/extend()尾部加入元素/列表 insert(index, "") 元素插入到任意位置,其后元素后移 检索 count() in 删除 :del list[2]/ remove("apple") /pop(index) index为空指最后一个 永久性排序:sort() a-z sort(reverse=True) z-a 列表全是字符串才可 临时性排序:sorted() 也可以使用上面的参数 列表全是字符串才可 永久性的逆序列表:reverse() 类似数组的操作,例如声明数组:参考博客 原始的定义就是 lists = [1, 2, 4] 若要定义连续列表 lists = range(0, 100) 得到的是range对象不是列表对象 若要定义大小1000全为0列表 lists = [0 for x in range(0, 1000)] 二维数组的定义: 原始: lists = [[1, 2], [3, 4]] 仿造一维的定义: lists = [[0 for x in range(10)] for y in range(10)] 10*10 初始为0的列表 简便但是不可行的方法: lists = [[0]*10]*10 这是个坑, 只是声明了一维数组,然后多次引用, 虽然看起来是二维, 引用数据就会发现是一维 【元组】 元组和列表类似但是元组是创建不可更改的 和列表相比,相同点:按定义的顺序排序,负索引一致,可以使用分片 不同点:元组使用的是(),不能增加删除元素,没有index方法但是有in,可以在字典中作为键列表不可以, 由于具有写保护,代码安全,操作速度略快列表 操作: 访问: 和列表一样的索引和分片, 连接:+ 连接得到新的元组 删除:del 删除整个元组 【字符串】 str() 将对象转化成字符串 (注:Python中不能像Java一样字符串和数值直接+) repr() 注意和str()的区别 r"d:\python27\" r前缀表示转义字符看成普通字符 因为Python字符串实现是类似字符数组,temp = "python" temp[0] 结果:p temp.index("p") 结果是:0 操作: index('s') 找到s字符的下标 find('s',[start,end]) 找s的下标,只有一个整数参数则是start replace('s','v') 替换 count('sd') 计数 split('') 正则切分 空参数默认是空格 join('') 列表转化成字符串的方法 cmp(str1,str2) 比较两个字符串是否相等 + 进行拼接 可以拼接字符串 列表 a in b 判断a是否在b里存在 * 重复序列 例如 print "-"*20 就会输出20个 - b = "www.github.com" c = b.split(".") "#".join(c) 实现了将字符串的 . 换成了# "i am %s %d" % ("python",67)%s %d %f 和C语言一样占位符 新的方式 "i am {0} {1} ..".format(23,"ret") 或者"i am {name} {age} ..".format(age=23,name="ret") 字典方式 title() 首字母大写 字符串,列表,元组相互转换: - 字符串-列表 : list(“python”) - 字符串-元组:tuple(“python”) - 列表或元组-字符串 join(obj) 参数是列表或元组类型,其元素只能是字符串类型 字符串编码问题(python 2问题): Python 3的bytes/str之别 encode("utf-8"): str -> bytes decode(): bytes -> str # coding:utf-8 unicode_str = unicode('使用',encoding='utf-8') print unicode_str.encode('utf-8') import codecs codecs.open('filename',encoding='utf-8') 因为文件不是UTF8:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb9 in position 2: invalid start byte 字典(键值对) 通过用空间来换取时间,与列表相比,键的增加不影响查找插入速度,需要占用大量内存 特性: 值是可以是任意的,甚至是字典嵌套 键必须不可变,只能由 数值,字符串,元组,不能用列表 操作: 定义字典 dict={} 添加 : dict['a'] = 2323 返回所有key:keys() 查询是否有这个键 :has_key() get() keys() values() 转化元组并返回 :items() 删除指定键:del() del dict['name'] 删除所有:clear() 删除指定键并返回值 :pop() 合并另一个字典:update() in 嵌套: 字典套列表 {'d':['we','e']} 列表套字典,当成普通类型包含即可 字典套字典 【基本运行结构】 输入输出: input(“”) 默认当成字符串输入 数值:int() 强转一下 print(“”) 选择: if elif else for循环: for in while 例如:for i in range(1,10,2): 范围 [1,10) 增量为2 pass 语句,当某个子句没有任何操作,,用pass保持程序结构完整性 不影响下一句 不像continue while 循环; while True:`` while ‘2’ in nums:`` while num<2: while 列表: 直到列表为空退出循环 if (b==0) and (a==1) : pass print("pass") else: print("Hi") 【函数】 形参赋值传递方式 按位置 就是直接用看起来和Java一样,但不是按类型和位置,只是位置 按指定名称 调用的时候 create(name='df') 缺省默认值(参数缺省之后,调用可以不传这个参数,否则必须要传) def create(name='df') 列表类型,不想形参改变实参 传递副本过去即可 list[:] 以下两种情况(* 和 **),都必须放在形参列表的最后 (两者同时使用时:* 只能在 ** 前 ) 多个实参 create(age, *name) create(12, 's','d') 所以这是名为name的元组 不能指定没有的名称 错误:create(12,d=2, 2,3,4) 多个指定名称实参 create(age, **name) create(12, name='d', lo=23) 必须要指定名称 这是名为name的键值对字典 错误:create(12,d=23,3,3,3) 注意: def hi(name, age=0, *names, **s) hi('d', 23,34, d=6) age会被赋值23 def hi(name, *names, age=0, **s) hi('d', 23,34, d=6) 这样写age就不会赋值,除非指定名称 age=23 返回值 返不返回 看需求 没有像Java一样的强制性约束类型 将函数写在一个py文件里,然后导入 import 文件名,名曰导入模块 还可以加别名 import creat as fun 给模块加别名 导入指定的函数 from create import create_aliens, type_button 多个就,分隔 同理 as给函数加别名 * 通配所有 注意:递归深度,Python中递归默认深度是 989, 要么更改实现,要么就 sys.setrecursionlimit(10000000) 变量 局部变量: 全局变量:定义在函数外的变量,也称公用变量,函数中 global x 声明引用全局变量x 【类】 Python 不存在多态,存在鸭子类型 博客介绍 - 写在一个py文件里,默认构造器,可以加参数 def __init__(self): 属性: 实例属性 形如self.name,在任何方法中声明过即可 类属性 不加self前缀,__name私有的类属性, 类不能访问对象属性 类属性可以修改,但是实际上只能修改实例属性(这个修改只是声明了同名的实例属性,引用的时候就会覆盖类属性,看起来就是修改了 可以删除实例属性,然后就能看到原有的类属性了 class People: name = 'md' p = People() p.name = 'gh' # 声明了实例属性覆盖了类属性 del p.name # 删除实例属性,恢复类属性引用 方法: 对象方法,类方法,静态方法 对象方法,同样的 __开头是私有的,只能在对象的公有方法中self.__引用 静态方法,之中只能引用类成员,不能访问对象成员 构造函数和析构函数: def __init__(self) def __del__(self) class Person: # 对象方法, 将对象作为参数self传进去 def say(self): print('hi') # 静态方法 @staticmethod def drink(): print('static method') # 类方法,将类作为参数cls传进去 @classmethod def eat(cls): print('class method') self 代表了自身引用 类似Java的this 特别不舒服 init 这种命名 不像Java的构造函数重载,这个就是后面覆盖前面定义的init 不管形参列表 因为不存在重载,就是说不能多个构造函数的书写了。。。 导入和函数一样 注意继承中类的依赖 继承 Python是支持多重继承的 同文件 父类定义要在子类之前 父类的构造器不会自动调用,需要显式使用父类构造器: 2.×版本: super(子类名, self).__init__(参数) 3.×版本: super().__init__(参数) 或者 父类名.__init__() 重写父类方法:只需要定义一个和父类方法同名的方法即可,因为没有多态,覆盖时形参不作考虑 多态: 方法重载: 子类覆盖父类的方法 运算符重载: 加__add__(self, x) 减__sub__(self, x) 【异常】 try: print(5/0) except ZeroDivisionError: print("0 不能做除数") else: print("成功") finally: print('finally') 基本语法 try except else finally else是无异常执行 有异常就执行 except, except 超类Exception,也可以多个except (和Java一致) 最终执行finally 和 Java的结构是一致的 except 分句使用形式 说明 except 捕获所有类型 except name 只捕获指定类型 except name, value 捕获指定类型,并获得抛出的异常对象 except (name1, name2) 捕获列出的异常 except (name1, name2), value 捕获列出的异常,获得抛出的异常对象 - raise 语句 和Java的throw关键字 一致 , 不过raise只是抛出一个通用异常类型 Exception - dir(exceptions) 查看所有异常类型 - raise name 手动引发异常 - raise name,data 传递一个附加的数据 - 同样的也是可以自定义异常类型的,class MyExcetion(Exception): - with 语句 在异常处理中,将 try except finally 关键字以及与资源分配释放相关的代码省略掉。 - 文件打开 with open('a.py') as files: 常见异常类 描述 NameError/UnboundLocalError 引用不存在的变量/或者引用在声明之前 ZeroDivisionError 除数为0 SyntaxError 语法错误 IndexError 索引错误 KeyError 使用不存在的字典关键字 IOError 输入输出错误 ValueError 搜索列表中不存在的值 AtrributeError 调用不存在的方法 TypeError 未强制转换就混用数据类型 EOPError 文件结束标识错误 【文件】 注意路径,Windows系统中要使用反斜杠 \ 最简单:file = open('') 只读打开 使用with来操作 好处是Python自动关闭文件 with open('filename') as name: name.read() 为写打开新文本文件只读 file = open('a.txt','w+'[,coding='utf-8']) 打开删空 file.write('') os模块 os.rename('filename1','filename2') mv os.remove('filename.py') rm os.listdir(path) ls os.getcwd() pwd os.makedirs(r'path') mkdir os.chdir('') 改变一个目录 os.rmdir('') 删除该目录,前提是空目录 os.path模块 abspath(”) 获取绝对路径 exists(”) 是否存在 isdir(”) 是否是一个目录 isfile(”) 是否是文件 islink(”) 是否是软链接硬链接文件 getsize() 获取文件尺寸 shutil模块 dir() 复制单个文件 shultil.copytree(r”,r”) 复制目录树 b 表示字节流(二进制文件) 不加表示字符流(文本文件) 方式 意义 当存在 当不存在 r 只读打开 打开 返回空指针 w 只写打开新 打开删空 新建打开 a 追加打开 打开 新建打开 r+ 读打开可写 打开 返回空指针 w+ 写打开新可读 打开删空 新建打开 a+ 追加打开可读 打开 新建打开 rb 只读打开 打开 返回空指针 wb 只写打开新 打开删空 新建打开 ab 追加打开 打开 新建打开 rb+ 读打开可写 打开 返回空指针 wb+ 写打开新可读 打开删空 新建打开 ab+ 追加打开可读 打开 新建打开 json alien = {'color': 'green', 'age': '23'} files = 'a.json' with open(files, 'w') as o: json.dump(alien, o) data = json.load(files) # 引用 data['root']['name'] json.dump()持久化 和 load() 装载 【测试】 文件名test开头就当做是测试类,不会直接运行 类继承 unittest.TestCase, 所有test_开头的方法都将自动运行 断言 self.assertEqual assertNotEquals assertIn(item, list) 直接运行 unittest.main() 输出结果,. 测试通过 E 测试运行错误 F 测试断言不通过 【GUI】 Tkinter 安装 - python2: sudo apt install python-tk - python3: sudo apt install python3-tk 引入 - python2:import Tkinter import Tkinter as tk from Tkinter import * - 但是python3.5的环境下,import tkinter 才是正确的 wxPython Qt5 【数据库】 【MySQL】 python3环境下: sudo apt install python3-mysqldb sudo apt install libmysqlclient-dev sudo pip install mysql-python 【Redis】 安装 python2 sudo pip install redis python3 sudo pip3 install redis 使用 使用的接口方法是和redis一样的 Redis笔记传送门 【绘图】 matplotlib python 3.5 安装 sudo apt install python3-matplotlib sudo apt install python3.5-dev python3.5-tk tk-dev sudo apt install libfreetype6-dev g++ 【代码风格】 一行只写一句 表达式尽量不要省略括号,有助于理解 函数的行数不要超过100行 尽量使用系统函数 尽量使用局部变量,不要使用全局 循环,分支,最好不要超过5层 尽量减少否定的条件语句 对输入的数据进行合法性检查 巨坑: tab和空格不能混用,如果你复制别人的代码是tab,自己敲空格,就会缩进错误!!!!, 天灭tab空格保平安, 要不是kate编辑器显示了tab字符,找半天都不知道错在哪 【常见函数】 id() 查看内存地址 help(方法名) 展示方法的说明文档 dir(对象) 展示对象的方法API 【常见库】 import codecs 编码 import os import time import shlex import datetime import subprocess def execute_command(cmdstring, cwd=None, timeout=None, shell=False): """执行一个SHELL命令 封装了subprocess的Popen方法, 支持超时判断,支持读取stdout和stderr 参数: cwd: 运行命令时更改路径,如果被设定,子进程会直接先更改当前路径到cwd timeout: 超时时间,秒,支持小数,精度0.1秒 shell: 是否通过shell运行 Returns: return_code Raises: Exception: 执行超时""" if shell: cmdstring_list = cmdstring else: cmdstring_list = shlex.split(cmdstring) if timeout: end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout) #没有指定标准输出和错误输出的管道,因此会打印到屏幕上; sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,bufsize=4096) #subprocess.poll()方法:检查子进程是否结束了,如果结束了,设定并返回码,放在subprocess.returncode变量中 while sub.poll() is None: time.sleep(0.1) if timeout: if end_time <= datetime.datetime.now(): raise Exception("Timeout:%s"%cmdstring) return str(sub.returncode) QT 在Terminal中输入:sudo apt-get install qt4-dev-tools qt4-doc qt4-qtconfig qt4-demos qt4-designer qt4-dev-tools 中包括了Qt Assistant,Qt Linguist,Qt Creator qt4-doc 这个是帮助文档 qt4-qtconfig Qt的配置工具,这个装好默认好 qt4-demos 官方的一些Demo qt4-designer 可视化窗体设置工具

优秀的个人博客,低调大师

Ansible入门

Ansible简介 ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。主要包括: (1)、连接插件connection plugins:负责和被监控端实现通信; (2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机; (3)、各种模块核心模块、command模块、自定义模块; (4)、借助于插件完成记录日志邮件等功能; (5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。 通过Apt (Ubuntu)安装最新发布版本 root@storage:~# apt-add-repository ppa:ansible/ansible Ansible is a radically simple IT automation platform that makes your applications and systems easier to deploy. Avoid writing scripts or custom code to deploy and update your applications— automate in a language that approaches plain English, using SSH, with no agents to install on remote systems. http://ansible.com/ More info: https://launchpad.net/~ansible/+archive/ubuntu/ansible Press [ENTER] to continue or ctrl-c to cancel adding it gpg: keyring `/tmp/tmpi636boen/secring.gpg' created gpg: keyring `/tmp/tmpi636boen/pubring.gpg' created gpg: requesting key 7BB9C367 from hkp server keyserver.ubuntu.com gpg: /tmp/tmpi636boen/trustdb.gpg: trustdb created gpg: key 7BB9C367: public key "Launchpad PPA for Ansible, Inc." imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) OK root@storage:~# apt-get update -y root@storage:~# apt-get install ansible -y 配置 无密码访问 root@storage:/etc/ansible# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: SHA256:rSrNWrBMLzr7gUUqVZZUQU+bUYiVVoqev37/r3Xfmck root@storage The key's randomart image is: +---[RSA 2048]----+ | .+++++=o | | o. .++= | | . . ..= | | . o . . . | |. . + o S . | | . = + . . | | . =oo o o| | ...+o. .. ..B| | o+oo..o. ...oE+| +----[SHA256]-----+ root@storage:/etc/ansible# ssh-copy-id 192.168.13.143 root@storage:/etc/ansible# ssh-copy-id 192.168.13.144 root@storage:~# vim /etc/ansible/hosts 192.168.13.143 192.168.13.144 [openstack] #主机组:openstack 192.168.13.30 192.168.13.33 192.168.13.45 简单测试1 root@storage:~# ansible all -m ping 192.168.13.143 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.13.144 | SUCCESS => { "changed": false, "ping": "pong" } 简单测试2 root@storage:~# ansible all -m command -a 'uptime' 192.168.13.144 | SUCCESS | rc=0 >> 07:39:00 up 6:02, 2 users, load average: 0.00, 0.00, 0.00 192.168.13.143 | SUCCESS | rc=0 >> 07:39:00 up 5:58, 2 users, load average: 0.06, 0.03, 0.01 root@storage:~# ansible openstack -m command -a 'uptime' 192.168.13.33 | SUCCESS | rc=0 >> 15:43:18 up 4 days, 1:38, 1 user, load average: 0.30, 0.26, 0.30 192.168.13.45 | SUCCESS | rc=0 >> 15:43:27 up 13 days, 1:08, 1 user, load average: 0.12, 0.08, 0.08 192.168.13.30 | SUCCESS | rc=0 >> 15:43:27 up 26 days, 1:39, 2 users, load average: 10.40, 10.49, 10.24 root@storage:~# 常用模块介绍 1、setup:用来查看远程主机的一些基本信息 root@storage:~# ansible openstack -m setup |more 2、ping:用来测试远程主机的运行状态 root@storage:~# ansible openstack -m ping 3、file:设置文件的属性 file选项如下: force:需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no group:定义文件/目录的属组 mode:定义文件/目录的权限 owner:定义文件/目录的属主 path:必选项,定义文件/目录的路径 recurse:递归设置文件的属性,只对目录有效 src:被链接的源文件路径,只应用于state=link的情况 dest:被链接到的路径,只应用于state=link的情况 state: directory:如果目录不存在,就创建目录 file:即使文件不存在,也不会被创建 link:创建软链接 hard:创建硬链接 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 absent:删除目录、文件或者取消链接文件 root@storage:# ansible openstack -m file -a 'src=/etc/resolv.conf dest=/home/resolv.conf state=link' 192.168.13.33 | SUCCESS => { "changed": true, "dest": "/home/resolv.conf", "gid": 0, "group": "root", "mode": "0777", "owner": "root", "size": 16, "src": "/etc/resolv.conf", "state": "link", "uid": 0 } 查看执行结果:-m command 在远端执行命令 root@storage:~# ansible openstack -m command -a 'ls /home' root@storage:~# ansible openstack -m command -a 'ls /home' 192.168.13.33 | SUCCESS | rc=0 >> andy resolv.conf root@storage:~# ansible openstack -m file -a 'path=/home/resolv.conf state=absent' root@storage:~# ansible openstack -m file -a 'path=/home/resolv.conf state=absent' 192.168.13.45 | SUCCESS => { "changed": true, "path": "/home/resolv.conf", "state": "absent" } 4、copy:复制文件到远程主机 相关选项如下: backup:在覆盖之前,将源文件备份,备份文件包含时间信息。有两个选项:yes|no content:用于替代“src”,可以直接设定指定文件的值 dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 directory_mode:递归设定目录的权限,默认为系统默认权限 force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes others:所有的file模块里的选项都可以在这里使用 src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用“/”来结尾,则只复制目录里的内容,如果没有使用“/”来结尾,则包含目录在内的整个内容全部复制,类似于rsync。 root@storage:~# ansible openstack -m copy -a 'src=/root/aa.txt dest=/tmp' 5、command:在远端主机上执行命令 相关选项如下: creates:一个文件名,当该文件存在,则该命令不执行 free_form:要执行的linux指令 chdir:在执行指令之前,先切换到该目录 removes:一个文件名,当该文件不存在,则该选项不执行 executable:切换shell来执行指令,该执行路径必须是一个绝对路径 #ansible openstack -m command -a 'uptime' root@storage:~# ansible openstack -m command -a 'uptime' 192.168.13.30 | SUCCESS | rc=0 >> 16:11:43 up 27 days, 2:08, 3 users, load average: 7.11, 7.81, 8.92 6、shell:切换到某个shell执行指定的命令,参数与command相同 与command不同的是,此模块可以支持命令管道,同时还有另一个模块也具备此功能:raw root@storage:~# vim data.sh root@storage:~# date +%F_%H:%M:%S 2016-08-24_08:16:50 root@storage:~# chmod +x data.sh root@storage:~# ansible openstack -m copy -a 'src=/root/data.sh dest=/tmp owner=root group=root mode=0755' 192.168.13.30 | SUCCESS => { "changed": true, "checksum": "a0c5ebf2b8c213d26a864ff89b381afc2b1eb901", "dest": "/tmp/data.sh", "gid": 0, "group": "root", "md5sum": "159569349be4db486945c106d187ea4a", "mode": "0755", "owner": "root", "size": 30, "src": "/root/.ansible/tmp/ansible-tmp-1472026735.85-123460492539355/source", "state": "file", "uid": 0 } root@storage:~# ansible openstack -m command -a 'ls -l /tmp/data.sh' 192.168.13.30 | SUCCESS | rc=0 >> -rwxr-xr-x 1 root root 30 Aug 24 16:18 /tmp/data.sh root@storage:~# ansible openstack -m shell -a '/tmp/data.sh' 192.168.13.30 | SUCCESS | rc=0 >> 2016-08-24_16:20:00 7、其它模块 其他常用模块,比如:service、cron、yum、synchronize就不一一例举,可以结合自身的系统环境进行测试。 service:系统服务管理 cron:计划任务管理 yum:yum软件包安装管理 synchronize:使用rsync同步文件 user:系统用户管理 group:系统用户组管理 更多模块可以参考: 本文转自 OpenStack2015 博客,原文链接:http://blog.51cto.com/andyliu/1842081 如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册