diff --git a/docs/tools/latex.md "b/docs/enginering/03-\347\274\226\347\250\213\350\257\255\350\250\200/latex.md" similarity index 100% rename from docs/tools/latex.md rename to "docs/enginering/03-\347\274\226\347\250\213\350\257\255\350\250\200/latex.md" diff --git "a/docs/enginering/45\344\270\252\345\260\217\346\212\200\345\267\247\344\274\230\345\214\226\344\273\243\347\240\201.md" "b/docs/enginering/45\344\270\252\345\260\217\346\212\200\345\267\247\344\274\230\345\214\226\344\273\243\347\240\201.md" deleted file mode 100644 index 24ed0a7..0000000 --- "a/docs/enginering/45\344\270\252\345\260\217\346\212\200\345\267\247\344\274\230\345\214\226\344\273\243\347\240\201.md" +++ /dev/null @@ -1,912 +0,0 @@ ---- -tags: - - 产品设计 -author: zhiminbai -date created: 2022-11-14 15:43 ---- - -本文我就从代码的编写规范,格式的优化,设计原则和一些常见的代码优化的技巧等方面总结了了45个小技巧分享给大家,如果不足,欢迎指正。 - -![图片](../enginering/images/45-ways-1.png) - -## 1、规范命名 - -命名是写代码中最频繁的操作,比如类、属性、方法、参数等。好的名字应当能遵循以下几点: - -###### 见名知意 - -比如需要定义一个变量需要来计数 - -```java -int i = 0; -``` -名称 i 没有任何的实际意义,没有体现出数量的意思,所以我们应当指明数量的名称 - -```java -int count = 0; -``` -###### 能够读的出来 - -如下代码: - -```java -private String sfzh; -private String dhhm; -``` - -这些变量的名称,根本读不出来,更别说实际意义了。 - -所以我们可以使用正确的可以读出来的英文来命名 - -```java -private String idCardNo; -private String phone; -``` - -## 2、规范代码格式 - -好的代码格式能够让人感觉看起来代码更加舒适。 - -好的代码格式应当遵守以下几点: - -- 合适的空格 -- 代码对齐,比如大括号要对齐 -- 及时换行,一行不要写太多代码 - -好在现在开发工具支持一键格式化,可以帮助美化代码格式。 - -## 3、写好代码注释 - -在《代码简洁之道》这本书中作者提到了一个观点,注释的恰当用法是用来弥补我们在用代码表达意图时的失败。换句话说,当无法通过读代码来了解代码所表达的意思的时候,就需要用注释来说明。 - -作者之所以这么说,是因为作者觉得随着时间的推移,代码可能会变动,如果不及时更新注释,那么注释就容易产生误导,偏离代码的实际意义。而不及时更新注释的原因是,程序员不喜欢写注释。(作者很懂啊) - -但是这不意味着可以不写注释,当通过代码如果无法表达意思的时候,就需要注释,比如如下代码 - -```java -for (Integer id : ids) { -     if (id == 0) { -      continue; - }      - //做其他事 -} -``` - - -为什么 id == 0 需要跳过,代码是无法看出来了,就需要注释了。 - -好的注释应当满足一下几点: - -- 解释代码的意图,说明为什么这么写,用来做什么 - -- 对参数和返回值注释,入参代表什么,出参代表什么 - -- 有警示作用,比如说入参不能为空,或者代码是不是有坑 - -- 当代码还未完成时可以使用 todo 注释来注释 - -## 4、try catch 内部代码抽成一个方法 - -try catch代码有时会干扰我们阅读核心的代码逻辑,这时就可以把try catch内部主逻辑抽离成一个单独的方法 - -如下图是Eureka服务端源码中服务下线的实现中的一段代码 - -![图片](../enginering/images/45-ways-2.png) - -整个方法非常长,try中代码是真正的服务下线的代码实现,finally可以保证读锁最终一定可以释放。 - -所以这段代码其实就可以对核心的逻辑进行抽取。 - -```JAVA -protected boolean internalCancel(String appName, String id, boolean isReplication) { -     try { -              read.lock();          -              doInternalCancel(appName, id, isReplication); -       }  - finally { -         read.unlock(); - } - // 剩余代码 - } - private boolean doInternalCancel(String appName, String id, boolean isReplication)  {      - //真正处理下线的逻辑 - } -``` - -## 5、方法别太长 - -方法别太长就是字面的意思。一旦代码太长,给人的第一眼感觉就很复杂,让人不想读下去;同时方法太长的代码可能读起来容易让人摸不着头脑,不知道哪一些代码是同一个业务的功能。 - -我曾经就遇到过一个方法写了2000+行,各种if else判断,我光理清代码思路就用了很久,最终理清之后,就用策略模式给重构了。 - -所以一旦方法过长,可以尝试将相同业务功能的代码单独抽取一个方法,最后在主方法中调用即可。 - -## 6、抽取重复代码 - -当一份代码重复出现在程序的多处地方,就会造成程序又臭又长,当这份代码的结构要修改时,每一处出现这份代码的地方都得修改,导致程序的扩展性很差。 - -所以一般遇到这种情况,可以抽取成一个工具类,还可以抽成一个公共的父类。 - -## 7、多用return - -在有时我们平时写代码的情况可能会出现if条件套if的情况,当if条件过多的时候可能会出现如下情况: - -```java -if (条件1) { - if (条件2) { - if (条件3) { - if (条件4) { - if (条件5) { - System.out.println("三友的java日记"); - } - } - } - } -} - -``` - - -面对这种情况,可以换种思路,使用return来优化 -```JAVA -if (!条件1) { -     return; -} -if (!条件2) { -     return; -} -if (!条件3) { -     return; -} -if (!条件4) { -     return; -} -if (!条件5) { -     return; -} - -System.out.println("三友的java日记"); -``` - -这样优化就感觉看起来更加直观 - -## 8、if条件表达式不要太复杂 - -比如在如下代码: - -```JAVA -if (((StringUtils.isBlank(person.getName()) - || "三友的java日记".equals(person.getName())) - && (person.getAge() != null && person.getAge() > 10)) - && "汉".equals(person.getNational())) { - // 处理逻辑 -} -``` - -这段逻辑,这种条件表达式乍一看不知道是什么,仔细一看还是不知道是什么,这时就可以这么优化 - -```JAVA -boolean sanyouOrBlank = StringUtils.isBlank(person.getName()) || "三友的java日记".equals(person.getName()); -boolean ageGreaterThanTen = person.getAge() != null && person.getAge() > 10; -boolean isHanNational = "汉".equals(person.getNational()); - -if (sanyouOrBlank - && ageGreaterThanTen - && isHanNational) { - // 处理逻辑 -} -``` - -此时就很容易看懂if的逻辑了 - -## 9、优雅地参数校验 - -当前端传递给后端参数的时候,通常需要对参数进场检验,一般可能会这么写 - -```JAVA -@PostMapping -public void addPerson(@RequestBody AddPersonRequest addPersonRequest) { - if (StringUtils.isBlank(addPersonRequest.getName())) { - throw new BizException("人员姓名不能为空"); - } - - if (StringUtils.isBlank(addPersonRequest.getIdCardNo())) { - throw new BizException("身份证号不能为空"); - } - - // 处理新增逻辑 -} -``` - -这种写虽然可以,但是当字段的多的时候,光校验就占据了很长的代码,不够优雅。 - -针对参数校验这个问题,有第三方库已经封装好了,比如hibernate-validator框架,只需要拿来用即可。 - -所以就在实体类上加@NotBlank、@NotNull注解来进行校验 - -```JAVA -@Data -@ToString -private class AddPersonRequest { - - @NotBlank(message = "人员姓名不能为空") - private String name; - @NotBlank(message = "身份证号不能为空") - private String idCardNo; - - //忽略 -} - -``` - -此时Controller接口就需要方法上就需要加上@Valid注解 - -```JAVA -@PostMapping -public void addPerson(@RequestBody @Valid AddPersonRequest addPersonRequest) { - // 处理新增逻辑 -} -``` - -## 10、统一返回值 - -后端在设计接口的时候,需要统一返回值 - -```JAVA -{ - "code":0, - "message":"成功", - "data":"返回数据" -} -``` - -不仅是给前端参数,也包括提供给第三方的接口等,这样接口调用方法可以按照固定的格式解析代码,不用进行判断。如果不一样,相信我,前端半夜都一定会来找你。 - -Spring中很多方法可以做到统一返回值,而不用每个方法都返回,比如基于AOP,或者可以自定义HandlerMethodReturnValueHandler来实现统一返回值。 - -## 11、统一异常处理 - -当你没有统一异常处理的时候,那么所有的接口避免不了try catch操作。 - -```JAVA -@GetMapping("/{id}") -public Result selectPerson(@PathVariable("id") Long personId) { - try { - PersonVO vo = personService.selectById(personId); - return Result.success(vo); - } catch (Exception e) { - //打印日志 - return Result.error("系统异常"); - } -} -``` - -每个接口都得这么玩,那不得满屏的try catch。 - -所以可以基于Spring提供的统一异常处理机制来完成。 - -## 12、尽量不传递null值 - -这个很好理解,不传null值可以避免方法不支持为null入参时产生的空指针问题。 - -当然为了更好的表明该方法是不是可以传null值,可以通过@NonNull和@Nullable注解来标记。@NonNull就表示不能传null值,@Nullable就是可以传null值。 - -```JAVA -//示例1 -public void updatePerson(@Nullable Person person) { - if (person == null) { - return; - } - personService.updateById(person); -} - -//示例2 -public void updatePerson(@NonNull Person person) { - personService.updateById(person); -} - -``` - -## 13、尽量不返回null值 - -尽量不返回null值是为了减少调用者对返回值的为null判断,如果无法避免返回null值,可以通过返回Optional来代替null值。 - -```JAVA -public Optional getPersonById(Long personId) { - return Optional.ofNullable(personService.selectById(personId)); -} - -``` - -如果不想这么写,也可以通过@NonNull和@Nullable表示方法会不会返回null值。 - -## 14、日志打印规范 - -好的日志打印能帮助我们快速定位问题 - -好的日志应该遵循以下几点: - -- 可搜索性,要有明确的关键字信息 - -- 异常日志需要打印出堆栈信息 - -- 合适的日志级别,比如异常使用error,正常使用info - -- 日志内容太大不打印,比如有时需要将图片转成Base64,那么这个Base64就可以不用打印 - -## 15、统一类库 - -在一个项目中,可能会由于引入的依赖不同导致引入了很多相似功能的类库,比如常见的json类库,又或者是一些常用的工具类,当遇到这种情况下,应当规范在项目中到底应该使用什么类库,而不是一会用Fastjson,一会使用Gson。 - -## 16、尽量使用工具类 - -比如在对集合判空的时候,可以这么写 - -```JAVA -public void updatePersons(List persons) { - if (persons != null && persons.size() > 0) { - - } -} -``` - -但是一般不推荐这么写,可以通过一些判断的工具类来写 - -```JAVA -public void updatePersons(List persons) { - if (!CollectionUtils.isEmpty(persons)) { - - } -} -``` - -不仅集合,比如字符串的判断等等,就使用工具类,不要手动判断。 - -## 17、尽量不要重复造轮子 - -就拿格式化日期来来说,我们一般封装成一个工具类来调用,比如如下代码 - -```JAVA -private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - -public static String formatDateTime(Date date) { - return DATE_TIME_FORMAT.format(date); -} -``` - -这段代码看似没啥问题,但是却忽略了SimpleDateFormat是个线程不安全的类,所以这就会引起坑。 - -一般对于这种已经有开源的项目并且已经做得很好的时候,比如Hutool,就可以把轮子直接拿过来用了。 - -## 18、类和方法单一职责 - -单一职责原则是设计模式的七大设计原则之一,它的核心意思就是字面的意思,一个类或者一个方法只做单一的功能。 - -就拿Nacos来说,在Nacos1.x的版本中,有这么一个接口HttpAgent - -![图片](../enginering/images/45-ways-3.png) - -这个类只干了一件事,那就是封装http请求参数,向Nacos服务端发送请求,接收响应,这其实就是单一职责原则的体现。 - -当其它的地方需要向Nacos服务端发送请求时,只需要通过这个接口的实现,传入参数就可以发送请求了,而不需要关心如何携带服务端鉴权参数、http请求参数如何组装等问题。 - -## 19、尽量使用聚合/组合代替继承 - -继承的弊端: - -- 灵活性低。java语言是单继承的,无法同时继承很多类,并且继承容易导致代码层次太深,不易于维护 -- 耦合性高。一旦父类的代码修改,可能会影响到子类的行为 - -所以一般推荐使用聚合/组合代替继承。 - -聚合/组合的意思就是通过成员变量的方式来使用类。 - -比如说,OrderService需要使用UserService,可以注入一个UserService而非通过继承UserService。 - -聚合和组合的区别就是,组合是当对象一创建的时候,就直接给属性赋值,而聚合的方式可以通过set方式来设置。 - -组合: -```java -public class OrderService { - private UserService userService = new UserService(); -} -``` - - -聚合: -```java -public class OrderService { - private UserService userService; - public void setUserService(UserService userService) { - this.userService = userService;      - } -} -``` - - -## 20、使用设计模式优化代码 - -在平时开发中,使用设计模式可以增加代码的扩展性。 - -比如说,当你需要做一个可以根据不同的平台做不同消息推送的功能时,就可以使用策略模式的方式来优化。 - -设计一个接口: -```java -public interface MessageNotifier { - - /** - * 是否支持改类型的通知的方式 - * - * @param type 0:短信 1:app - * @return - */ - boolean support(int type); - - /** - * 通知 - * - * @param user - * @param content - */ - void notify(User user, String content); - -} -``` - - -短信通知实现: - -```JAVA -@Component -public class SMSMessageNotifier implements MessageNotifier { - @Override - public boolean support(int type) { - return type == 0; - } - - @Override - public void notify(User user, String content) { - //调用短信通知的api发送短信 - } -} - -``` - -app通知实现: - -```JAVA -public class AppMessageNotifier implements MessageNotifier { - @Override - public boolean support(int type) { - return type == 1; - } - - @Override - public void notify(User user, String content) { - //调用通知app通知的api - } -} - -``` - -最后提供一个方法,当需要进行消息通知时,调用notifyMessage,传入相应的参数就行。 - -```JAVA -@Resource -private List messageNotifiers; - -public void notifyMessage(User user, String content, int notifyType) { - for (MessageNotifier messageNotifier : messageNotifiers) { - if (messageNotifier.support(notifyType)) { - messageNotifier.notify(user, content); - } - } -} - -``` - -假设此时需要支持通过邮件通知,只需要有对应实现就行。 - -## 21、不滥用设计模式 - -用好设计模式可以增加代码的扩展性,但是滥用设计模式确是不可取的。 - -```JAVA -public void printPerson(Person person) { - StringBuilder sb = new StringBuilder(); - if (StringUtils.isNotBlank(person.getName())) { - sb.append("姓名:").append(person.getName()); - } - if (StringUtils.isNotBlank(person.getIdCardNo())) { - sb.append("身份证号:").append(person.getIdCardNo()); - } - - // 省略 - System.out.println(sb.toString()); -} - -``` - -比如上面打印Person信息的代码,用if判断就能够做到效果,你说我要不用责任链或者什么设计模式来优化一下吧,没必要。 - -## 22、面向接口编程 - -在一些可替换的场景中,应该引用父类或者抽象,而非实现。 - -举个例子,在实际项目中可能需要对一些图片进行存储,但是存储的方式很多,比如可以选择阿里云的OSS,又或者是七牛云,存储服务器等等。所以对于存储图片这个功能来说,这些具体的实现是可以相互替换的。 - -所以在项目中,我们不应当在代码中耦合一个具体的实现,而是可以提供一个存储接口 - -```JAVA -public interface FileStorage { - - String store(String fileName, byte[] bytes); - -} - -``` - -如果选择了阿里云OSS作为存储服务器,那么就可以基于OSS实现一个FileStorage,在项目中哪里需要存储的时候,只要实现注入这个接口就可以了。 - -```JAVA -@Autowired -private FileStorage fileStorage; - -``` - -假设用了一段时间之后,发现阿里云的OSS比较贵,此时想换成七牛云的,那么此时只需要基于七牛云的接口实现FileStorage接口,然后注入到IOC,那么原有代码用到FileStorage根本不需要动,实现轻松的替换。 - -## 23、经常重构旧的代码 - -随着时间的推移,业务的增长,有的代码可能不再适用,或者有了更好的设计方式,那么可以及时的重构业务代码。 - -就拿上面的消息通知为例,在业务刚开始的时候可能只支持短信通知,于是在代码中就直接耦合了短信通知的代码。但是随着业务的增长,逐渐需要支持app、邮件之类的通知,那么此时就可以重构以前的代码,抽出一个策略接口,进行代码优化。 - -## 24、null值判断 - -空指针是代码开发中的一个难题,作为程序员的基本修改,应该要防止空指针。 - -可能产生空指针的原因: - -- 数据返回对象为null -- 自动拆箱导致空指针 -- rpc调用返回的对象可能为空格 - -所以在需要这些的时候,需要强制判断是否为null。前面也提到可以使用Optional来优雅地进行null值判断。 - -## 25、pojo类重写toString方法 - -pojo一般内部都有很多属性,重写toString方法可以方便在打印或者测试的时候查看内部的属性。 - -## 26、魔法值用常量表示 - -```JAVA -public void sayHello(String province) { - if ("广东省".equals(province)) { - System.out.println("靓仔~~"); - } else { - System.out.println("帅哥~~"); - } -} - -``` - -代码里,广东省就是一个魔法值,那么就可以将用一个常量来保存 - -```JAVA -private static final String GUANG_DONG_PROVINCE = "广东省"; - -public void sayHello(String province) { - if (GUANG_DONG_PROVINCE.equals(province)) { - System.out.println("靓仔~~"); - } else { - System.out.println("帅哥~~"); - } -} - -``` - -## 27、资源释放写到finally - -比如在使用一个api类锁或者进行IO操作的时候,需要主动写代码需释放资源,为了能够保证资源能够被真正释放,那么就需要在finally中写代码保证资源释放。 - -![图片](../enginering/images/45-ways-4.png) - -如图所示,就是CopyOnWriteArrayList的add方法的实现,最终是在finally中进行锁的释放。 - -## 28、使用线程池代替手动创建线程 - -使用线程池还有以下好处: - -- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 -- 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。 -- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统 的稳定性,使用线程池可以进行统一的分配,调优和监控。 - -所以为了达到更好的利用资源,提高响应速度,就可以使用线程池的方式来代替手动创建线程。 - -如果对线程池不清楚的同学,可以看一下这篇文章:7000字+24张图带你彻底弄懂线程池 - -## 29、线程设置名称 - -在日志打印的时候,日志是可以把线程的名字给打印出来。 - -![图片](../enginering/images/45-ways-5.png) - -如上图,日志打印出来的就是tom猫的线程。 - -所以,设置线程的名称可以帮助我们更好的知道代码是通过哪个线程执行的,更容易排查问题。 - -## 30、涉及线程间可见性加volatile - -在RocketMQ源码中有这么一段代码 - -![图片](../enginering/images/45-ways-6.png) - -在消费者在从服务端拉取消息的时候,会单独开一个线程,执行while循环,只要stopped状态一直为false,那么就会一直循环下去,线程就一直会运行下去,拉取消息。 - -当消费者客户端关闭的时候,就会将stopped状态设置为true,告诉拉取消息的线程需要停止了。但是由于并发编程中存在可见性的问题,所以虽然客户端关闭线程将stopped状态设置为true,但是拉取消息的线程可能看不见,不能及时感知到数据的修改,还是认为stopped状态设置为false,那么就还会运行下去。 - -针对这种可见性的问题,java提供了一个volatile关键字来保证线程间的可见性。 - -![图片](../enginering/images/45-ways-7.png) - -所以,源码中就加了volatile关键字。 - -加了volatile关键字之后,一旦客户端的线程将stopped状态设置为true时候,拉取消息的线程就能立马知道stopped已经是false了,那么再次执行while条件判断的时候,就不成立,线程就运行结束了,然后退出。 - -## 31、考虑线程安全问题 - -在平时开发中,有时需要考虑并发安全的问题。 - -举个例子来说,一般在调用第三方接口的时候,可能会有一个鉴权的机制,一般会携带一个请求头token参数过去,而token也是调用第三方接口返回的,一般这种token都会有个过期时间,比如24小时。 - -我们一般会将token缓存到Redis中,设置一个过期时间。向第三方发送请求时,会直接从缓存中查找,但是当从Redis中获取不到token的时候,我们都会重新请求token接口,获取token,然后再设置到缓存中。 - -整个过程看起来是没什么问题,但是实则隐藏线程安全问题。 - -假设当出现并发的时候,同时来两个线程AB从缓存查找,发现没有,那么AB此时就会同时调用token获取接口。假设A先获取到token,B后获取到token,但是由于CPU调度问题,线程B虽然后获取到token,但是先往Redis存数据,而线程A后存,覆盖了B请求的token。 - -这下就会出现大问题,最新的token被覆盖了,那么之后一定时间内token都是无效的,接口就请求不通。 - -针对这种问题,可以使用double check机制来优化获取token的问题。 - -所以,在实际中,需要多考虑考虑业务是否有线程安全问题,有集合读写安全问题,那么就用线程安全的集合,业务有安全的问题,那么就可以通过加锁的手段来解决。 - -## 32、慎用异步 - -虽然在使用多线程可以帮助我们提高接口的响应速度,但是也会带来很多问题。 - -##### 事务问题 - -一旦使用了异步,就会导致两个线程不是同一个事务的,导致异常之后无法正常回滚数据。 - -##### cpu负载过高 - -之前有个小伙伴遇到需要同时处理几万调数据的需求,每条数据都需要调用很多次接口,为了达到老板期望的时间要求,使用了多线程跑,开了很多线程,此时会发现系统的cpu会飙升 - -##### 意想不到的异常 - -还是上面的提到的例子,在测试的时候就发现,由于并发量激增,在请求第三方接口的时候,返回了很多错误信息,导致有的数据没有处理成功。 - -虽然说慎用异步,但不代表不用,如果可以保证事务的问题,或是CPU负载不会高的话,那么还是可以使用的。 - -## 33、减小锁的范围 - -减小锁的范围就是给需要加锁的代码加锁,不需要加锁的代码不要加锁。这样就能减少加锁的时间,从而可以较少锁互斥的时间,提高效率。 - -![图片](../enginering/images/45-ways-8.png) - -比如CopyOnWriteArrayList的addAll方法的实现,lock.lock(); 代码完全可以放到代码的第一行,但是作者并没有,因为前面判断的代码不会有线程安全的问题,不放到加锁代码中可以减少锁抢占和占有的时间。 - -## 34、有类型区分时定义好枚举 - -比如在项目中不同的类型的业务可能需要上传各种各样的附件,此时就可以定义好不同的一个附件的枚举,来区分不同业务的附件。 - -不要在代码中直接写死,不定义枚举,代码阅读起来非常困难,直接看到数字都是懵逼的。。 - -## 35、远程接口调用设置超时时间 - -比如在进行微服务之间进行rpc调用的时候,又或者在调用第三方提供的接口的时候,需要设置超时时间,防止因为各种原因,导致线程”卡死“在那。 - -我以前就遇到过线上就遇到过这种问题。当时的业务是订阅kafka的消息,然后向第三方上传数据。在某个周末,突然就接到电话,说数据无法上传了,通过排查线上的服务器才发现所有的线程都线程”卡死“了,最后定位到代码才发现原来是没有设置超时时间。 - -## 36、集合使用应当指明初始化大小 - -比如在写代码的时候,经常会用到List、Map来临时存储数据,其中最常用的就是ArrayList和HashMap。但是用不好可能也会导致性能的问题。 - -比如说,在ArrayList中,底层是基于数组来存储的,数组是一旦确定大小是无法再改变容量的。但不断的往ArrayList中存储数据的时候,总有那么一刻会导致数组的容量满了,无法再存储其它元素,此时就需要对数组扩容。所谓的扩容就是新创建一个容量是原来1.5倍的数组,将原有的数据给拷贝到新的数组上,然后用新的数组替代原来的数组。 - -在扩容的过程中,由于涉及到数组的拷贝,就会导致性能消耗;同时HashMap也会由于扩容的问题,消耗性能。所以在使用这类集合时可以在构造的时候指定集合的容量大小。 - -## 37、尽量不要使用BeanUtils来拷贝属性 - -在开发中经常需要对JavaBean进行转换,但是又不想一个一个手动set,比较麻烦,所以一般会使用属性拷贝的一些工具,比如说Spring提供的BeanUtils来拷贝。不得不说,使用BeanUtils来拷贝属性是真的舒服,使用一行代码可以代替几行甚至十几行代码,我也喜欢用。 - -但是喜欢归喜欢,但是会带来性能问题,因为底层是通过反射来的拷贝属性的,所以尽量不要用BeanUtils来拷贝属性。 - -比如你可以装个JavaBean转换的插件,帮你自动生成转换代码;又或者可以使用性能更高的MapStruct来进行JavaBean转换,MapStruct底层是通过调用(settter/getter)来实现的,而不是反射来快速执行。 - -## 38、使用StringBuilder进行字符串拼接 - -如下代码: - -```JAVA -String str1 = "123"; -String str2 = "456"; -String str3 = "789"; -String str4 = str1 + str2 + str3; - -``` - -使用 + 拼接字符串的时候,会创建一个StringBuilder,然后将要拼接的字符串追加到StringBuilder,再toString,这样如果多次拼接就会执行很多次的创建StringBuilder,z执行toString的操作。 - -所以可以手动通过StringBuilder拼接,这样只会创建一次StringBuilder,效率更高。 - -```JAVA -StringBuilder sb = new StringBuilder(); -String str = sb.append("123").append("456").append("789").toString(); - -``` - -## 39、@Transactional应指定回滚的异常类型 - -平时在写代码的时候需要通过rollbackFor显示指定需要对什么异常回滚,原因在这: - -![图片](../enginering/images/45-ways-9.png) - -默认是只能回滚RuntimeException和Error异常,所以需要手动指定,比如指定成Expection等。 - -## 40、谨慎方法内部调用动态代理的方法 - -如下事务代码 - -```JAVA -@Service -public class PersonService { - - public void update(Person person) { - // 处理 - updatePerson(person); - } - - @Transactional(rollbackFor = Exception.class) - public void updatePerson(Person person) { - // 处理 - } - -} - -``` - -update调用了加了@Transactional注解的updatePerson方法,那么此时updatePerson的事务就是失效。 - -其实失效的原因不是事务的锅,是由AOP机制决定的,因为事务是基于AOP实现的。AOP是基于对象的代理,当内部方法调用时,走的不是动态代理对象的方法,而是原有对象的方法调用,如此就走不到动态代理的代码,就会失效了。 - -如果实在需要让动态代理生效,可以注入自己的代理对象 - -```JAVA -@Service -public class PersonService { - - @Autowired - private PersonService personService; - - public void update(Person person) { - // 处理 - personService.updatePerson(person); - } - - @Transactional(rollbackFor = Exception.class) - public void updatePerson(Person person) { - // 处理 - } - -} - -``` - -## 41、需要什么字段select什么字段 - -查询全字段有以下几点坏处: - -###### 增加不必要的字段的网络传输 - -比如有些文本的字段,存储的数据非常长,但是本次业务使用不到,但是如果查了就会把这个数据返回给客户端,增加了网络传输的负担 - -###### 会导致无法使用到覆盖索引 - -比如说,现在有身份证号和姓名做了联合索引,现在只需要根据身份证号查询姓名,如果直接select name 的话,那么在遍历索引的时候,发现要查询的字段在索引中已经存在,那么此时就会直接从索引中将name字段的数据查出来,返回,而不会继续去查找聚簇索引,减少回表的操作。 - -所以建议是需要使用什么字段查询什么字段。比如mp也支持在构建查询条件的时候,查询某个具体的字段。 - -```JAVA - Wrappers.query().select("name"); -``` - -## 42、不循环调用数据库 - -不要在循环中访问数据库,这样会严重影响数据库性能。 - -比如需要查询一批人员的信息,人员的信息存在基本信息表和扩展表中,错误的代码如下: - -```JAVA -public List selectPersons(List personIds) { - List persons = new ArrayList<>(personIds.size()); - List personList = personMapper.selectByIds(personIds); - for (Person person : personList) { - PersonVO vo = new PersonVO(); - PersonExt personExt = personExtMapper.selectById(person.getId()); - // 组装数据 - persons.add(vo); - } - return persons; -} - -``` - -遍历每个人员的基本信息,去数据库查找。 - -正确的方法应该先批量查出来,然后转成map: - -```JAVA -public List selectPersons(List personIds) { - List persons = new ArrayList<>(personIds.size()); - List personList = personMapper.selectByIds(personIds); - //批量查询,转换成Map - List personExtList = personExtMapper.selectByIds(person.getId()); - Map personExtMap = personExtList.stream().collect(Collectors.toMap(PersonExt::getPersonId, Function.identity())); - for (Person person : personList) { - PersonVO vo = new PersonVO(); - //直接从Map中查找 - PersonExt personExt = personExtMap.get(person.getId()); - // 组装数据 - persons.add(vo); - } - return persons; -} - -``` - -## 43、用业务代码代替多表join - -如上面代码所示,原本也可以将两张表根据人员的id进行关联查询。但是不推荐这么,阿里也禁止多表join的操作 - -![图片](../enginering/images/45-ways-10.png) - -而之所以会禁用,是因为join的效率比较低。 - -MySQL是使用了嵌套循环的方式来实现关联查询的,也就是for循环会套for循环的意思。用第一张表做外循环,第二张表做内循环,外循环的每一条记录跟内循环中的记录作比较,符合条件的就输出,这种效率肯定低。 - -## 44、装上阿里代码检查插件 - -我们平时写代码由于各种因为,比如什么领导啊,项目经理啊,会一直催进度,导致写代码都来不及思考,怎么快怎么来,cv大法上线,虽然有心想写好代码,但是手确不听使唤。所以我建议装一个阿里的代码规范插件,如果有代码不规范,会有提醒,这样就可以知道哪些是可以优化的了。 - -![图片](../enginering/images/45-ways-11.png) - -如果你有强迫症,相信我,装了这款插件,你的代码会写的很漂亮。 - -## 45、及时跟同事沟通 - -写代码的时候不能闭门造车,及时跟同事沟通,比如刚进入一个新的项目的,对项目工程不熟悉,一些技术方案不了解,如果上来就直接写代码,很有可能就会踩坑。 - -#### 参考资料: - -《代码简洁之道》 - -《阿里巴巴Java开发手册》 - -如何写出让人抓狂的代码? - -## 程序汪资料链接 - -[程序汪接的7个私活都在这里,经验整理](http://mp.weixin.qq.com/s?__biz=MzA4NzQ0Njc4Ng==&mid=2247501524&idx=1&sn=2cb28e7b64ab77c55bcc1a172b82a2ad&chksm=903bc2b9a74c4baf5737cd430560ee3c5a357bb37864257a05a72e3cccf41db5bd221ccc63d8&scene=21#wechat_redirect) - -[**Java项目分享  最新整理全集,找项目不累啦 07版**](http://mp.weixin.qq.com/s?__biz=Mzg2ODU0NTA2Mw==&mid=2247488419&idx=2&sn=0b80c7f9f73fca89b91e257a269cfada&chksm=ceabf4ebf9dc7dfdaa605a9bb92d31c9fc0a10a7a94351234181a89ba5800672c6e7da2ebfbe&scene=21#wechat_redirect) - -[**堪称神级的Spring Boot手册,从基础入门到实战进阶**](http://mp.weixin.qq.com/s?__biz=MzA4NzQ0Njc4Ng==&mid=2247494170&idx=1&sn=5181a5277946be31478b1b9425c93f63&chksm=903bee77a74c67614b2772248e8b5e912d323bfe42a0e576dd157a4752f5fed88d6b439ec52f&scene=21#wechat_redirect) - -[**卧槽!字节跳动《算法中文手册》火了,完整版 PDF 开放下载!**](http://mp.weixin.qq.com/s?__biz=MzA4NzQ0Njc4Ng==&mid=2247492941&idx=1&sn=2ff31fec735d7c5d6f3483c346d5ca69&chksm=903be120a74c68361fd9afad178e7338315041a2cd4459f2165a8faa20e995a3477af3eda2bb&scene=21#wechat_redirect) - -[**卧槽!阿里大佬总结的《图解Java》火了,完整版PDF开放下载!**](http://mp.weixin.qq.com/s?__biz=MzA4NzQ0Njc4Ng==&mid=2247496297&idx=2&sn=d253dda2160821262d9f6fc1a9a637d0&chksm=903bf604a74c7f126ab936e374a1f22b9b7cb26a7964b6cc837c3f73af516139064e522a1294&scene=21#wechat_redirect) - -[**字节跳动总结的设计模式 PDF 火了,完整版开放下载!**](http://mp.weixin.qq.com/s?__biz=MzA4NzQ0Njc4Ng==&mid=2247490715&idx=2&sn=7f2c5de11bebaecfbaf1ce4b945a4d6f&chksm=903818f6a74f91e0fde557b75bd44adfd5d378612f682aa3eef6766927aebb9e5afc72c91a9e&scene=21#wechat_redirect) diff --git a/docs/enginering/design-pattern.md b/docs/enginering/design-pattern.md deleted file mode 100644 index e69de29..0000000 diff --git a/docs/enginering/mvc-ddd.md b/docs/enginering/mvc-ddd.md deleted file mode 100644 index 371bf39..0000000 --- a/docs/enginering/mvc-ddd.md +++ /dev/null @@ -1,194 +0,0 @@ -DDD这几年越来越火,资料也很多,大部分的资料都偏向于理论介绍,有给出的代码与传统MVC的三层架构差异较大,再加上大量的新概念很容易让初学者望而却步。本文从MVC架构角度来讲解如何演进到DDD架构。 - -### **从DDD的角度看MVC架构的问题** - -代码角度: - -- 瘦实体模型:只起到数据类的作用,业务逻辑散落到service,可维护性越来越差; -- 面向[数据库](https://cloud.tencent.com/solution/database?from=10680)表编程,而非模型编程; -- 实体类之间的关系是复杂的网状结构,成为大泥球,牵一发而动全身,导致不敢轻易改代码; -- service类承接的所有的业务逻辑,越来越臃肿,很容易出现几千行的service类; -- 对外接口直接暴露实体模型,导致不必要开放内部逻辑对外暴露,就算有DTO类一般也是实体类的直接copy; -- 外部依赖层直接从service层调用,字段转换、异常处理大量充斥在service方法中; - -[项目管理](https://cloud.tencent.com/product/coding-pm?from=10680)角度: - -- 交付效率:越来越低; -- 稳定性差:不好测试,代码改动的影响范围不好预估; -- 理解成本高:新成员介入成本高,长期会导致模块只有一个人最熟悉,离职成本很大; - -### **第一层:初出茅庐** - -以上的问题越来越严重,很多人开始把眼光转向DDD,于是埋头啃了几本大部头的书,对以下概念有了基本的了解: - -- 统一语言 -- 限界上下文 -- 领域、子域、支撑域 -- 聚合、实体、值对象 -- 分层:用户接口层、应用层、领域层、基础层 - -于是把MVC架构进行了改造,演进成DDD的分层架构。 - -DDD分层架构: - -![](images/DDD分层架构.png) - -MVC架构到DDD分层架构的映射: - -![](images/MVC架构到DDD分层架构的映射.jpeg) - -至此,算了基本入门了DDD架构,扩展性也得到了一定的提升。不过随着业务的发展,不断冒出新的问题: - -- 一段业务逻辑代码,到底应该放到应用层还是领域层? -- 领域服务当成原来的MVC中的service层,随着业务不断发展,类也在不断膨胀,好像还是老样子啊? -- 聚合包含多个实体类,这个接口用不到这么多实体,为了性能还是直接写个SQL返回必要的操作吧,不过这样貌似又回到了MVC模式 -- 既然实体类可以包含业务逻辑、领域服务也可以放业务逻辑,那到底放哪里? -- 资料上说领域层不能有外部依赖,要做到100%单测覆盖,可是我的领域服务中需要用到外部接口、中央缓存等等,那这不就有了外部依赖了吗? - -### **第二层:草船借箭(战术设计)** - -带着问题不断学习他人经验,并不断的尝试,逐渐get到以下技能: - -#### **1、领域层** - -领域(domain)是个模块,包含以下组成部分,传统的service按功能可能拆分到任何一个地方,各司其职。 - -- 1个聚合 -- 1到多个实体 -- 若干值对象 -- 多个DomainService -- 1个Factory:新建聚合 -- 1个Repository:聚合仓储服务 - -##### **聚合根(AggregateRoot)** - -聚合本身也是一个实体,聚合可以包含其他实体,其他实体不能脱离聚合而单独提供服务,比如一篇文章下的评论,评论必须从属于文章,没有文章也就没有评论。仓库层(repository)也必须是以聚合为核心提供服务的; - -实体:可以理解为一张数据库表,必须有主键; - -值对象:没有主键,依附于实体而存在,比如用户实体下住址对象,一般在数据库中已json字符串的形式存在;最常见的值对象是枚举; - -##### **仓库服务(repository)** - -资源库是聚合的仓储机制,外部世界通过资源库,而且只能通过资源库来完成对聚合的访问。资源库以聚合的整体管理对象。因此,一个聚合只能有一个资源库对象,那就是以聚合根命名的资源库。除此之外的其他对象,都不应该提供资源库对象。仓储服务的实现一般有Spring Data JPA、Mybatis两种方式。 - -如果是用Spring Data JPA实现,直接使用JPA注解@OneToOne、@OneToMany,配合fetch配置,即可一个方法查询出所有的关联实体。 - -如果是用Mybatis实现,那么repository需要加入多个mapper的引用,再手动做拼装。 - -这里有一个经典的Hibernate笛卡尔积问题,答案是在聚合根中,一般不会加在大量的关联实体对象。如果确实需要查询关联对象而关联对象又比较多怎么办呢?在DDD中有一个CQRS(Command-Query Responsibility Segregation)模式,是一种读写分离模式,在此场景中需要将查询操作放到查询命令中分页查询。 - -当然CQRS也是一个很复杂模式,不应照搬他人方案,而是根据自己的业务场景选择适合自己的方案,以下列举了CQRS的几种应用模式: - -![](images/CQRS的几种应用模式.png) - -##### **工厂服务(factory)** - -作用是创建聚合,只传入必要的参数,工厂服务内部隐藏复杂的创建逻辑。简单的聚合可以直接通过new、静态方法等创建,不是必须由factory创建。 - -##### **领域服务** - -单个实体对象能处理的逻辑放到实体里,多个实体或有交互的场景放到领域服务里。 - -领域服务可不可以调用仓储层或外部接口? 可以,但不能直接和领域服务代码放一起,领域服务模块存放API,实现放基础层(infrastructure)。 - -领域服务对象不建议直接以聚合名+DomainService命名,而要以操作命令关联,比如用户保存服务命名为:UserSaveService, 审核服务:UserAuditSerivce。 - -#### **2、应用层** - -应用层通过应用服务接口来暴露系统的全部功能。在应用服务的实现中,它负责编排和转发,它将要实现的功能委托给一个或多个领域对象来实现,它本身只负责处理业务用例的执行顺序以及结果的拼装。通过这样一种方式,它隐藏了领域层的复杂性及其内部实现机制。 - -比如下订单服务的方法: - -```java -1. public void submitOrder(Long orderId) { -2. Order order = OrderFetchService.fetchById(orderId); //获取订单对象 -3. OrderCheckSerivce.check(order); //验证订单是否有效 -4. OrderSubmitSerivce.submit(order); //提交订单 -5. ShoppingCartClearService.clear(order); //移除购物车中已购商品 -6. NotifySerivce.emailNotify(order.getUser()); //发送邮件通知买家 -7. } -``` - -对于复杂的业务来说,应用层也有几种模式: - -- 编排服务:最典型比如Drools; -- Command、Query命令模式; -- 业务按Rhase、Step逐层拆分模式; - -![](images/ddd1.png) - -#### **3、Maven模块划分** - -基础层是比较简单一层,不过这里还有个比较疑惑的问题:按照DDD的四层架构图去划分Maven模块,基础层是最上的一层,但是基础层也要包含基础组件供其他层使用,这时基础层应该是放到最下层,直接按照这样构建Maven模块会造成循环依赖。 - -![](images/ddd2.png) - -相比来说,另一个架构图更准确一些,不过依然没有直观体现Maven模块如何划分。 - -![](images/ddd3.png) - -我的最佳实践是将基础层拆分两部分,一部分是基础的组件+仓储API,一部分是实现,maven模块划分图如下所示: - -![](images/ddd4.png) - -### **第三层:运筹帷幄(战略设计)** - -经过以上的两层的磨炼,恭喜你把DDD战术都学习完了,应付日常的代码开发也够了,不过作为架构师来说,探索的道路还不能止步于此,接下来会DDD战略部分。战略部分关注点有3个: - -- 统一语言 -- 领域 -- 限界上下文 - -##### **1、统一语言** - -统一语言的重要性可以根据Jeff Patton 在《用户故事地图》中给出的一副漫画来直观的描述: - -![](images/userstory.png) - -统一语言是提炼领域知识的输出结果,也是进行后续需求迭代及重构的基础,统一语言的建立有以下几个要点: - -- 统一语言必须以文档的形式提供出来,并且在整个项目组的各团队达成共识; -- 统一语言必须每个中文名有对应的英文名,并且在整个技术栈保持一致; -- 统一语言必须是完整的,包含以下要素: - 1. 领域模型的概念与逻辑; - 2. 界限上下文(Bounded Context); - 3. 系统隐喻; - 4. 职责的分层; - 5. 模式(patterns)与惯用法。 - -##### **2、领域划分** - -以事件风暴的形式(Event Storming),列出所有的用户故事(Use Story),用户故事可通过6W模型来构建,即描写场景的 Who、What、Why、Where、When 与 hoW 六个要素。然后圈选功能相近的部分,就形成了领域,领域又根据职能不同划分为:核心域、支撑域、通用域, - -具体的过程有很多参考资料,这里不再细讲,最终的输出是领域划分图,以下是一个保险业务示例: - -![](images/领域划分-支付.png) - -##### **3、限界上下文** - -限界上下文包含两部分:上下文(Context)是业务目标,限界(Bounded)则是保护和隔离上下文的边界。 - -比如上图中的实现部分即是限界上下文的边界,虚线部分代表了领域的边界。限界上下文没有统一的划分标准,需要的读者根据自己的业务场景来甄别如何划分。 - -一个上下文中包含了相同的领域知识,角色在上下文中完成动作目标; - -边界体现在以下几方面: - -- 领域逻辑层:确定了领域模型的业务边界,维护了模型的完整性与一致性,从而降低系统的业务复杂度; -- 团队合作层:限界上下文一般也是用户换分团队的依据; -- 技术实现层:限界上下文可当成是微服务的划分边界; - -### **DDD的不足** - -DDD架构作为一套先进的方法论,在很多场景能发挥很大价值,但是DDD也不是银弹。高级的架构师把DDD架构当成一种工具,结合其他架构经验一起为业务服务。 - -DDD的不足有几个方面: - -1. 性能:DDD是基于聚合来组织代码,对于高性能场景下,加载聚合中大量的无用字段会严重影响性能,比如报表场景中,直接写SQL会更简单直接; -2. 事务:DDD中的事务被限定在限界上下文中,跨多个限界上下文的场景需要开发者额外考虑分布式事务问题; -3. 难度系数高,推广成本大:DDD项目需要领域专家专家,且需要特别熟悉业务、建模、OOP,对于管理者来说评估一个人是否真的能胜任也是一件困难的事情; - -### **总结** - -本文从MVC架构开始讲述了如何从演进到DDD架构,限于篇幅很多DDD的知识点没有讲到,希望大家在实践过程中能灵活运用,尽享DDD给业务带来的价值。本文如有不足之处敬请反馈。 \ No newline at end of file diff --git "a/docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\344\277\241\350\264\267\344\272\247\345\223\201-\346\224\277\345\272\234\350\236\215\350\265\204\345\271\263\345\217\260.md" "b/docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\344\277\241\350\264\267\344\272\247\345\223\201-\346\224\277\345\272\234\350\236\215\350\265\204\345\271\263\345\217\260.md" deleted file mode 100644 index 443b3f7..0000000 --- "a/docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\344\277\241\350\264\267\344\272\247\345\223\201-\346\224\277\345\272\234\350\236\215\350\265\204\345\271\263\345\217\260.md" +++ /dev/null @@ -1,701 +0,0 @@ -???+note - - 本页面简要介绍地方政府融资平台、常见的融资方式以及相关的政策指引。 - - -## 一、什么是政府融资平台 - -### 1.1地方政府融资平台的释义 - - “地方政府融资平台”(以下简称“平台”),目前尚无标准定义。但可以根据其所行驶的职能做出如下阐释:政府融资平台是指地方政府为了融资用于地方及城市基础设施的投资建设所组建的城市建设投资公司、交通开发公司、国有资产经营公司等各种不同类型的公司,这些公司通过地方政府所划拨的土地等资产组建一个资产和现金流大致可以达到融资标准的公司,并将融入的资金投入市政建设、公用事业等项目之中。 - -值得注意的是,地方政府融资平台并不代表国有投资公司。正确的区分两者,是我司开展融资工作的重要前提。我们可以通过以下两点对二者进行区分。 - -一是从公司的成立及运作方式上来看,地方政府融资平台的成立一般是通过地方政府财政拨款或注入土地、股权等资产设立,从而组建一个资产和现金流大致可以达到融资标准的公司,并将融入的资金投入市政建设、公用事业等项目之中。而国有投资公司则是是按《公司法》要求组建而成的国有控股或独资公司。成立后经过长期运作,形成了例如能源、金融、不动产等等各种市场竞争性实体经济板块的运作实体。 - -二是从对举债所筹集的资金用途和担保形式上看,融资平台公司所筹集资金多用于基础设施建设,一般提供财政性或者变相的财政担保,而国有投资公司所筹措资金主要用于竞争性实体经济,用作各成员企业补充生产经营资金、调整债务结构等方面。 - -## 二、政府融资平台的常见融资方式 - -### 2.1银行信贷 - -银行信贷又分为政策贷款、一般贷款、专项贷款,企业从银行贷款主要用于发展项目上的长期资金占用,银行作为债权人,有权利对企业的资金运用进行干涉和对债券资产进行保护。 - -政策性贷款是指由各政策性银行在人民银行确定的年度贷款总规模内,根据申请贷款的项目或企业情况按照相关规定自主审核,发放给企业的贷款。政策性贷款是目前中国政策性银行的主要资产业务,发放给国家扶植的优质企业和优质项目,具有成本低,款项来源稳定,风险性低的特点。但国家政策性贷款有额度限制、审核项目严格等限定,企业申请比较困难而且额度有限。 - -一般贷款与专项贷款指的是银行的一般贷款业务,专项贷款要求企业投入到专门的项目中,一般贷款不要求监管资金使用方向。银行贷款一般情况属于信用贷款,不要求进行物质抵押,银行对于企业的授信额度取决于企业的主要经营指标,通常授信额度为上一年度资产负债表营业收入的10%——20%。银行贷款企业一般要求条件如下: - -①财务结构: - -净资产与年末贷款余额比率大于100%。 - -资产负债率小于70%。 - -②偿债能力: - -流动比率在150%~200%较好;速动比率在100%左右较好;担保比例小于0.5为好;现金比率大于30%。 - -③现金流量 - -企业经营活动中的现金流量为正值,现金回笼在85%——95%以上,支付采购商品,劳务的现金支付率应在85%——95%以上。 - -④经营能力 - -主营企业增长率不小于8%;应收账款周转速度大约6;存货周转速度大于5. - -⑤经营效益 - -营业利润大于8%;净资产收益率大于5%;利息保证倍数大于400%。 - -以上要求作为通用一般要求,不作为硬性规定与贷款核定标准。各家银行对不同行业的要求也各有不同。 - -企业使用银行贷款方式的有点是成本低,资金充足。主要缺点是银行放贷谨慎而且资金监管严格,存在借款资金的利率变化、国家宏观经济和产业经济技术政策调整、借款资金所投资的项目发生比较大的市场变化导致不能如期偿还银行借款等风险因素。综上,对于大部分企业而言,不能依靠银行信贷作为融资的主要方式。 - -### 2.2企业债券 - -债券融资是指企业通过向个人或机构投资者出售债券等筹集营运资金或资本开支。企业债券通常又称为公司债券,是企业一招法定程序发行,约定在一定期限内还本付息的债券。企业债券代表着发债企业和投资者之间的一种债权债务关系。 - -发行企业债券的一般要求: - -①股份有限公司的净资产不低于人民币3000万元,有限责任公司的净资产不低于人民币6000万元; - -②本次发行后累计公司债券余额不超过最近一期期末净资产额的40%; - -③公司的生产经营符合法律、行政法规和公司章程的规定,募集的资金投向符合国家产业政策; - -④最近三个会计年度实现的年均可分配利润不少于公司债券1年的利息; - -⑤债券的利率不超过国务院规定的利率水平; - -⑥公司内部控制制度健全,内部控制制度的完整性、合理性、有效性不存在重大缺陷; - -⑦经资信评估机构评级,债券信用级别良好。 - -企业发行债券需要中国证监会批准,如果为国有制企业还需要国务院机关的批准,申请手续比较复杂,一般规律通常需要3—6个月的操作时间。 - -企业发行债券可以调整企业资产负债结构,增大财务杠杆,较大额度融资。但是债券融资作为债务融资方式,要求按照约定还本付息,对企业的现金流要求较高,如果资不抵债,企业会面临破产危险,从这个意义上来说,企业债券也有较大的风险。 - -### 2.3专项债融资 - -2015年4月,财政部发布《地方政府专项债券发行管理暂行办法》,以加强地方政府债务管理。政府专项债券区别与一般政府债券,为有一定收益的公益性项目发行,由政府性基金或专项收入偿还,安全性较高的债券。 - -政府专项债券主要分为四种: - -①城市地下综合管廊建设专项债券。重点支持城市地下综合管廊建设项目,建设期限超过5年的综合管廊建设项目,核准文件有效期可从1年延长至2年。 - -②战略性新兴产业专项债券。鼓励节能环保、新一代信息技术、生物、高端装备制造、新能源、新材料、新能源汽车等领域符合条件的企业发债,重点支持《“十二五”国家战略性新兴产业发展规划》中明确的二十大产业创新发展工程项目,允许不超过50%的募集资金用于偿还银行贷款和补充营运资金。 - -③养老产业专项债券。重点支持养老项目,债券资金可用于改造其他社会机构的养老设施,或收购政府拥有的学校、医院、疗养机构等闲置公用设施并改造为养老服务设施。 - -④城市停车场建设专项债券。重点支持城市停车场建设项目,鼓励发债用于收购已建成的停车场进行统一经营管理。 - -### 2.4过桥贷款 - -过桥贷款是一种短期资金的融通,期限通常以六个月为限,是一种与长期资金相对接的资金,属于短期借款范畴,借款企业使用它可以为长期低成本融资安排提供担保,或还清现有的债务,或实现资本运营中某一过渡期的特殊目的。这种类型的贷款融资主要是解决短期问题、资金缺口问题、历史遗留问题,预期今后可以用诸如长期贷款、企业债券或者其他融资而得以较快的回收。 - -过桥资金的利率通常较高,有时比同期银行信贷利率高出几倍,并且要求类似于股权、房产等资产进行抵押。总之,过桥资金是使购买时机直接资本化的一种有效的工具,具有回收速度快和过渡性质强的特点。 - -### 2.5融资租赁 - -融资租赁,是目前国际上最普遍、最基本的非债务性融资形式之一,通过发展与创新,目前已经将租赁的传统标的物,如设备、机械等延伸到其他的资产,如路灯、管网等,从而为企业提供两个方向的融资,一是作为承租人进行融资租赁,即传统的租赁方式,另一种是售后回租方式融通资金,即企业先将资产出售给租赁公司,再以融资租赁的形式租回的新兴租赁融资模式。 - -    企业需要某设备,可以直接联系融资租赁公司,由租赁公司联系厂家,出资购买设备,然后交付企业使用,企业按期支付租金,在约定期限届满之后,支付名义价格获得设备的所有权。融资租赁是集融资、融物、贸易、技术更新与一体的方式,当设备使用过程中,企业出现资金问题支付租金困难时,租赁公司可以回售和处理租赁物,因此在办理融资时对企业资信和担保的要求比银行信贷低,不影响企业的资信状况,不占用企业贷款信用额度,非常适合生产性企业的融资,降低资金占用成本和利率风险。 - -传统融资租赁的四个种类: - -①直接融资租赁,即传统的以设备为标的物的租赁方式。 - -②杠杆融资租赁,融资方式与传统方式类似,在资金提供方,通常由一家租赁公司牵头作为主干公司,为一个超大型的租赁项目融资,主干公司提供资金不少于20%。一般用于飞机、轮船、通讯设备和大型成套设备的租融资租赁。 - -③委托融资租赁,融资方式上与传统方式相同,但出租人与承租人与委托人签订书面委托,代为操作,在租赁期内租赁标的物的所有权归委托人,出租人只收取手续费,不承担风险。这种委托租赁的特点是让有资金而没有租赁经营权的企业可以“借权”经营。 - -④项目融资租赁,承租人以项目自身的财产和效益为保证,与出租人签订融资租赁合同,出租人对项目之外的财产和收益无追索权,租金的收取也只能以项目的现金流量和效益来确定。通常通讯设备、大型医疗设备、运输设备甚至高速公路经营权都可以采用这种方法。 - -出租人以租赁物件的购买价格为基础,按承租人占用出租人资金的时间为计算依据,根据双方商定的利率计算租金。全部租金等于购买租赁物件的购置成本加上租赁期的租赁融资利息。 - -### 2.6股权融资 - -股权融资是指公司通过出售或以其他方式交易公司的股份(或股票)获得企业生产经营资金和发展资金的融资方式。股权融资与其他融资方式的本质区别就是发生了公司的股权变化,资金提供者通过购买公司股权而成为公司的股东,享有股东权利、承担股东义务。股权融资包括增资扩股、发行股份(或股票)、配股、债转股等。股权融资作为企业的主要融资方式,是企业实现快速发展的重要融资手段。 - -#### 2.6.1股权融资的优缺点 - -与债权融资相比,股权融资的优势主要表现在: - -①资本优势,股权吸收的资本属于权益资本,不用承担还本付息义务,风险较低。 - -②战略投资者优势,可以联合优质企业进行战略合作,拓宽市场渠道、政府关系优势、技术优势等,产生协同效应,壮大公司。 - -主要的缺陷表现在: - -①从控制管理层面,会稀释公司的股权、控制权、收益权。 - -②股东之间对于公司战略发展等重大问题上的分歧会导致管理危机,导致合作破裂。 - -③经营管理层面上,公司不同的股东可能会产生有利于自己而不利于其他股东的投资行为,产生利益冲突。 - -#### 2.6.2股权融资的方式 - -表1 - -| 分类标准 | 分类 | 操作方式 | -| -------------------------- | -------- | ------------------------------------ | -| 按资金流向划分 | 增资扩股 | 企业向投资者增发新股,资金进入企业。 | -| | 旧股转让 | 老股东向投资者转让旧股 | -| 按融资的渠道及开放程度划分 | 公募发售 | 公开市场发售募集资金。 | -| |私募融资|通过协商、招标等非社会公开方式进行融资。| - - -### 2.7项目融资 - -    项目融资是指贷款人向特定的工程项目提供1年期以上的借贷资金,以项目营运收益承担债务偿还责任的融资形式,项目融资属于债务融资范畴。更准确地说,是指借款人以建设项目的名义筹措资金,并以该项目预期现金流量和未来收益、自身财产及所有者权益承担债务或担保并作为偿还贷款资金来源的一种融资方式。实质上,贷款人对于该项目所产生的现金流量享有偿债请求权,而该项目资产作为附属担保以控制贷款人的信贷风险。 - -项目贷款方式始于由20世纪30年代美国油田开发项目,后逐渐扩大,主要用于三大类项目的开发:资源开发、基础设施建设、制造业等,目前多广泛应用于石油、天然气、煤炭、铜等矿产资源的开发。因其不需要信用或者财产进行担保,也不需要政府部门的还款承诺,贷款的发放对象是项目公司,它是专门为项目融资和经营而成立的。 - -#### 2.7.1项目融资的分类 - -项目融资以项目的资产、预期收益或权益作抵押取得的一种无追索权或有限追索权的融资或贷款,按照有无追索权可划分为一下两种: - -①无追索权的项目融资。指贷款人对项目公司的发起人无任何追索权,只能依靠项目所产生的收益作为还本付息的唯一来源。同时,贷款银行无权向该项目的主办人追索。对于金融机构而言,无追索权的项目融资风险巨大,要求贷款成本较高,目前应用的比较少。 - -②有限追索权的项目融资。有限追索权项目融资一般是指仅在项目的建设开发阶段贷款人有权对项目发起人进行追索,而通过完工达到验收标准投产后,项目进入正常运营阶段时,贷款就变为无追索的了。因此,有限追索权项目融资除了以贷款项目的经营收益作为还款来源和项目取得的物权担保外,贷款银行还要求有项目实体以外的第三方(如项目发起人)提供担保,贷款银行有权向第三方担保人追索。但担保人承担债务的责任,以他们各自提供的担保金额为限,所以称为有限追索权的项目融资,需要对项目进行严格的论证。在现代项目融资实物中,大多数项目融资都是有限追索。 - -#### 2.7.2项目融资的模式 - -①直接项目融资。 - -是指项目的投资者直接向境内银行等金融机构申请贷款,取得一年以上信贷资金,按照贷款协议由项目投资者直接偿还贷款和利息的融资方式,无论项目本身的成败,都由项目投资者,来偿还项目贷款。这是企业采用最多也是最普通简单的项目融资方式,通常需要项目以外的资产或第三方抵押担保,债权人对债务有完全的追索权,及时项目失败也必须由项目投资者还贷。 - -②间接项目融资 - -简介项目融资是指,投资者设立项目公司,并由项目公司承担项目融资、项目建设、生产经营、产品销售、还本付息责任。此种方式是项目融资的狭义概念,一般不包括直接向银行的贷款,因其操作的专业性和项目管理的适用性与规范性,是管理效率较高的方法。 - -③产品支付 - -在项目投产后直接用项目产品来还本付息,而不以项目产品的销售收入的现金来偿还债务的一种融资形式。主要用于美国石油、天然气、矿产的开采,其特点是:用来清偿债务本息的唯一来源是项目的产品、贷款的偿还期应该短于项目有效生产期、贷款方对项目经营费用不承担直接责任。 - -④BOT融资 - -BOT即“建设—经营—转让”,是指政府部门就某个基础设施项目与私人企业(项目公司)签订特许权协议,授予签约方的私人企业(包括外国企业)来承担该项目的投资、融资、建设和维护,在协议规定的特许期限内,许可其融资建设和经营特定的公用基础设施,并准许其通过向用户收取费用或出售产品以清偿贷款,回收投资并赚取利润。政府对这一基础设施有监督权,调控权,特许期满,签约方的私人企业将该基础设施无偿或有偿移交给政府部门。 - -⑤TOT融资 - -TOT即“移交——经营——移交”,是国际上较为流行的一种项目融资方式,通常是指政府部门或国有企业将建设好的项目的一定期限的产权或经营权,有偿转让给投资人,由其进行运营管理;投资人在约定的期限内通过经营收回全部投资并得到合理的回报,双方合约期满之后,投资人再将该项目交还政府部门或原企业的一种融资方式。 - -⑥PPP融资 - -指在公共服务领域,政府采取竞争性方式选择具有投资、运营管理能力的社会资本,双方按照平等协商原则订立合同,由社会资本提供公共服务,政府依据公共服务绩效评价结果向社会资本支付对价,在该模式下,鼓励私营企业、民营资本与政府进行合作,参与公共基础设施的建设。与BOT相比,狭义PPP的主要特点是,政府对项目中后期建设管理运营过程参与更深,企业对项目前期科研、立项等阶段参与更深。政府和企业都是全程参与,双方合作的时间更长,信息也更对称。 - -⑦PFI融资 - -即私人投资计划,其含义是指政府部门根据社会对基础设置的需求,提出需要建设的项目,通过招投标由获得特许权的私营部门进行公共基础设置项目的建设与运营,并在特许期(通常是30年左右)结束时将所经营的项目完好地、无债务地归还政府,而私营部门则从政府部门或从接受服务方来收取费用以回收成本的项目融资方式。 - -FPI模式和PPP模式是最近几年国外发展得比较快的两种民资介入公共投资领域的模式,虽然在中国尚属于起步阶段,但是具有很好的借鉴作用。 - -⑧ABS融资 - -即资产收益证券化融资,指的是以项目所拥有的资产为基础,以该项目资产可以带来的预期收益为保证,通过在资本市场上发行债券筹集资金的一种项目融资方式。概括说就是“以项目所属的资产为支持的证券化融资方式”。特点: - -(1)ABS融资模式的最大优势是通过在国际市场上发行债券筹集资金,债券利率一般较低,从而降低了筹资成本。 - -(2)通过证券市场发行债券筹集资金,是ABS不同于其他项目融资方式的一个显著特点。 - -(3)ABS融资模式隔断了项目原始权益人自身的风险使其清偿债券本息的资金仅与项目资产的未来现金收入有关,加之,在国际市场上发行债券是由众多的投资者购买,从而分散了投资风险。 - -(4)ABS融资模式是通过SPV发行高档债券筹集资金,这种负债不反映在原始权益人自身的资产负债表上,从而避免了原始权益人资产质量的限制。 - -(5)作为证券化项目融资方式的ABS,由于采取了利用SPV增加信用等级的措施,从而能够进入国际高档证券市场,发行那些易于销售、转让以及贴现能力强的高档债券。 - -(6)由于ABS融资模式是在高档证券市场筹资,其接触的多为国际一流的证券机构,有利于培养东道国在国际项目融资方面的专门人才,也有利于国内证券市场的规范。 - -#### 2.7.3项目融资的特点 - -①有限追索权。 - -②信用担保结构复杂。项目融资需要信用支持,可以是自身信用,也可以由第三方提供。项目本身的多参与方(包括设备提供商、项目建筑商等)共同为项目分散风险,提高项目抗风险能力。另外,由于项目的用资金额较大,通常由多家金融机构参与,并通过书面协议明确各贷款机构承担风险的程度,一般还会形成结构严谨而复杂的担保体系。 - -③要求完备的现金流保证。项目在经济上的可行性须通过一定方式表现出来,必须具备关于项目现金流量的可行方案,该方案应由独立的工程可行性研究报告做证明,证明项目的未来现金流量足够支付项目的现金需要,支付施工费用及偶然费用。 - -④财务杠杆作用只是融资比例大。项目融资可以是投资者受到非常高的投资利润率,对投资者投入的权益资本金数量没有太多的要求,绝大部分资金依靠银行贷款来回凑集,一般项目融资在70%左右,某些项目可以做到100%融资。 - -⑤融资成本高。一般而言,处于风险因素、管理因素、测评因素等影响, 项目融资的利息一般高出同等条件抵押贷款的利息,小于担保借款的利息。 - -⑥实现资产负债表外融资。项目融资的债务不表现在投资者公司的资产负债表中,资产股债表外融资对于项目投资者的价值在于使某些财力有限的公司能够从事更多的投资,特别是一个公司在从事超过自身资产规模的投资时,这种融资方式的优势可充分体现。 - -#### 2.7.4项目融资的申请条件 - -  1. 项目本身已经经过政府部门批准立项。 - -  2. 项目可行性研究报告和项目设计预算已经政府有关部门审查批准。 - -  3. 引进国外技术、设备、专利等已经政府经贸部门批准,并办妥了相关手续。 - -  4. 项目产品的技术、设备先进适用,配套完整,有明确的技术保证。 - -  5. 项目的生产规模合理。 - -  6. 项目产品经预测有良好的市场前景和发展潜力,盈利能力较强。 - -  7. 项目投资的成本以及各项费用预测较为合理。 - -  8. 项目生产所需的原材料有稳定的来源,并已经签订供货合同或意向书。 - -  9. 项目建设地点及建设用地已经落实。 - -  10. 项目建设以及生产所需的水、电、通讯等配套设施已经落实。 - -  11. 目有较好的经济效益和社会效益。 - -  12. 其它与项目有关的建设条件已经落实。 - -  13. 项目建设公司或管理机构已经成立,管理团队具备管理项目的能力和素质。 - -### 2.8银行间债券市场融资 - -#### 2.8.1整体情况 - -银行间债券市场主要有六种融资方式,包括超短期融资债券、中期票据、非公开定向债务融资工具、短期融资券、资产支持证券、集合票据等。其中后两种使用者甚少,超短期融资债券因备案制、灵活机动、融资周期短等特点,是目前市场上使用效率最高的融资方式。 - -#### 2.8.2具体债券产品介绍  - -①超短期融资债券,简称“超级短融(SCP)”,期限为7-270天,发行规模不受净资产40%的红线限制,采用备案制,无需按年注册,要求企业评级AA以上,成本与短期融资债券基本持平。 - -②中期票据。期限在1年-10年之间,是企业5年以下中期贷款的替代品,受40%红线限制,一次注册通过,可以在两年内发行,可以采用固定或者浮动的计息方式,成本略低于10年期以上企业债券。 - -③非公开定向债务融资工具,简称“定向工具(PPN)”,注册之后向特定投资人发行金融产品,发行人与投资人的协商在注册之前基本完成,发行价格、发行利率、所涉费率遵循自律规则、按市场方式确定,不再强制要求信用评级,发行规模可突破“40%”限制,融资快速便捷。 - -④短期融资券。期限1年以内,可以循环贷款,实现“短债长用”,降低融资成本,要求信用评级AA以上,受到40%红线限制。 - -⑤长期限含权票据。属于票据种类,受40%限制,无固定期限,一般为X+N(5+N为主,即5年后可赎回),要求主体评级AA以上、计入**权益**的独立计算,**可用于项目投资建设(可作为资本金,占资本金比重不超过50%)。** - -⑥资产支持票据(ABN)。企业通过真实销售将应收账款、银行贷款、信用卡应收款等资产出售给SPV,再由SPV以这些资产作为支持发行票据在市场上公开出售,约定在一定期限内还本付息的债务融资工具。以非公开为主,不受40%红线限制,行规模受限于基础资产产生的现金流规模,还款方式和期限应与基础资产现金流相匹配,基础资可以为天然气收费收益权、自来水销售收入、高速公路建设应收款等领域的现金流,募集资金用于民生领域建设。 - -⑦项目收益票据。在银行间债券市场发行的,募集资金用于项目建设且以项目产生的经营性现金流为主要偿债来源的债务融资工具。发行人设立独立的项目公司,以非公开发行为主,期限与项目期限一致,一般用于市政、交通、公用事业、教育、医疗等与城镇化建设相关的、能产生持续稳定经营性现金流的项目。 - -银行间债券市场是融资的一个主要市场,第⑥⑦项是比较新颖且国家支持的方式,不同的类型各有特点,可以相互作为补充。具体对比如下表: - -表2 - -| | 期限 | 评级要求 | 资金用途 | 是否受40%限制 | 发行方式 | -| -------------- | ---------- | -------- | ------------ | ------------- | -------- | -| 超级短融 | 7天-720天 | A+ | 补充营运资金 | 否 | 备案制 | -| 中期票据 | 1年-10年 | AA- | 补充营运资金 | 是 | 注册制 | -| 定向工具 | 1年-3年 | 无 | 补充营运资金 | 否 | 注册制 | -| 短期融资券 | 1年以内 | A | 补充营运资金 | 是 | 注册制 | -| 长期限含权票据 | X+N年 | AA | 可作为资本金 | 否 | 注册制 | -| 资产支持票据 | 约定 | AA- | 补充营运资金 | 否 | 注册制 | -| 项目收益票据 | 与项目一致 | 授信 | 无 | 否 | 注册制 | - - - -## 三、中央对政府融资平台的政策指引 - -### 3.1 政府融资平台的现状 - -目前,全国城投公司3800多家,西部多省地方负债水平达到了200%,负债总额已远超地方一年可用财力的总和,有的地方甚至达到地方可用财力几年的总和。对于地方融资平台由于偿债能力不足可能引发的财政风险和系统性金融风险,中央政府已经给予了高度重视。财政部正积极牵头制定并陆续出台了旨在规范地方政府融资平台的文件;同时,银监会也正对地方融资平台项目贷款进行“解包还原”、锁定现金流等整理工作。 - -### 3.2 中央对政府融资平台融资工作指引性文件解读 - -正确的了解政策对政府平台融资工作的指引是我司为政府平台开展融资服务的重要前提。自2014年至2017年,中央各部门先后发布国发43号,财预50号,财预62号,财预87号文。其中国发43号指明了政府融资平台的后续发展方向,财预50号,财预62号,财预87号文则是对43号文总思路的补充与加强。现将4篇指引文件梳理解读如下: - -#### 3.2.1 43号文解读 - -**一、解读之前,首先要清楚以下几个概念:** - - **1、原地方政府性债务范围的界定** - - 43号文明确在存量债务处置中:以2013年政府性债务审计结果为基础,结合审计后债务增减变化情况,经债权人与债务人共同协商确认,对地方政府性债务存量进行甄别。所以原地方政府性债务的范围界定依据应该是2013年的审计结果。按照《国务院办公厅关于做好全国政府性债务审计工作的通知(国办发明电【2013】20号)》,2013年地方政府性债务审计范围包括: - - (1)地方政府负有偿还责任的债务增长情况。是指地方政府(含政府部门和机构,下同)、经费补助事业单位、公用事业单位、政府融资平台公司和其他相关单位举借,确定由财政资金偿还的债务。一是地方政府债券、国债转贷、外债转贷、农业综合开发借款、其他财政转贷债务中确定由财政资金偿还的债务。二是政府融资平台公司、政府部门和机构、经费补助事业单位、公用事业单位及其他单位举借、拖欠或以回购(BT)等方式形成的债务中,确定由财政资金(不含车辆通行费、学费等收入)偿还的债务。三是地方政府粮食企业和供销企业政策性挂账。 - - (2)地方政府负有担保责任的债务增长情况。是指因地方政府提供直接或间接担保,当债务人无法偿还债务时,政府负有连带偿债责任的债务。一是政府融资平台公司、经费补助事业单位、公用事业单位和其他单位举借,确定以债务单位事业收入(含学费、住宿费等教育收费收入)、经营收入(含车辆通行费收入)等非财政资金偿还,且地方政府提供直接或间接担保的债务。二是地方政府举借,以非财政资金偿还的债务,视同政府担保债务。 - - (3)地方政府可能承担一定救助责任的其他相关债务(以下简称其他相关债务)增长情况。是指政府融资平台公司、经费补助事业单位和公用事业单位为公益性项目举借,由非财政资金偿还,且地方政府未提供担保的债务(不含拖欠其他单位和个人的债务)。政府在法律上对该类债务不承担偿债责任,但当债务人出现债务危机时,政府可能需要承担救助责任。 - - (4)通过新的举债主体和举债方式形成的地方政府性债务。即在上述三类债务范围之外,通过新的举债主体和举债方式形成的地方政府性债务。一是全额拨款事业单位为其他单位提供直接或间接担保,且由非财政资金偿还的政府负有担保责任的债务。二是政府融资平台公司、经费补助事业单位和公用事业单位通过融资租赁、集资、回购(BT)、垫资施工、延期付款或拖欠等新的方式形成,用于非市场化方式运营的公益性项目,由非财政资金偿还,且地方政府及其全额拨款事业单位未提供担保的其他相关债务。三是国有独资或控股企业(不含地方政府融资平台公司)、自收自支事业单位等新的举债主体,通过举借、融资租赁、集资、回购(BT)、垫资施工、延期付款或拖欠等方式形成的,用于公益性项目,由非财政资金偿还,且地方政府及其全额拨款事业单位未提供担保的其他相关债务。其中新的举债主体用于公益性项目的债务仅包括用于交通运输(铁路、公路、机场、港口等)、市政建设(地铁、城市道路、公共交通、广场、文体场馆、绿化、污水及垃圾处理等)、保障性住房、土地收储整理等的债务,不包括企业法人和自然人投资完全按市场化方式运营项目形成的债务。 - - **2、政府性债务、政府债务和政府或有债务。** - - 43号文中多次出现:政府债务、政府性债务和政府或有债务,因此,我们要明确政府债务、政府性债务和政府债务的区别和相互关系。 - - 政府性债务包括:政府负有偿还责任、政府负有担保责任、可能有一定救助责任的债务。其中,政府负有偿还责任的债务即政府债务,政府债务以外的政府性债务统称政府或有债务。 - - **3、公益性问题** - - 预算法修正案规定举借的债务只能用于公益性资本支出,不得用于经常性支出。按照43号文规定,地方政府举债融资机制主要针对公益性事业。那么何谓公益性是投资者和金融机构都需要注意的一个问题。 - - 目前已有的相关文件资料中对于公益性的定义有一下几种: - - (1)发改委在审核发行企业债中对于平台债和产业债的分类认定中规定: - - 公益性项目是指为社会公共利益服务、不以盈利为目的,且不能或不宜通过市场化方式运作的政府投资项目。公益性项目包含但不限于以下几类: - -  ①城市开发、基础设施建设项目:包括城市基础设施建设、市政建设、园区开发、建设等; - -  ②土地开发项目:包括土地整理、土地储备管理等; - -  ③公益性住房项目:包括棚户区改造、保障房、安居房、安置房、经济适用房、廉租房等; - -  ④公益性事业:包括垃圾、污水处理、环境整治、水利建设等。 - -  准公益性项目是指为社会公共利益服务,虽不以盈利为目的但可产生较稳定的经营性收入的政府投资项目。准公益性项目包含但不限于以下几类: - -  ①公共服务项目:包括供水、供电(电力)、供气、供热等; - -  ②公共交通建设运营项目:包括高速公路投资运营、铁路、港口、码头、机场(民航)建设运营、轨道交通建设运营、城市交通建设运营等。 - - (2)《关于贯彻国务院加强地方政府融资平台公司管理通知》财预【2010】412号文 - - “公益性项目”是指为社会公共利益服务、不以盈利为目的,且不能或不宜通过市场化方式运作的政府投资项目,如市政道路、公共交通等基础设施项目,以及公共卫生、基础科研、义务教育、保障性安居工程等基本建设项目 - - (3)《国务院办公厅关于做好全国政府性债务审计工作的通知》(国办发明电【2013】20号) - -  公益性项目包括交通运输(铁路、公路、机场、港口等)、市政建设(地铁、城市道路、公共交通、广场、文体场馆、绿化、污水及垃圾处理等)、保障性住房、土地收储整理等。从以上政府规定中,明确都提到属于公益性的只有:市政道路、公共交通、保障性住房。所以对于公益性的定义目前尚无统一规范,还需要等待相关政策细则的明确。 - -**二、按照新预算法和43号文规定,规范的地方政府融资机制** - - 规范的地方政府举债融资机制仅限于:政府举债、PPP(即政府和社会资本合作)和规范的或有债务。 - - 1、政府举债 - - 政府债务只能通过政府及其部门举借,不得通过企事业单位等举借,规定主体仅限省级政府,省级以下无举债权,市县可由省级政府代为举借。政府债务举债:用途限定(只能用于公益性资本支出和适度归还存量债务,不得用于经常性支出)、规模控制(财政部测算、国务院确定、人大批准)、预算管理(分类纳入管理)政府举债以政府债券形式,按照公益性事业有无收益分为一般债券和专项债券。 - - 2、PPP - - 43号文规定:鼓励社会资本通过特许经营等方式,参与城市基础设施等有一定收益的公益性事业投资和运营,政府通过特许经营权、合理定价、财政补贴等事先公开的收益约定规则,使投资者有长期稳定收益。政府不承担投资者或特别目的公司的偿债责任。社会资本独自或者与政府共同成立特别目的公司(以下简称SPV)进行公司建设和运营合作项目,投资者或SPV可以通过银行贷款、企业债、项目收益债券、资产证券化等市场化方式举债并承担偿债责任。 - - 3、规范或有债务 - - 43号文规定:剥离融资平台公司政府融资职能,融资平台公司不得新增政府债务。地方政府新发生或有债务,要严格限定在依法担保的范围内,并根据担保合同依法承担相关责任。 - - 地方政府依法担保范围: - - 《中华人民共和国担保法》(1995年)是规定和约束担保行为的根本法律。它规定的担保方式包括保证、抵押、质押、留置和定金。该法第八条规定:“国家机关不得为保证人,但经国务院批准为使用外国政府或者国际经济组织贷款进行转贷的除外”。保证是指保证人和债权人约定,当债务人不履行债务时,保证人按照约定履行债务或者承担责任的行为。《新预算法》规定:除法律另有规定外,地方政府及其所属部门不得为任何单位和个人的债务以任何方式提供担保。由此可见,地方政府依法担保范围仅限经国务院批准为使用外国政府或者国际经济组织贷款进行转贷的担保行为。而且进一步根据预算法和43号文可以合理推测,政府融资行为仅限于公益性项目,不同融资方式是围绕的投资项目的运作方式、公益性和收益性来考虑。从政府自身控制债务的角度出发,能够市场化运作的,一定会市场化;无法完全市场化的就考虑政府举债和PPP来运作。 - -**三、规范的政府性债务范围** - - 根据预算法和43号文,不考虑现有的政府性债务存量处置,结合规范的政府举债融资机制,未来规范的政府性债务范围如下: - - 其中需要特别注意的是,43号文明确规定:对于PPP形式运作,特别是社会资本与政府共同成立特别目的公司进行公司建设和运营合作项目所形成的债务,既不属于政府债务,又不属于政府或有债务,但是纳入政府举债融资机制,需要依靠财政补贴,而且将政府与社会资本合作项目中的财政补贴等支出按性质纳入相应政府预算管理。所以存在一定关系,这是投资者需要注意的一点。 - -**四、存量债务处置和确保在建工程后续融资方式** - - 1、处置范围: - - 以2013年政府性债务审计结果为基础,结合审计后债务增减变化情况,经债权人与债务人共同协商确认,对地方政府性债务存量进行甄别。 - - 2、处置方法: - - 对项目自身运营收入能够按时还本付息的债务,应继续通过项目收入偿还。对项目自身运营收入不足以还本付息的债务,可以通过依法注入优质资产、加强经营管理、加大改革力度等措施,提高项目盈利能力,增强偿债能力。对确需地方政府偿还的债务,地方政府要切实履行偿债责任,必要时可以处置政府资产偿还债务。对确需地方政府履行担保或救助责任的债务,地方政府要切实依法履行协议约定,作出妥善安排。有关债务举借单位和连带责任人要按照协议认真落实偿债责任,明确偿债时限,按时还本付息,不得单方面改变原有债权债务关系,不得转嫁偿债责任和逃废债务。对确已形成损失的存量债务,债权人应按照商业化原则承担相应责任和损失。 - - 3、确保在建工程后续融资 - - 地方政府要统筹各类资金,优先保障在建项目续建和收尾。对使用债务资金的在建项目,原贷款银行等要重新进行审核,凡符合国家有关规定的项目,要继续按协议提供贷款,推进项目建设;对在建项目确实没有其他建设资金来源的,应主要通过政府与社会资本合作模式和地方政府债券解决后续融资。这一点相当于赋予了地方政府一定的一个灵活性,也有助于稳定政府性债务的系统性风险。 - -#### 3.2.2 50号文解读 - -50号文是由六部委联合发文,意在结合各自权限立体化、全方位的监管地方政府债务,防止债务风险和金融风险相互交叉感染。内容主要针对融资平台和PPP等方式隐性举债的纠偏,而非否定模式本身,通过规范化使之达到当初设计制度的本意。50号文,主要在两个方面进行了规范: - -1、规范融资平台 - -针对融资平台,50号文重申,“地方政府不得将公益性资产、储备土地注入融资平台公司,不得承诺将储备土地预期出让收入作为融资平台偿债资金来源,不得利用政府性资源干预金融机构正常经营行为”、“融资平台公司在境内外举债时,应当向债权人主动书面声明不承担政府融资职能” - -2、纠偏PPP - -2014年财政部和发改委先后力推PPP的初衷主要是转变基础设施和公共服务项目融资方式、发挥市场机制的决定性作用,但在实操中一开始就异化成新的融资工具:其一,撬动社会资本投资功能逐渐减弱,目前参与PPP项目的社会资本以央企和国企居多,民企相对较少。其二,一些地方政府违规出具担保函、兜底函,对项目进行回购或承诺固定收益等,不符合PPP风险共担、利益共享的理念。增加了地方政府性债务风险。其三,部分不规范的PPP项目形成了地方政府或有债务,导致地方政府隐性负债增加。 - -#### 3.2.3 62号文解读 - -62号文中“2017年先从土地储备领域开展试点,发行土地储备专项债券,规范土地储备融资行为,促进土地储备事业持续健康发展,今后逐步扩大范围。”表达保守,主要针对的是专项债券。专项债券必须对应有专项收入的项目,但对于无收入的公益性城市基础设施项目是否可通过PPP或政府购买服务来实现此处并未明确。 - -#### 3.2.4 87号文解读 - -87号文详细列举政府购买服务负面清单并首次将非金融机构的融资列入禁止范围。2014年《政府购买服务管理办法(暂行)》规定,政府向社会力量购买服务的内容为适合采取市场化方式提供、社会力量能够承担的公共服务,突出公共性和公益性,要逐步加大政府向社会力量购买服务的力度。并且只要纳入政府采购目录的事项都可以做政府购买服务,而禁止纳入的范围又比较模糊,加上县级政府就有列入政府购买目录的权限,因此,政府购买服务有日益泛滥之势。不少地方政府扩大政府购买服务的范围,把采购工程变成了采购服务,用工程代建服务、购买基础设施服务等变通方式做成了政府购买服务,变相举借债务,隐性债务风险不断积累累加。针对上述乱象,财政部87号文严肃进行了规范。在政府购买服务的范围上,财政部要求不得将原材料、燃料、设备、产品等货物,以及对建筑物和构筑物的新建、改建、扩建及其相关的装修、拆除、修缮等建设工程作为政府购买服务项目。严禁将铁路、公路、机场、通讯、水电煤气,以及教育、科技、医疗卫生、文化、体育等领域的基础设施建设,储备土地前期开发,农田水利等建设工程作为政府购买服务项目。严禁将建设工程与服务打包作为政府购买服务项目。严禁将金融机构、融资租赁公司等非金融机构提供的融资行为纳入政府购买服务范围。政府建设工程项目确需使用财政资金,应当依照《中华人民共和国政府采购法》及其实施条例、《中华人民共和国招标投标法》规范实施。就是以列举的方式,明确将有形的建设和物品的采购与无形的服务分开,将融资行为与政府的服务分开。从预算管理上,要求先有预算,然后才能购买服务,不得把政府购买服务作为增加预算支出的依据。签订购买服务合同,就当确认财政支出已在年度预算和中期财政规划中安排。防止以购买服务的名义增加将来政府的支出责任,增加政府的负债。并且87号文提出不得利用或虚构政府购买服务合同为建设工程变相举债不得通过政府购买服务向金融机构、融资租赁公司等非金融机构进行融资,不得以任何方式虚构或超越权限签订应付(收)账款合同帮助融资平台公司等企业融资。 - -## 四、附件 - - -### 附件一国发43号文 - -国务院【2014】43号文《关于加强地方政府性债务管理的意见》 - -2014年10月2日,《国务院关于加强地方政府性债务管理的意见》(国发,下称《意见》)对外公布,意见主要内容如下: - -(一)基本原则 - -疏堵结合,修明渠、堵暗道,赋予地方政府依法适度举债融资权限,加快建立规范的地方政府举债融资机制。同时,坚决制止地方政府违法违规举债;分清责任,明确政府和企业的责任,政府债务不得通过企业举借,企业债务不得推给政府偿还,切实做到谁借谁还、风险自担。政府与社会资本合作的,按约定规则依法承担相关责任;规范管理,对地方政府债务实行规模控制,严格限定政府举债程序和资金用途,把地方政府债务分门别类纳入全口径预算管理,实现“借、用、还”相统一;防范风险,牢牢守住不发生区域性和系统性风险的底线,切实防范和化解财政金融风险;稳步推进,加强债务管理,既要积极推进,又要谨慎稳健。在规范管理的同时,要妥善处理存量债务,确保在建项目有序推进。 - -(二)加快建立规范的地方政府举债融资机制 - -1.赋予地方政府依法适度举债权限。经国务院批准,省、自治区、直辖市政府可以适度举借债务,市县级政府确需举借债务的由省、自治区、直辖市政府代为举借。明确划清政府与企业界限,政府债务只能通过政府及其部门举借,不得通过企事业单位等举借。 - -2.建立规范的地方政府举债融资机制。地方政府举债采取政府债券方式。没有收益的公益性事业发展确需政府举借一般债务的,由地方政府发行一般债券融资,主要以一般公共预算收入偿还。有一定收益的公益性事业发展确需政府举借专项债务的,由地方政府通过发行专项债券融资,以对应的政府性基金或专项收入偿还。 - -3.推广使用政府与社会资本合作模式。鼓励社会资本通过特许经营等方式,参与城市基础设施等有一定收益的公益性事业投资和运营。政府通过特许经营权、合理定价、财政补贴等事先公开的收益约定规则,使投资者有长期稳定收益。投资者按照市场化原则出资,按约定规则独自或与政府共同成立特别目的公司建设和运营合作项目。投资者或特别目的公司可以通过银行贷款、企业债、项目收益债券、资产证券化等市场化方式举债并承担偿债责任。政府对投资者或特别目的公司按约定规则依法承担特许经营权、合理定价、财政补贴等相关责任,不承担投资者或特别目的公司的偿债责任。 - -4.加强政府或有债务监管。剥离融资平台公司政府融资职能,融资平台公司不得新增政府债务。地方政府新发生或有债务,要严格限定在依法担保的范围内,并根据担保合同依法承担相关责任。地方政府要加强对或有债务的统计分析和风险防控,做好相关监管工作。 - -(三)对地方政府债务实行规模控制和预算管理 - -1.对地方政府债务实行规模控制。地方政府债务规模实行限额管理,地方政府举债不得突破批准的限额。地方政府一般债务和专项债务规模纳入限额管理,由国务院确定并报全国人大或其常委会批准,分地区限额由财政部在全国人大或其常委会批准的地方政府债务规模内根据各地区债务风险、财力状况等因素测算并报国务院批准。 - -2.严格限定地方政府举债程序和资金用途。地方政府在国务院批准的分地区限额内举借债务,必须报本级人大或其常委会批准。地方政府不得通过企事业单位等举借债务。地方政府举借债务要遵循市场化原则。建立地方政府信用评级制度,逐步完善地方政府债券市场。地方政府举借的债务,只能用于公益性资本支出和适度归还存量债务,不得用于经常性支出。 - -3.把地方政府债务分门别类纳入全口径预算管理。地方政府要将一般债务收支纳入一般公共预算管理,将专项债务收支纳入政府性基金预算管理,将政府与社会资本合作项目中的财政补贴等支出按性质纳入相应政府预算管理。地方政府各部门、各单位要将债务收支纳入部门和单位预算管理。或有债务确需地方政府或其部门、单位依法承担偿债责任的,偿债资金要纳入相应预算管理。 - -(四)控制和化解地方政府性债务风险 - -1.建立地方政府性债务风险预警机制。财政部根据各地区一般债务、专项债务、或有债务等情况,测算债务率、新增债务率、偿债率、逾期债务率等指标,评估各地区债务风险状况,对债务高风险地区进行风险预警。列入风险预警范围的债务高风险地区,要积极采取措施,逐步降低风险。债务风险相对较低的地区,要合理控制债务余额的规模和增长速度。 - -2.建立债务风险应急处置机制。要硬化预算约束,防范道德风险,地方政府对其举借的债务负有偿还责任,中央政府实行不救助原则。各级政府要制定应急处置预案,建立责任追究机制。地方政府出现偿债困难时,要通过控制项目规模、压缩公用经费、处置存量资产等方式,多渠道筹集资金偿还债务。地方政府难以自行偿还债务时,要及时上报,本级和上级政府要启动债务风险应急处置预案和责任追究机制,切实化解债务风险,并追究相关人员责任。 - -3.严肃财经纪律。建立对违法违规融资和违规使用政府性债务资金的惩罚机制,加大对地方政府性债务管理的监督检查力度。地方政府及其所属部门不得在预算之外违法违规举借债务,不得以支持公益性事业发展名义举借债务用于经常性支出或楼堂馆所建设,不得挪用债务资金或改变既定资金用途;对企业的注资、财政补贴等行为必须依法合规,不得违法为任何单位和个人的债务以任何方式提供担保;不得违规干预金融机构等正常经营活动,不得强制金融机构等提供政府性融资。地方政府要进一步规范土地出让管理,坚决制止违法违规出让土地及融资行为。 - -(五)完善配套制度 - -1.完善债务报告和公开制度。完善地方政府性债务统计报告制度,加快建立权责发生制的政府综合财务报告制度,全面反映政府的资产负债情况。对于中央出台的重大政策措施如棚户区改造等形成的政府性债务,应当单独统计、单独核算、单独检查、单独考核。建立地方政府性债务公开制度,加强政府信用体系建设。各地区要定期向社会公开政府性债务及其项目建设情况,自觉接受社会监督。 - -2.建立考核问责机制。把政府性债务作为一个硬指标纳入政绩考核。明确责任落实,各省、自治区、直辖市政府要对本地区地方政府性债务负责任。强化教育和考核,纠正不正确的政绩导向。对脱离实际过度举债、违法违规举债或担保、违规使用债务资金、恶意逃废债务等行为,要追究相关责任人责任。 - -3.强化债权人约束。金融机构等不得违法违规向地方政府提供融资,不得要求地方政府违法违规提供担保。金融机构等购买地方政府债券要符合监管规定,向属于政府或有债务举借主体的企业法人等提供融资要严格规范信贷管理,切实加强风险识别和风险管理。金融机构等违法违规提供政府性融资的,应自行承担相应损失,并按照商业银行法、银行业监督管理法等法律法规追究相关机构和人员的责任。 - -(六)妥善处理存量债务和在建项目后续融资 - -1.抓紧将存量债务纳入预算管理。以2013年政府性债务审计结果为基础,结合审计后债务增减变化情况,经债权人与债务人共同协商确认,对地方政府性债务存量进行甄别。对地方政府及其部门举借的债务,相应纳入一般债务和专项债务。对企事业单位举借的债务,凡属于政府应当偿还的债务,相应纳入一般债务和专项债务。地方政府将甄别后的政府存量债务逐级汇总上报国务院批准后,分类纳入预算管理。纳入预算管理的债务原有债权债务关系不变,偿债资金要按照预算管理要求规范管理。 - -2.积极降低存量债务利息负担。对甄别后纳入预算管理的地方政府存量债务,各地区可申请发行地方政府债券置换,以降低利息负担,优化期限结构,腾出更多资金用于重点项目建设。 - -3.妥善偿还存量债务。处置到期存量债务要遵循市场规则,减少行政干预。对项目自身运营收入能够按时还本付息的债务,应继续通过项目收入偿还。对项目自身运营收入不足以还本付息的债务,可以通过依法注入优质资产、加强经营管理、加大改革力度等措施,提高项目盈利能力,增强偿债能力。地方政府应指导和督促有关债务举借单位加强财务管理、拓宽偿债资金渠道、统筹安排偿债资金。对确需地方政府偿还的债务,地方政府要切实履行偿债责任,必要时可以处置政府资产偿还债务。对确需地方政府履行担保或救助责任的债务,地方政府要切实依法履行协议约定,作出妥善安排。 - -4.确保在建项目后续融资。地方政府要统筹各类资金,优先保障在建项目续建和收尾。对使用债务资金的在建项目,原贷款银行等要重新进行审核,凡符合国家有关规定的项目,要继续按协议提供贷款,推进项目建设;对在建项目确实没有其他建设资金来源的,应主要通过政府与社会资本合作模式和地方政府债券解决后续融资。 - -(七)加强组织领导 - -各地区、各部门要高度重视,把思想和行动统一到党中央、国务院决策部署上来。地方政府要切实担负起加强地方政府性债务管理、防范化解财政金融风险的责任,结合实际制定具体方案,政府主要负责人要作为第一责任人,认真抓好政策落实。要建立地方政府性债务协调机制,统筹加强地方政府性债务管理。财政部门作为地方政府性债务归口管理部门,要完善债务管理制度,充实债务管理力量,做好债务规模控制、债券发行、预算管理、统计分析和风险监控等工作;发展改革部门要加强政府投资计划管理和项目审批,从严审批债务风险较高地区的新开工项目;金融监管部门要加强监管、正确引导,制止金融机构等违法违规提供融资;审计部门要依法加强对地方政府性债务的审计监督,促进完善债务管理制度,防范风险,规范管理,提高资金使用效益。各地区、各部门要切实履行职责,加强协调配合,全面做好加强地方政府性债务管理各项工作,确保政策贯彻落实到位。 - -### 附件二财预50号文 - -**关于进一步规范地方政府举债融资行为的通知****(****财预〔****2017****〕****50****号****)** - ---- - -财预〔2017〕50号 - -各省、自治区、直辖市、计划单列市财政厅(局)、发展改革委、司法厅(局),中国人民银行上海总部、各分行、营业管理部、省会(首府)城市中心支行、副省级城市中心支行,各银监局、证监局: - -  2014年修订的预算法和《国务院关于加强地方政府性债务管理的意见》(国发〔2014〕43号)实施以来,地方各级政府加快建立规范的举债融资机制,积极发挥政府规范举债对经济社会发展的支持作用,防范化解财政金融风险,取得了阶段性成效。但个别地区违法违规举债担保时有发生,局部风险不容忽视。为贯彻落实党中央、国务院决策部署,牢牢守住不发生区域性系统性风险的底线,现就进一步规范地方政府举债融资行为有关事项通知如下: - -  **一、全面组织开展地方政府融资担保清理整改工作** - -  各省级政府要认真落实国务院办公厅印发的《地方政府性债务风险应急处置预案》(国办函〔2016〕88号)要求,抓紧设立政府性债务管理领导小组,指导督促本级各部门和市县政府进一步完善风险防范机制,结合2016年开展的融资平台公司债务等统计情况,尽快组织一次地方政府及其部门融资担保行为摸底排查,督促相关部门、市县政府加强与社会资本方的平等协商,依法完善合同条款,分类妥善处置,全面改正地方政府不规范的融资担保行为。上述工作应当于2017年7月31日前清理整改到位,对逾期不改正或改正不到位的相关部门、市县政府,省级政府性债务管理领导小组应当提请省级政府依法依规追究相关责任人的责任。财政部驻各地财政监察专员办事处要密切跟踪地方工作进展,发现问题及时报告。 - -  **二、切实加强融资平台公司融资管理** - -  加快政府职能转变,处理好政府和市场的关系,进一步规范融资平台公司融资行为管理,推动融资平台公司尽快转型为市场化运营的国有企业、依法合规开展市场化融资,地方政府及其所属部门不得干预融资平台公司日常运营和市场化融资。地方政府不得将公益性资产、储备土地注入融资平台公司,不得承诺将储备土地预期出让收入作为融资平台公司偿债资金来源,不得利用政府性资源干预金融机构正常经营行为。金融机构应当依法合规支持融资平台公司市场化融资,服务实体经济发展。进一步健全信息披露机制,融资平台公司在境内外举债融资时,应当向债权人主动书面声明不承担政府融资职能,并明确自2015年1月1日起其新增债务依法不属于地方政府债务。金融机构应当严格规范融资管理,切实加强风险识别和防范,落实企业举债准入条件,按商业化原则履行相关程序,审慎评估举债人财务能力和还款来源。金融机构为融资平台公司等企业提供融资时,不得要求或接受地方政府及其所属部门以担保函、承诺函、安慰函等任何形式提供担保。对地方政府违法违规举债担保形成的债务,按照《国务院办公厅关于印发地方政府性债务风险应急处置预案的通知》(国办函〔2016〕88号)、《财政部关于印发〈地方政府性债务风险分类处置指南〉的通知》(财预〔2016〕152号)依法妥善处理。 - -  **三、规范政府与社会资本方的合作行为** - -  地方政府应当规范政府和社会资本合作(PPP)。允许地方政府以单独出资或与社会资本共同出资方式设立各类投资基金,依法实行规范的市场化运作,按照利益共享、风险共担的原则,引导社会资本投资经济社会发展的重点领域和薄弱环节,政府可适当让利。地方政府不得以借贷资金出资设立各类投资基金,严禁地方政府利用PPP、政府出资的各类投资基金等方式违法违规变相举债,除国务院另有规定外,地方政府及其所属部门参与PPP项目、设立政府出资的各类投资基金时,不得以任何方式承诺回购社会资本方的投资本金,不得以任何方式承担社会资本方的投资本金损失,不得以任何方式向社会资本方承诺最低收益,不得对有限合伙制基金等任何股权投资方式额外附加条款变相举债。 - -  **四、进一步健全规范的地方政府举债融资机制** - -  全面贯彻落实依法治国战略,严格执行预算法和国发〔2014〕43号文件规定,健全规范的地方政府举债融资机制,地方政府举债一律采取在国务院批准的限额内发行地方政府债券方式,除此以外地方政府及其所属部门不得以任何方式举借债务。地方政府及其所属部门不得以文件、会议纪要、领导批示等任何形式,要求或决定企业为政府举债或变相为政府举债。允许地方政府结合财力可能设立或参股担保公司(含各类融资担保基金公司),构建市场化运作的融资担保体系,鼓励政府出资的担保公司依法依规提供融资担保服务,地方政府依法在出资范围内对担保公司承担责任。除外国政府和国际经济组织贷款转贷外,地方政府及其所属部门不得为任何单位和个人的债务以任何方式提供担保,不得承诺为其他任何单位和个人的融资承担偿债责任。地方政府应当科学制定债券发行计划,根据实际需求合理控制节奏和规模,提高债券透明度和资金使用效益,建立信息共享机制。 - -  **五、建立跨部门联合监测和防控机制** - -  完善统计监测机制,由财政部门会同发展改革、人民银行、银监、证监等部门建设大数据监测平台,统计监测政府中长期支出事项以及融资平台公司举借或发行的银行贷款、资产管理产品、企业债券、公司债券、非金融企业债务融资工具等情况,加强部门信息共享和数据校验,定期通报监测结果。开展跨部门联合监管,建立财政、发展改革、司法行政机关、人民银行、银监、证监等部门以及注册会计师协会、资产评估协会、律师协会等行业自律组织参加的监管机制,对地方政府及其所属部门、融资平台公司、金融机构、中介机构、法律服务机构等的违法违规行为加强跨部门联合惩戒,形成监管合力。对地方政府及其所属部门违法违规举债或担保的,依法依规追究负有直接责任的主管人员和其他直接责任人员的责任;对融资平台公司从事或参与违法违规融资活动的,依法依规追究企业及其相关负责人责任;对金融机构违法违规向地方政府提供融资、要求或接受地方政府提供担保承诺的,依法依规追究金融机构及其相关负责人和授信审批人员责任;对中介机构、法律服务机构违法违规为融资平台公司出具审计报告、资产评估报告、信用评级报告、法律意见书等的,依法依规追究中介机构、法律服务机构及相关从业人员的责任。 - -  **六、大力推进信息公开** - -  地方各级政府要贯彻落实中共中央办公厅、国务院办公厅《关于全面推进政务公开工作的意见》等规定和要求,全面推进地方政府及其所属部门举债融资行为的决策、执行、管理、结果等公开,严格公开责任追究,回应社会关切,主动接受社会监督。继续完善地方政府债务信息公开制度,县级以上地方各级政府应当重点公开本地区政府债务限额和余额,以及本级政府债务的规模、种类、利率、期限、还本付息、用途等内容。省级财政部门应当参考国债发行做法,提前公布地方政府债务发行计划。推进政府购买服务公开,地方政府及其所属部门应当重点公开政府购买服务决策主体、购买主体、承接主体、服务内容、合同资金规模、分年财政资金安排、合同期限、绩效评价等内容。推进政府和社会资本合作(PPP)项目信息公开,地方政府及其所属部门应当重点公开政府和社会资本合作(PPP)项目决策主体、政府方和社会资本方信息、合作项目内容和财政承受能力论证、社会资本方采购信息、项目回报机制、合同期限、绩效评价等内容。推进融资平台公司名录公开。 - -  各地区要充分认识规范地方政府举债融资行为的重要性,把防范风险放在更加重要的位置,省级政府性债务管理领导小组要切实担负起地方政府债务管理责任,进一步健全制度和机制,自觉维护总体国家安全,牢牢守住不发生区域性系统性风险的底线。各省(自治区、直辖市、计划单列市)政府性债务管理领导小组办公室应当汇总本地区举债融资行为清理整改工作情况,报省级政府同意后,于2017年8月31日前反馈财政部,抄送发展改革委、人民银行、银监会、证监会。 - -  特此通知。 - -    财政部 发展改革委 司法部 人民银行 银监会 证监会 - -                       2017年4月26日 - -附件下载: - -### 附件三财预62号文 - -**关于印发《地方政府土地储备专项债券****管理办法(试行)》的通知****(****财预〔****2017****〕****62****号****)** - ---- - -财预〔2017〕62号 - -各省、自治区、直辖市、计划单列市财政厅(局)、各省级国土资源主管部门: - -  根据《中华人民共和国预算法》和《国务院关于加强地方政府性债务管理的意见》(国发〔2014〕43号)等有关规定,为完善地方政府专项债券管理,逐步建立专项债券与项目资产、收益对应的制度,有效防范专项债务风险,2017年先从土地储备领域开展试点,发行土地储备专项债券,规范土地储备融资行为,促进土地储备事业持续健康发展,今后逐步扩大范围。为此,我们研究制订了《地方政府土地储备专项债券管理办法(试行)》。 - -  2017年土地储备专项债券额度已经随同2017年分地区地方政府专项债务限额下达,请你们在本地区土地储备专项债券额度内组织做好土地储备专项债券额度管理、预算编制和执行等工作,尽快发挥债券资金效益。 - -  现将《地方政府土地储备专项债券管理办法(试行)》印发给你们,请遵照执行。 - -  附件:地方政府土地储备专项债券管理办法(试行) - -  财政部   国土资源部 - -  2017年5月16日 - -附件: - -**地方政府土地储备专项债券管理办法(试行)** - -**第一章** **总则** - -  第一条 为完善地方政府专项债券管理,规范土地储备融资行为,建立土地储备专项债券与项目资产、收益对应的制度,促进土地储备事业持续健康发展,根据《中华人民共和国预算法》和《国务院关于加强地方政府性债务管理的意见》(国发〔2014〕43号)等有关规定,制订本办法。 - -  第二条 本办法所称土地储备,是指地方政府为调控土地市场、促进土地资源合理利用,依法取得土地,进行前期开发、储存以备供应土地的行为。 - -  土地储备由纳入国土资源部名录管理的土地储备机构负责实施。 - -  第三条 本办法所称地方政府土地储备专项债券(以下简称土地储备专项债券)是地方政府专项债券的一个品种,是指地方政府为土地储备发行,以项目对应并纳入政府性基金预算管理的国有土地使用权出让收入或国有土地收益基金收入(以下统称土地出让收入)偿还的地方政府专项债券。 - -  第四条 地方政府为土地储备举借、使用、偿还债务适用本办法。 - -  第五条 地方政府为土地储备举借债务采取发行土地储备专项债券方式。省、自治区、直辖市政府(以下简称省级政府)为土地储备专项债券的发行主体。设区的市、自治州,县、自治县、不设区的市、市辖区级政府(以下简称市县级政府)确需发行土地储备专项债券的,由省级政府统一发行并转贷给市县级政府。经省级政府批准,计划单列市政府可以自办发行土地储备专项债券。 - -  第六条 发行土地储备专项债券的土地储备项目应当有稳定的预期偿债资金来源,对应的政府性基金收入应当能够保障偿还债券本金和利息,实现项目收益和融资自求平衡。 - -  第七条 土地储备专项债券纳入地方政府专项债务限额管理。土地储备专项债券收入、支出、还本、付息、发行费用等纳入政府性基金预算管理。 - -  第八条 土地储备专项债券资金由财政部门纳入政府性基金预算管理,并由纳入国土资源部名录管理的土地储备机构专项用于土地储备,任何单位和个人不得截留、挤占和挪用,不得用于经常性支出。 - -**第二章** **额度管理** - -  第九条 财政部在国务院批准的年度地方政府专项债务限额内,根据土地储备融资需求、土地出让收入状况等因素,确定年度全国土地储备专项债券总额度。 - -  第十条 各省、自治区、直辖市年度土地储备专项债券额度应当在国务院批准的分地区专项债务限额内安排,由财政部下达各省级财政部门,抄送国土资源部。 - -  第十一条 省、自治区、直辖市年度土地储备专项债券额度不足或者不需使用的部分,由省级财政部门会同国土资源部门于每年8月底前向财政部提出申请。财政部可以在国务院批准的该地区专项债务限额内统筹调剂额度并予批复,抄送国土资源部。 - -**第三章** **预算编制** - -  第十二条 县级以上地方各级土地储备机构应当根据土地市场情况和下一年度土地储备计划,编制下一年度土地储备项目收支计划,提出下一年度土地储备资金需求,报本级国土资源部门审核、财政部门复核。市县级财政部门将复核后的下一年度土地储备资金需求,经本级政府批准后于每年9月底前报省级财政部门,抄送省级国土资源部门。 - -  第十三条 省级财政部门会同本级国土资源部门汇总审核本地区下一年度土地储备专项债券需求,随同增加举借专项债务和安排公益性资本支出项目的建议,经省级政府批准后于每年10月底前报送财政部。 - -  第十四条 省级财政部门在财政部下达的本地区土地储备专项债券额度内,根据市县近三年土地出让收入情况、市县申报的土地储备项目融资需求、专项债务风险、项目期限、项目收益和融资平衡情况等因素,提出本地区年度土地储备专项债券额度分配方案,报省级政府批准后将分配市县的额度下达各市县级财政部门,并抄送省级国土资源部门。 - -  第十五条 市县级财政部门应当在省级财政部门下达的土地储备专项债券额度内,会同本级国土资源部门提出具体项目安排建议,连同年度土地储备专项债券发行建议报省级财政部门备案,抄送省级国土资源部门。 - -  第十六条 增加举借的土地储备专项债券收入应当列入政府性基金预算调整方案。包括: - -  (一)省级政府在财政部下达的年度土地储备专项债券额度内发行专项债券收入; - -  (二)市县级政府收到的上级政府转贷土地储备专项债券收入。 - -  第十七条 增加举借土地储备专项债券安排的支出应当列入预算调整方案,包括本级支出和转贷下级支出。土地储备专项债券支出应当明确到具体项目,在地方政府债务管理系统中统计,纳入财政支出预算项目库管理。 - -  地方各级国土资源部门应当建立土地储备项目库,项目信息应当包括项目名称、地块区位、储备期限、项目投资计划、收益和融资平衡方案、预期土地出让收入等情况,并做好与地方政府债务管理系统的衔接。 - -  第十八条 土地储备专项债券还本支出应当根据当年到期土地储备专项债券规模、土地出让收入等因素合理预计、妥善安排,列入年度政府性基金预算草案。 - -  第十九条 土地储备专项债券利息和发行费用应当根据土地储备专项债券规模、利率、费率等情况合理预计,列入政府性基金预算支出统筹安排。 - -  第二十条 土地储备专项债券收入、支出、还本付息、发行费用应当按照《地方政府专项债务预算管理办法》(财预〔2016〕155号)规定列入相关预算科目。 - -  **第四章** **预算执行和决算** - -  第二十一条 省级财政部门应当根据本级人大常委会批准的预算调整方案,结合市县级财政部门会同本级国土资源部门提出的年度土地储备专项债券发行建议,审核确定年度土地储备专项债券发行方案,明确债券发行时间、批次、规模、期限等事项。 - -  市县级财政部门应当会同本级国土资源部门、土地储备机构做好土地储备专项债券发行准备工作。 - -  第二十二条 地方各级国土资源部门、土地储备机构应当配合做好本地区土地储备专项债券发行准备工作,及时准确提供相关材料,配合做好信息披露、信用评级、土地资产评估等工作。 - -  第二十三条 土地储备专项债券应当遵循公开、公平、公正原则采取市场化方式发行,在银行间债券市场、证券交易所市场等交易场所发行和流通。 - -  第二十四条 土地储备专项债券应当统一命名格式,冠以“××年××省、自治区、直辖市(本级或××市、县)土地储备专项债券(×期)——×年××省、自治区、直辖市政府专项债券(×期)”名称,具体由省级财政部门商省级国土资源部门确定。 - -  第二十五条 土地储备专项债券的发行和使用应当严格对应到项目。根据土地储备项目区位特点、实施期限等因素,土地储备专项债券可以对应单一项目发行,也可以对应同一地区多个项目集合发行,具体由市县级财政部门会同本级国土资源部门、土地储备机构提出建议,报省级财政部门确定。 - -  第二十六条 土地储备专项债券期限应当与土地储备项目期限相适应,原则上不超过5年,具体由市县级财政部门会同本级国土资源部门、土地储备机构根据项目周期、债务管理要求等因素提出建议,报省级财政部门确定。 - -  土地储备专项债券发行时,可以约定根据土地出让收入情况提前偿还债券本金的条款。鼓励地方政府通过结构化创新合理设计债券期限结构。 - -  第二十七条 省级财政部门应当按照合同约定,及时偿还土地储备专项债券到期本金、利息以及支付发行费用。市县级财政部门应当及时向省级财政部门缴纳本地区或本级应当承担的还本付息、发行费用等资金。 - -  第二十八条 土地储备项目取得的土地出让收入,应当按照该项目对应的土地储备专项债券余额统筹安排资金,专门用于偿还到期债券本金,不得通过其他项目对应的土地出让收入偿还到期债券本金。 - -  因储备土地未能按计划出让、土地出让收入暂时难以实现,不能偿还到期债券本金时,可在专项债务限额内发行土地储备专项债券周转偿还,项目收入实现后予以归还。 - -  第二十九条 年度终了,县级以上地方各级财政部门应当会同本级国土资源部门、土地储备机构编制土地储备专项债券收支决算,在政府性基金预算决算报告中全面、准确反映土地储备专项债券收入、安排的支出、还本付息和发行费用等情况。 - -  **第五章** **监督管理** - -  第三十条 地方各级财政部门应当会同本级国土资源部门建立和完善相关制度,加强对本地区土地储备专项债券发行、使用、偿还的管理和监督。 - -  第三十一条 地方各级国土资源部门应当加强对土地储备项目的管理和监督,保障储备土地按期上市供应,确保项目收益和融资平衡。 - -  第三十二条 地方各级政府不得以土地储备名义为非土地储备机构举借政府债务,不得通过地方政府债券以外的任何方式举借土地储备债务,不得以储备土地为任何单位和个人的债务以任何方式提供担保。 - -  第三十三条 地方各级土地储备机构应当严格储备土地管理,切实理清土地产权,按照有关规定完成土地登记,及时评估储备土地资产价值。县级以上地方各级国土资源部门应当履行国有资产运营维护责任。 - -  第三十四条 地方各级土地储备机构应当加强储备土地的动态监管和日常统计,及时在土地储备监测监管系统中填报相关信息,获得相应电子监管号,反映土地储备专项债券运行情况。 - -  第三十五条 地方各级土地储备机构应当及时在土地储备监测监管系统填报相关信息,反映土地储备专项债券使用情况。 - -  第三十六条   财政部驻各地财政监察专员办事处对土地储备专项债券额度、发行、使用、偿还等进行监督,发现违反法律法规和财政管理、土地储备资金管理等政策规定的行为,及时报告财政部,抄送国土资源部。 - -  第三十七条 违反本办法规定情节严重的,财政部可以暂停其地方政府专项债券发行资格。违反法律、行政法规的,依法追究有关人员责任;涉嫌犯罪的,移送司法机关依法处理。 - -  **第六章** **职责分工** - -  第三十八条 财政部负责牵头制定和完善土地储备专项债券管理制度,下达分地区土地储备专项债券额度,对地方土地储备专项债券管理实施监督。 - -  国土资源部配合财政部加强土地储备专项债券管理,指导和监督地方国土资源部门做好土地储备专项债券管理相关工作。 - -  第三十九条 省级财政部门负责本地区土地储备专项债券额度管理和预算管理、组织做好债券发行、还本付息等工作,并按照专项债务风险防控要求审核项目资金需求。 - -  省级国土资源部门负责审核本地区土地储备规模和资金需求(含成本测算等),组织做好土地储备项目库与地方政府债务管理系统的衔接,配合做好本地区土地储备专项债券发行准备工作。 - -  第四十条 市县级财政部门负责按照政府债务管理要求并根据本级国土资源部门建议以及专项债务风险、土地出让收入等因素,复核本地区土地储备资金需求,做好土地储备专项债券额度管理、预算管理、发行准备、资金监管等工作。 - -  市县级国土资源部门负责按照土地储备管理要求并根据土地储备规模、成本等因素,审核本地区土地储备资金需求,做好土地储备项目库与政府债务管理系统的衔接,配合做好土地储备专项债券发行各项准备工作,监督本地区土地储备机构规范使用土地储备专项债券资金,合理控制土地出让节奏并做好与对应的专项债券还本付息的衔接,加强对项目实施情况的监控。 - -  第四十一条 土地储备机构负责测算提出土地储备资金需求,配合提供土地储备专项债券发行相关材料,规范使用土地储备专项债券资金,提高资金使用效益。 - -  **第七章** **附** **则** - -  第四十二条 省、自治区、直辖市财政部门可以根据本办法规定,结合本地区实际制定实施细则。 - -  第四十三条 本办法由财政部会同国土资源部负责解释。 - -  第四十四条 本办法自印发之日起实施。 - -### 附件四财预87号文 - -**关于坚决制止地方以政府购买服务名义****违法违规融资的通知****(****财预〔****2017****〕****87****号****)** - ---- - -财预〔2017〕87号 - -各省、自治区、直辖市、计划单列市财政厅(局): - -  《国务院办公厅关于政府向社会力量购买服务的指导意见》(国办发〔2013〕96号)印发后,各地稳步推进政府购买服务工作,取得了良好成效。同时,一些地区存在违法违规扩大政府购买服务范围、超越管理权限延长购买服务期限等问题,加剧了财政金融风险。根据《中华人民共和国预算法》、《中华人民共和国政府采购法》、《国务院关于实行中期财政规划管理的意见》(国发〔2015〕3号)、国办发〔2013〕96号文件等规定,为规范政府购买服务管理,制止地方政府违法违规举债融资行为,防范化解财政金融风险,现就有关事项通知如下: - -  一、坚持政府购买服务改革正确方向。推广政府购买服务是党的十八届三中全会决定明确的一项重要改革任务,有利于加快转变政府职能、改善公共服务供给、推进财政支出方式改革。政府购买服务所需资金应当在年度预算和中期财政规划中据实足额安排。实施政府购买服务改革,要坚持费随事转,注重与事业单位改革、行业协会商会与行政主管部门脱钩转制改革、支持社会组织培育发展等政策相衔接,带动和促进政事分开、政社分开。地方政府及其所属部门要始终准确把握并牢固坚持政府购买服务改革的正确方向,依法依规、积极稳妥地加以推进。 - -  二、严格按照规定范围实施政府购买服务。政府购买服务内容应当严格限制在属于政府职责范围、适合采取市场化方式提供、社会力量能够承担的服务事项,重点是有预算安排的基本公共服务项目。科学制定并适时完善分级分部门政府购买服务指导性目录,增强指导性目录的约束力。对暂时未纳入指导性目录又确需购买的服务事项,应当报财政部门审核备案后调整实施。 - -  严格按照《中华人民共和国政府采购法》确定的服务范围实施政府购买服务,不得将原材料、燃料、设备、产品等货物,以及建筑物和构筑物的新建、改建、扩建及其相关的装修、拆除、修缮等建设工程作为政府购买服务项目。严禁将铁路、公路、机场、通讯、水电煤气,以及教育、科技、医疗卫生、文化、体育等领域的基础设施建设,储备土地前期开发,农田水利等建设工程作为政府购买服务项目。严禁将建设工程与服务打包作为政府购买服务项目。严禁将金融机构、融资租赁公司等非金融机构提供的融资行为纳入政府购买服务范围。政府建设工程项目确需使用财政资金,应当依照《中华人民共和国政府采购法》及其实施条例、《中华人民共和国招标投标法》规范实施。 - -  三、严格规范政府购买服务预算管理。政府购买服务要坚持先有预算、后购买服务,所需资金应当在既有年度预算中统筹考虑,不得把政府购买服务作为增加预算单位财政支出的依据。地方各级财政部门应当充分考虑实际财力水平,妥善做好政府购买服务支出与年度预算、中期财政规划的衔接,足额安排资金,保障服务承接主体合法权益。年度预算未安排资金的,不得实施政府购买服务。购买主体应当按照批准的预算执行,从部门预算经费或经批准的专项资金等既有年度预算中统筹安排购买服务资金。购买主体签订购买服务合同,应当确认涉及的财政支出已在年度预算和中期财政规划中安排。政府购买服务期限应严格限定在年度预算和中期财政规划期限内。党中央、国务院统一部署的棚户区改造、易地扶贫搬迁工作中涉及的政府购买服务事项,按照相关规定执行。 - -  四、严禁利用或虚构政府购买服务合同违法违规融资。金融机构涉及政府购买服务的融资审查,必须符合政府预算管理制度相关要求,做到依法合规。承接主体利用政府购买服务合同向金融机构融资时,应当配合金融机构做好合规性管理,相关合同在购买内容和期限等方面必须符合政府购买服务有关法律和制度规定。地方政府及其部门不得利用或虚构政府购买服务合同为建设工程变相举债,不得通过政府购买服务向金融机构、融资租赁公司等非金融机构进行融资,不得以任何方式虚构或超越权限签订应付(收)账款合同帮助融资平台公司等企业融资。 - -  五、切实做好政府购买服务信息公开。各地应当将年度预算中政府购买服务总金额、纳入中期财政规划的政府购买服务总金额以及政府购买服务项目有关预算信息,按规定及时向社会公开,提高预算透明度。购买主体应当依法在中国政府采购网及其地方分网及时公开政府购买服务项目相关信息,包括政府购买服务内容、购买方式、承接主体、合同金额、分年财政资金安排、合同期限、绩效评价等,确保政府购买服务项目信息真实准确,可查询、可追溯。坚决防止借政府购买服务名义进行利益输送等违法违规行为。 - -  各省级财政部门要充分认识规范政府购买服务管理、防范财政金融风险的重要性,统一思想,加强领导,周密部署,报经省级政府批准后,会同相关部门组织全面摸底排查本地区政府购买服务情况,发现违法违规问题的,督促相关地区和单位限期依法依规整改到位,并将排查和整改结果于2017年10月底前报送财政部。 - -  特此通知。 - -  财  政  部 - -  2017年5月28日 - -附件下载: \ No newline at end of file diff --git "a/docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\344\277\241\350\264\267\344\272\247\345\223\201-\346\266\210\350\264\271\351\207\221\350\236\215.md" "b/docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\350\201\224\345\220\210\350\264\267\345\222\214\345\212\251\350\264\267.md" similarity index 100% rename from "docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\344\277\241\350\264\267\344\272\247\345\223\201-\346\266\210\350\264\271\351\207\221\350\236\215.md" rename to "docs/loan/02-\344\272\247\345\223\201\344\273\213\347\273\215/\350\201\224\345\220\210\350\264\267\345\222\214\345\212\251\350\264\267.md" diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\347\233\221\347\256\241-\346\226\255\347\233\264\350\277\236.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\347\233\221\347\256\241-\346\226\255\347\233\264\350\277\236.md" deleted file mode 100644 index d6a311d..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\347\233\221\347\256\241-\346\226\255\347\233\264\350\277\236.md" +++ /dev/null @@ -1,153 +0,0 @@ -???+note - 目前几大头部互联网流量机构接到监管通知,要在2022年11月底完成信贷领域的断直连试点工作。 - - 网上看了几篇文章发现都语焉不详,啰里啰唆,只能自己梳理这一事件的来龙去脉,以究其背景和方案是如何。 - -## 1、何为断直连 - -过去互联网平台的和资金方(银行、消费金融公司等)合作放款的模式以助贷模式为主,其本质是由银行查央行征信,互联网平台提供风控和流量。 - -断直连之后,监管要求客户信息必须由资产方传给个人征信机构,由个人征信机构传给资金方。 - -**即资产方(互联网流量平台)不能绕过个人征信机构和资金方进行放款交易。** - -## 2、其信息流程如图: - -![图片](images/断直连.png) - -## 3、其依据来自: - -央行征信局的《征信业务管理办法》。 - -明确了:自2022年1月1日起施行。信用信息的采集、整理、保存、加工等全流程合规管理“断直连”,明确了征信业务边界,加强了信息主体权益保护。 - -《征信业务管理办法》考虑了互联网平台、数据公司等机构与金融机构业务合作模式的调整,对本办法施行前未取得征信业务资质但实质从事征信业务的市场机构给予了一定的业务整改过渡期,过渡期为本办法施行之日至2023年6月底。 - -## 4、其监管背景: - -最近在各种国家会议提出,数据是一种生产要素,那么金融业务,涉及国计民生等重大问题,不得不察,其数据的方方面面需要掌握。 - -断直连之前,资产平台和资金平台对接,资金平台调用央行征信,央行征信机构是不掌握资产平台(互联网流量平台)数据的。 - -这不符合征信管理在生产要素的管理颗粒度。 - -当然还有风控层面和个人信息保护层面的后续好处,这点后面会讲。 - -## 5、目前涉及的持牌个人征信公司有 - -百行征信 - -朴道征信 - -钱塘征信 - -其特点都是国有控股,加上具有金融、生活、电商等数据属性的数据公司和金融科技私企公司参股。 - -![图片](images/持牌个人征信公司.png) - -不同的私企属性,使得其数据产品有不同的特点,当然这个和断直连这件事没有直接关系,但未来各家资金方可以根据自己的产品特性,接入不同的个人征信机构。 - -央行征信则主要记录个人或者企业的信用信息,包括借贷、担保、纳税信用等等方面,数据主要来自于传统的金融机构,比如说银行、持牌消费金融之类。 - -个人征信公司除了个人的金融数据之外,包括生活数据、电商数据等数据。 - -将个人的消费金融贷款、生活数据进行了收集,很大程度上是对央行征信的完善和补充,两者结合结合起来。 - -**个人信息对央行就是“透明化”的,此监管天眼打开。** - -## 6、其带来的意义有: - -- **征信监管:**  - -未来涉及个人信息共享的,流程需要按照个人征信的基本要求去开展和执行,各方需要积极对接持牌征信机构,如上所述,监管天眼打开。 - -- **个人信息保护:** - -对于部分信息,假如个人征信公司不收集不接受,而互联网平台不能和金融机构直连,那么互联网平台收集信息也没有**直接动力,当然间接动力还是存在的,有野心的大平台都喜欢自己存点私房数据。** - -- **策略输出:** - -过去互联网平台的风控策略结果都不愿意和资金方共享,有啥风险字段都藏着掖着,现在个人征信公司,集齐了所有平台的数据,其策略优化有了数据基础。 - -## 7、断直连之后的信息流程: - -按照“平台-个人征信机构-金融机构流程,和监管思想,可以分成三种。 - -(1)接口层面断直连 - -![图片](images/接口层面断直连.png) - -- 图例标记只要是授信申请,实际业务中当然用信申请也包括。 - -- 其流程是授信申请or用信申请 资产方(互联网平台)传给个人征信机构,这里要明确是整个接口直接由个人征信机构提供。 - -- 资产方所有的申请入参都传给个人征信机构,这样个人征信机构本地保存一份申请记录。 - -- 并且调用资金方的申请接口,把资产方的数据传给资金方。 - -- 授信or用信通知,由资金方通知个人征信机构,个人征信机构通知资产方。 - - -- **此方案的特点:** - -资金方接入or切换成本低,只需要把和资产方的接口,切换成资金方的接口即可,接口层面切换,逻辑也比较清晰。 - -同时断直连也断的也彻底,整个接口,不管是监管字段还是非监管字段,都全部上交国家。 - -**(2)信息层面断直连** - -![图片](images/信息层面断直连.png) - -- 图例标记只要是授信申请,实际业务中当然用信申请也包括。 - -- 其流程是授信申请or用信申请 资产方(互联网平台)把客户基本信息、设备信息、风险字段等传给个人征信机构,个人征信机构返回一个授权码。 - -- 资产方拿着这个授权码,授信申请or用信申请传给资金方,资金方收到申请之后。 - -- 再用授权码去个人征信机构查询相关客户信息。 - -- 资金方申请结果通知给资产方。 - - - -- **此方案特点:** - - -此方案断了一半,交互也稍复杂,个人征信机构沦为纯粹的数据收集方,并不知道交易是否成功和失败。 - -孰是孰非,时间自有定论。 - -**(3)流量层面断直连** - -![图片](images/流量层面断直连.png) - -- 根据监管要求,既然不让资产方和资金方直接信息交互,那么资产方也可以选择躺平,客户从录入信息的界面,就让资金方提供,比如挂一个h5。 - -- 客户填完信息直接发送到资金方,资金方审核通过后直接在h5上展示给客户。 - -- 资产方在这里只提供一个入口,自己收一点流量费用,其它都省心了。 - - -**此方案特点:** - -此方案目前适合比较小的流量平台,不需要投入什么开发人力。 - -但是可以作为一个模板,其实未来,监管的期望就是大的流量平台收流量费用,数据和风险等都让个人征信机构和资金方来做。 - -## 8、断直连对行业的影响: - -短期来看: - -对互联网平台的成本有影响,目前所有的业务都需要切换到个人征信机构,需要有一次性研发投入。 - -其次是新增了数据成本,因为要借用征信机构的接口给金融机构传送数据,比如有数据成本,行业内一般按照接口调用次数收费。 - -长期来看: - -相当于从数据层面被监管拿捏的死死的,后续监管的号令将会更加有效。 - -监管的长期诉求是流量平台只收流量费用,个人征信公司拿数据,金融机构做风险和业务。 - -随着断直连的正式落地,此抓手也逐步形成! - -总之跟着政策走,在这个行业才能长远生存。 \ No newline at end of file diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-Vintage\343\200\201\346\273\232\345\212\250\347\216\207\345\222\214\350\277\201\347\247\273\347\216\207.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-Vintage\343\200\201\346\273\232\345\212\250\347\216\207\345\222\214\350\277\201\347\247\273\347\216\207.md" deleted file mode 100644 index 77d8523..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-Vintage\343\200\201\346\273\232\345\212\250\347\216\207\345\222\214\350\277\201\347\247\273\347\216\207.md" +++ /dev/null @@ -1,303 +0,0 @@ -???+note - - 信贷风险管理是一门艺术,更是一门科学。资产质量分析中常会涉及到三个理论: - - - 账龄分析(Vintage Analysis):用以分析账户成熟期、变化规律等。 - - 滚动率分析(Roll Rate Analysis):用以定义账户好坏程度。 - - 迁移率分析(Flow Rate Analysis):用以分析不同逾期状态之间的转化率。 - - 本文基于《金融风控研究院-Vintage、滚动率和迁移率》,力求系统介绍这三者的概念、计算逻辑和业务应用,希望能对大家有所帮助。 - -## **Part 1.** 基础风控指标概念 - -为了更容易理解后续内容,我们先介绍一些基础的风控指标概念。 - -**定义一:账龄(Month on Book,MOB)** - -指**资产放款月份**。类似于婴孩一出生就有了年龄,一旦申贷订单被放款,也便拥有了账龄和生命周期。 - -- MOB0:放款日至当月月底 -- MOB1:放款后第二个完整的月份 -- MOB2:放款后第三个完整的月份 - -**MOB的最大值取决于信贷产品期限**。如果是12期产品,那么该资产的生命周期是12期,MOB最大到MOB12。 - -例如,2019年11月13日放款的订单,2019年11月是MOB0,2019年12月是MOB1,以此类推。 - -**定义二:逾期天数(Days Past Due,DPD)** - -**逾期天数 = 实际还款日 - 应还款日。** - -DPDN+表示逾期天数 >= N天,如DPD30+表逾期天数 >=30天的资产 - -例如,若还款日是每月8号,那么9号就是逾期第一天。如果客户在10号还款,那么逾期2天。 - -**定义三:逾期期数(M)** - -**指实际还款日与应还款日之间的逾期天数,并按区间划分后的逾期状态。** M取自Month on Book的第一个单词。(注:不同机构所定义的区间划分可能存在差异) - -- M0:当前未逾期(或用C表示,取自Current) -- M1: 逾期1-30日 -- M2:逾期31-60日 -- M3:逾期61-90日 -- M4:逾期91-120日 -- M5:逾期121-150日 -- M6:逾期151-180日 -- M7:逾期180日以上。此时也被称为*呆账*(Bad Debts),会予以注销账户(write-off) - -## **Part 2. Vintage Analysis** - -Vintage一词最初来源于葡萄酒业 。由于每年采摘的葡萄会受到日照、气温、降水等因素的影响,最终酿造的葡萄酒品质会存在差异。在窖藏一定年份后,葡萄酒的品质将趋于稳定,也就是品质成熟,这段年份数被称为*成熟期* (maturity)。 - -简便起见,我们以酒精浓度作为衡量葡萄酒品质的标准,约定:浓度越高,品质越好。首先,记录入窖年份作为该批次葡萄酒的标签,这也被称为Vintage或者Cohort。之后,我们将每年定期抽样测量酒精浓度,保存记录数据,如图1所示。 - -经过几年的数据积累,我们就可以绘制出酒精浓度随时间变化的Vintage曲线。俗话说,酒越酿越醇,Vintage曲线通常是*单调递增*的,如图1所示。 - -![](images/Pasted%20image%2020221201144844.png) - -图 1 - 葡萄酒的Vintage曲线 - -我们可以利用Vintage曲线做什么呢?如图2所示,主要用途包括: - -1. **分析变化规律**:评估不同年份的葡萄酒的品质随着窖藏时间推移的变化规律。某些年份的葡萄酒浓度在入窖第1年就能达到较高的水平,但上升缓慢;有些起点低,但上升快 。 -2. **确定最终品质**:Vintage曲线最终稳定值,表明了这批葡萄酒的最终酒精浓度 。 -3. **确定成熟期**:由图1可知,在入窖第6年后,酒精浓度稳定不变,可以确定成熟期是6年,我们最早在第6年就可以开桶品尝 。 -4. **分析影响因素**:根据Vintage曲线特征,我们可以分析某个年份的葡萄所受到的环境影响因素,从而改善生产工艺。比如,由于某一年的光照不充分,糖分积累少,酒精浓度可能最终就比较低。我们就可以人工增加光照强度 。 - -![](images/Pasted%20image%2020221201144902.png) - -图 2 - 葡萄酒的Vintage分析 - -在信贷领域中,我们也可以用Vintage曲线分析*资产*(portfolio)质量的成熟过程变化规律。为更容易理解,在此列举了Vintage分析过程中两个领域的对应关系,如图3所示。 - -![](images/Pasted%20image%2020221201144916.png) - -图 3 - 葡萄酒和信贷行业的Vintage对比 - -遵循同样的分析思路,按账龄(MOB)长短对齐后比较,我们可以了解同一产品不同时期放款的资产质量。 - -1. **确定资产质量**:一般以逾期率来定义资产质量,也就是曲线平缓后对应的逾期率。 -2. **分析变化规律**:资产质量(例如逾期率指标)的变化情况,如果前几期逾期率上升很快,那么说明短期风险没有捕捉住,欺诈风险较高;反之,如果曲线一直在上升,说明信用风险识别能力不佳。 -3. **确定账户成熟期**:用来判断客户展现好坏的时间因素,从而帮助定义表现期。 -4. **分析影响因素**:风控策略收紧或放松、客群变化、市场环境、政策法规等都会影响资产质量。分析影响因素,可以用来指导风控策略的调整。 - -求知的你肯定会疑惑,如果以逾期率来定义资产质量,那么逾期风险(目标变量Y)是如何定义的?如何确定M3,还是M6? 稍安勿躁,后续将会结合滚动率分析来揭晓谜底。 - -首先,我们来分析为什么要确定账户的表现期?在《[风控特征—时间滑窗统计特征体系](https://zhuanlan.zhihu.com/p/85440355)》一文中,我们提到过: - -> 表现期越长,信用风险暴露将越彻底,但意味着观察期离当前越远,用以提取样本特征的历史数据将越陈旧,建模样本和未来样本的差异也越大。反之,表现期越短,风险还未暴露完全,但好处是能用到更近的样本。 - -![](images/Pasted%20image%2020221201145203.png) - -图 4 - 观察点、观察期与表现期 - -例如,对于一个12期分期还款的信贷产品,理论上当用户在12期结束,并还清所有的钱后,我们才能定义为绝对的好客户;反之,我们只能说到目前为止是一个好客户,但并不能知道未来几期用户会不会逾期不还钱。 - -因此,我们需要确定一个合适的表现期能覆盖足够多的坏客户即可。 - -![](images/Pasted%20image%2020221201145150.png) - -图 5 - 某12期信贷产品2018年的Vintage曲线 - -根据图5的信贷产品Vintage曲线,我们可以得到哪些信息呢? - -1. 账龄最长为12个月,代表**产品期限为12期**。随着12期结束,账户的生命周期走到尽头。 -2. 账龄MOB1、MOB2、MOB3的逾期率都为0,说明**逾期指标为M4+(逾期超过90天)风险。** -3. 由放贷月份从2018年1月~12月的账户的最终逾期率都在降低,说明**资产质量在不断提升**,可能是因为风控水平在不断提升。 -4. 2018年5月相对于2018年1~4月的逾期率大幅度下降,说明该阶段风控策略提升明显。 -5. 不同月份放款的M4+在经过9个MOB后开始趋于稳定,说明**账户成熟期是9个月**。 - -绘制Vintage曲线时,就不得不提到纵坐标中逾期率的定义。通常有两种计算口径: - -- 第一种,订单口径,逾期率 = 逾期订单数 / 总放贷订单数 -- 第二种,金额口径,逾期率 = 逾期剩余本金 / 总放贷本金 - -目前互联网金融各家机构的**口径定义存在差异**,因此仅仅根据各家发布的Vintage曲线,有时并不能客观分析资产质量和风控水平。 - -计算逻辑详见:《[求是汪在路上:Vintage分析表计算过程详解](https://zhuanlan.zhihu.com/p/163206686)》 - -## **Part 3. Roll Rate Analysis** - -滚动率分析就是从某个观察点之前的一段时间(观察期)的最坏的状态,向观察点之后的一段时间(表现期)的最坏的状态的发展变化情况,如图6所示。 - -⚠️注意:一般大家也习惯把vintage中的成熟期叫做表现期,因此出现一定的混淆。但意思是都是未来的一段时间窗。 - -![](https://pic4.zhimg.com/80/v2-2b205377904876fbfcecf9955d9082ff_720w.webp) - -图 6 - 客户逾期状态转化 - -滚动率分析的具体操作步骤为: - -- **step 1.** 确定数据源。一般利用客户还款计划表(repayment schedule)。 -- **step 2.** 选择观察点,以观察点为截止时间,统计客户在观察期(如过去6个月)的最长逾期期数,按最坏逾期状态将用户分为几个层次,如C、M1、M2、M3、M4+。 -- **step 3.** 以观察点为起始时间,统计客户在表现期(如未来6个月)的最长逾期期数,按最坏逾期状态将用户分为几个层次,如C、M1、M2、M3、M4+。 -- **step 4.** 交叉统计每个格子里的客户数,如图6中表1所示。 -- **step 5.** 统计每个格子里的客户占比,如图6中表2所示。 -- **step 6.** 为了排除观察点选择时的随机影响,一般会选择多个观察点。重复step1 ~5。 - -例如,选择观察点为2018年6月30日,我们取10,000个客户作为研究对象,统计该10,000个客户从观察期到表现期的最大逾期状态的变化情况,如图7所示。 - -![](images/Pasted%20image%2020221201145825.png) - -图 7 - 滚动率分析矩阵 - -观察图7,我们可以发现以下规律: - -1. 逾期状态为M0的客户,在未来6个月里,有96%会继续保持正常状态,4%会恶化为M1和M2; -2. 逾期状态为M1的客户,未来有81%会回到正常状态,即从良率为81%,有7%会恶化,13%会保持M1状态; -3. 逾期状态为M2的客户,从良率为23%,有39%会恶化为M3和M4+; -4. 逾期状态为M3的客户,从良率为14.7%,有60.7%会恶化为M4+; -5. 逾期状态为M4+的客户,从良率仅为4%,有80%会继续保持此状态。 - -因此,我们认为历史逾期状态为M4+的客户已经坏透了,几乎不会从良。为了让风控模型有更好的区分能力,需要将客户好坏界限尽可能清晰,可以定义: - -> 坏用户(bad)= 逾期状态为M4+(逾期超过90天) - -## **Part 4. 如何确定目标变量Y** - -在风控建模中,由于是有监督学习,我们非常关心如何定义合适的目标变量Y?这就需要结合滚动率分析和Vintage分析,两者的分工在于: - -- 滚动率分析用于定义客户的**好坏程度**。 -- Vintage分析用于确定合适的**表现期**。 - -定义目标变量Y的具体操作步骤为: - -- **step 1.** 利用滚动率分析定义坏客户,例如上文案例中定义:**M4+为坏客户**。 -- **step 2.** 以M4+作为资产质量指标,统计Vintage数据表,绘制Vintage曲线。目的是**分析账户成熟期**,例如上文案例确定:**账户成熟期是9个月。** - -你可能还是会比较疑惑,为什么还需要通过Vintage分析来确定表现期? - -这是因为:虽然滚动率分析确定了M4+作为坏的程度,但是对于12期的产品,有些账户是在前4期MOB(也就是MOB1 ~ MOB4,经过4个表现期)就达到M4+,有些是在后几期才达到M4+。 - -对于这个Vintage里所有的账户,我们的目的是抓住尽可能多的坏客户。 - -现在进一步补充Vintage曲线的绘制过程:如图8所示,对于这10,000个账户,以MOB1为起点,把前N个MOB作为一个窗口,滑窗统计坏客户率,得到图5-表1中的Vintage数据,并绘制Vintage曲线。我们可以发现:经过9期,我们几乎能够抓住所有的坏客户。 - -![](https://pic4.zhimg.com/80/v2-8c0014d8126afefda8100c9e324ecd77_720w.webp) - -图 8 - 不同客户的逾期状态(红=逾期,绿=正常) - -因此,我们将两者结合起来,定义: - -- Bad = 账户经过9期表现期后,逾期状态为M4+(逾期超过90天)。此时 Y=1 。 -- Good = 经过9期表现期,但未达到M4+逾期状态。此时 Y=0 。 -- Intermediate = 未进入9期表现期,账户还未成熟,无法定义好坏,也就是不定样本。 - -## **Part 5. Flow Rate Analysis** - -**迁移率分析法**(Flow Rate)也叫做**净流量滚动比例法**(Net Flow Rate),能形象展示客户贷款账户在整个生命周期中的变化轨迹,也是**预测未来坏账损失**的最常用的方法。 - -其**核心假设**为:处于某一逾期状态(如M2)的账户,一个月后,要么从良为M0账户,要么恶化为更坏的下一个逾期状态(如M3)。 - -> 迁移率 = 前一期逾期金额到下一期逾期金额的转化率 - -一般缩写为M0-M1、M4-M5等形式,例如: - -- M0-M1 = 当月进入M1的贷款余额 / 上月末M0的贷款余额 -- M2-M3 = 当月进入M3的贷款余额 / 上月末M2的贷款余额 - -迁移率分析的具体操作步骤为: - -- **step 1.** 定义逾期状态,如前文所述的M0、M1、M2等。 -- **step 2.** 计算各逾期状态之间的迁移率,如M0-M1、M2-M3等。 -- **step 3.** 计算不同月份(也可称为Vintage)的平均迁移率。目的是对本平台在不同时期的资产的迁移率有整体的认知。 -- **step 4.** 根据平均迁移率和不良资产回收率,计算净坏账损失率。 - -接下来,我们以数值案例(非真实业务数据)展示上述过程。 - -![](https://pic4.zhimg.com/80/v2-b5b4256a397202940da4bcef790aec87_720w.webp) - -图 9 - 迁移率分析 - -图9-表2中,2月份的逾期M1资产只能从1月份的正常M0资产滚动而来,因此从逾期M0资产向M1的转化率为 2373371007843=23.55% 。 - -以此类推,我们可以计算所有月份的资产恶化率。黄色部分为不良资产的恶化迁移路径,其计算口径为: - -- 截止1月末,正常M0资产为 1007844 元,这是起点。 -- 截止2月末,1月末的正常M0资产中有 2373371007843=23.55% 恶化为逾期M1资产。 -- 截止3月末,2月末的逾期M1资产中有 55362237338=23.33% 恶化为逾期M2资产。 -- 截止4月末,3月末的逾期M2资产中有 2514455362=45.42% 恶化为逾期M3资产。 -- 截止5月末,4月末的逾期M4资产中有 20965525144=83.38% 恶化为逾期M5资产。此时已过催收黄金期(90天以内)。 -- 截止6月末,5月末的逾期M5资产中有 1035020965=49.37% 恶化为逾期M6资产。这可能采用了委外催收、司法手段等催收策略,效果显著。 -- 截止7月末,6月末的逾期M5资产中有 855910350=82.70% 恶化为逾期M7资产。此时将视为不良资产,打包转卖给第三方公司,这样就能回收部分不良资产,减少损失。 - -通过迁移率,我们可以清晰观察到每个Vintage的资产在各逾期状态的演变规律。 - -图9-表2中,我们从横向比较每个月的迁移率,发现不完全一样。这是因为随着时间推移、外在宏观经济环境、内部政策等变化而产生一定的波动。我们可以利用这些数据: - -1. 观察迁移率的发展轨迹,监控坏账的发展倾向和催收效果。 -2. 通过对多个月份的迁移率计算平均值,从而使迁移率更加稳定。 - -## **Part 6. 坏账准备金的计算** - -呆帐风险是信贷机构必须面对的风险,主要来源于信用风险和欺诈风险等。为了应对未来呆帐的可能,信贷机构一般都会设定一个储备资金,这就是**坏账准备金(Bad Debt Reserve)。**那么我们该如何计算坏账准备金? - -一般做法是,把未清偿贷款余额乘以一定的**准备金比例(Reserve Ratio)**所得。可以理解,资产逾期等级越高(越差),准备金比例也应该越高,因为恶化为呆帐的可能性也更高。如图10所示,正常M0资产恶化为呆帐的可能性最低,因此我们预留的准备金比例也就最少。 - -我们总结下计算坏账准备金的步骤为: - -- **step 1.** 统计未清偿贷款金额的分布,也就是M0~M6状态分别对应的资产余额。 -- **step 2.** 为每个逾期状态的资产分配一个准备金比例。 -- **step 3.** 每个子项目的准备金金额 = 未清偿贷款余额 x 准备金比例。 -- **step 4.** 每个子项目的准备金金额相加,得到最终的准备金。 - -![](https://pic3.zhimg.com/80/v2-7f7c474479a20271db484361905e4d06_720w.webp) - -图 10 - 坏账准备金计算示例 - -你或许会问,这里最关键的准备金比例是如何给出的? - -由于坏账准备金是用来覆盖预期的未来呆帐损失的,**准备金比例必须等于处于各个逾期状态的资产未来演变为呆帐的比例**。 - -回到迁移率分析中,我们发现从正常M0资产迁移至逾期M7资产(呆帐)需经过7次迁移,如图11所示。那么,我们只要把各个状态之间的转化率相乘,不就得到准备金比例了? - -![](https://pic3.zhimg.com/80/v2-2bc3e7254690eb773faa4bc66ef5ea6e_720w.webp) - -图 11 - 各逾期状态的迁移率和毛坏账率计算 - -因此,我们定义**正常M0资产对应的毛坏账损失率,**也就是迁移到呆帐的转化率为**:** - -> 毛坏账损失率 = (M0−M1)×(M1−M2)×...×(M6−M7) - -在本案例中,正常M0资产对应的毛坏账损失率为: - -(1)16.1%×29.28%×42.27%×80.1%×53.6%×80.32%×88.03%=0.60% - -在实际中,信贷机构会将不良资产打包转卖给第三方公司,这样就能回收部分不良资产,减少损失。因此,我们定义净坏账损失率为: - -> 净坏账损失率 = 毛坏账损失率 - 不良资产外卖回收率 - -由于M7不良资产的平均回收率为 10.79% ,则可计算**净坏账损失率**为: - -(2)0.60%×(1−10.79%)=0.54% - -同理,我们可以计算正常资产到不同逾期状态资产的毛损失率和净损失率如下: - -![](https://pic4.zhimg.com/80/v2-35d0ebb91b81844a08674e690b317477_720w.webp) - -图 12 - 毛损失率和净损失率 - -根据图12所示的损失率表,我们定义: - -- 当月应计拨备额 = SUM(净坏账损失率 * 月末应收账款余额) -- 拨备率 = 当月应计拨备额 / 总资产金额 - -其中,拨备率是用来预防不良资产的发生而准备的金额的比例。拨备率应越低越好。拨备率越高说明风险越大,损失越大,利润越小。 - -![](https://pic4.zhimg.com/80/v2-5cbf67b46a2bd9cfc0c10175b7aec153_720w.webp) - -图 13 - 2018年7月的资产预计期望损失计算 - -在本案例中,当月应计拨备额为65421元,如图13所示。拨备率为:654212625091=2.49% - -## **Part 7. 总结** - -本文所整理的主要知识点包括: - -1. Vintage、滚动率、迁移率的概念和区别。 -2. 如何根据数据分析来确定风控建模中的好坏定义。 -3. 拨备率的概念,以及如何根据迁移率来计算拨备率。 - -## 参考资料 - -[^1]:信贷风控中Vintage、滚动率、迁移率的理解:https://zhuanlan.zhihu.com/p/81027037 \ No newline at end of file diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\344\270\273\346\265\201\351\243\216\346\216\247\346\250\241\345\236\213.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\344\270\273\346\265\201\351\243\216\346\216\247\346\250\241\345\236\213.md" deleted file mode 100644 index 54e8378..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\344\270\273\346\265\201\351\243\216\346\216\247\346\250\241\345\236\213.md" +++ /dev/null @@ -1,74 +0,0 @@ -???+note - - 一个成熟的风险决策体系核心是由平台积累的海量数据基础,以及上百甚至上千个模型共同作用构成的。本文主要对工作中最常见的违约风险PD模型和差异化定价模型进行介绍。 - - 本文转自《金融风控研究院:风控-主流风控模型》 - -## 1 违约风险PD模型 - -在贷款审批方面,如果可以**通过构建量化模型对客户的信用等级进行一定的区分**。在信贷资金管理方面,得知了每个账户的违约概率后,可以预估一下未来的坏账比例,及时做好资金安排。 - -也可以**对违约概可能性较高的客户进行更加频繁的“关怀”**,及时发现问题,以避免损失。PD模型的重要性也就不言而喻了。 - -**1)原理** - -违约风险PD模型的原理为运用用户历史贷款的相关信息**对此后产生违约风险的相关概率进行预测**。 - -**2)实现路径** - -违约风险PD模型分三个步骤: - -第一步,归集当下客户的**征信、个人信息、交易信息、经营情况**等诸多层面的信息; - -第二步,根据归集的信息,筛选出显著对信用有影响的相关变量,建立PD模型; - -第三步,按照PD模型的评分结果将客户划分为有较好信用和较差信用的两大类。如图所示。 - -![](images/Pasted%20image%2020221201162233.png) - -该模型评分结果如下所示: - -![](images/Pasted%20image%2020221201162245.png) - - -**3)应用场景及意义** - -PD模型主要有两个方面的应用: - -一是可以按照PD模型的评分对准入客户进行筛选,**细化客户授信,实现贷前风控**; - -二是可以用于**自动申请贷款、自动审批,贷中风险监控**等。 - -针对一个稳健型信用类线上贷款产品来说,直接上模型进行利率分档,可能会产生对优质客户的“利率伤害”,或者不利于对不同群体的客户进行利率下浮营销。 - -基于这样一些背景和问题,更适合采用客群分类+风险模型结合 ,制定差异化的利率定价方案,差异化定价模型在其中的作用也就不言而喻了。 - -## 2 差异化定价模型 - -针对一个稳健型信用类线上贷款产品来说,直接上模型进行利率分档,可能会产生对优质客户的“利率伤害”,或者不利于对不同群体的客户进行利率下浮营销。 - -基于这样一些背景和问题,更适合采用客群分类+风险模型结合 ,制定差异化的利率定价方案,差异化定价模型在其中的作用也就不言而喻了。 - -**1)原理** - -差异化定价思路有以下两层涵义: - -一是结合个体风险预测(PD模型)以及个体利率敏感度模型,对每个客户制订符合其风险和收益特征的最优定价策略,真正体现一人一价(贷款利率市场化); - -二是对新增客户采用**“前低后高”**的定价方式,即前期设定比较低的基础利率,等企业发展到一定的程度后,触发事先约定的条件,再采用更高的利率;针对续贷的老客户采用“前高后低”的定价方式,即前期收取标准利率,后期给予相应的利率折扣。 - -这其中,信用良好且贷款使用习惯较好的小微企业,则可以逐步获得更低成本的融资机会。以往多以执行日息万分之五的通行信贷产品定价,结合信用差异化定价政策,小微企业融资最低的年化利率可达12%。 - -**2)实现路径** - -**对新客户**:体验式定价。主要采用了用于精细化运营的客户分层以及个性化区别对待的响应模型。该模型的KS值大概在0.67左右。 - -**对续贷客户**:对第一次续贷客户实行利率敏感度风险定价,对多次续贷客户给予利率折扣。 - -定价=**相对固定的资金及运营成本+PD*LGD+ProfitMargin**(其中,PD是违约概率,LGD是违约损失率,ProfitMargin是毛利率)。 - -其中毛利率的值主要通过基于Chow-test敏感度预测的决策树将利率测试客户分为高敏感组、中敏感组、低敏感组三个组别,然后对不同组别的客户实行差别利率定价方式。 - -![](images/Pasted%20image%2020221201162304.png) - -通过对续贷客户进行实时的信用矫验,根据客户的经营、信用等具体情况给予额度提升或者利率折扣的优惠。 diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\345\217\215\346\254\272\350\257\210.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\345\217\215\346\254\272\350\257\210.md" deleted file mode 100644 index c1c3b54..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\345\217\215\346\254\272\350\257\210.md" +++ /dev/null @@ -1,97 +0,0 @@ -???+note - - 本文主要介绍反欺诈体系的一些方法论,具体细节可参考《[大数据反欺诈](https://zhuanlan.zhihu.com/c_147252758)》。 - - -## Part 1. 欺诈分类体系 - -![](images/Pasted%20image%2020221201161436.png) - -图 1 - 信贷欺诈风险分类 - -从作案规模上,信贷反欺诈一般可分为个人欺诈和团队欺诈。如图1所示,从风险归因上,可分为以下7类: - -1. **白户风险**:借款人信息缺失,没有足够的数据来对借款人进行风险评估。包括内部白户(新注册用户、无申贷历史记录)和外部白户(央行征信、第三方民间征信无覆盖)。由于从未或较少有申贷记录,因此黑名单规则、多头规则等都会失效。在对待白户时,应当谨慎其被黑产利用的可能。 -2. **黑户风险**:借款人存在逾期、失信、欺诈的记录。包括内部黑户(历史多笔订单出现逾期、在途订单催收失联等)、外部黑户(央行征信花/黑、第三方民间征信黑)。出于炫耀等心理,很多黑户会在口子论坛、QQ群等交流撸贷经验,因此可通过论坛舆情监控、黑产群卧底等来发现新的作案手法。 -3. **恶意欺诈**:借款人通过伪造资料,蓄意骗贷。例如,伪造账单流水记录来企图骗取更高的额度。一般都是借款老哥,熟悉各平台流程,深谙套路。恶意欺诈人群往往到处借钱,广撒网来提高放款概率。同时,可能涉及不良嗜好(黄赌毒)。 -4. **身份冒用**:伪冒他人身份进行欺诈骗贷。包括熟人冒用(亲戚朋友、同学等)和他人盗用(购买他人四件套、个人隐私信息泄漏等)。一般可通过信审、人脸识别、活体验证等方式来核验借款人身份。 -5. **以贷养贷**:通过拆东墙补西墙的方式,来维持不良消费(黄赌毒、奢侈品等)。借款人现金流收入主要靠不断借款,借下家的钱,还上家的债。这种击鼓传花的游戏,会将共债风险杠杆逐渐放大。一旦借款人再也借不到钱,资金链便会立刻断裂,所有平台全线逾期。目前市场上,同盾、百融、亿美等第三方征信机构都提供此类多头借贷产品服务。 -6. **中介风险**:黑中介哄骗或招揽客户实施骗贷。网贷中介有利有弊,好中介可帮助平台导流(类似贷款超市),提高市场份额;黑中介将对平台风控漏洞进行大规模攻击,造成巨大资损。黑中介可利用白户轻松突破风控防线,并骗取白户的高额手续费。黑中介通讯录一般会存客户的号码;若是远程贷款操作,可能会采取视频通话、翻拍照片来应对活体识别核身。 -7. **传销风险**:有组织地开展收费并发展多级下线,存在集中骗贷的风险。给成员洗脑诱导骗贷,同时不断以拉新会员费来给老会员发工资,从而扩大规模。由于老客拉新,从关系网络上观察具有明显的星状结构。 - -## Part 2. 反欺诈调研 - -案件调研是反欺诈战场的侦察部队,基本要求是: - -1. **风险事件发现**:具有敏锐的风险嗅觉,发现可疑事件,不放过任何的蛛丝马迹。 -2. **欺诈场景还原**:广泛收集各渠道信息还原欺诈场景,调研分析背后的可能原因。 -3. **风险规则提炼**:从欺诈场景中提炼相应的专家规则,用以拦截欺诈,果断回击。 - -我们一般可以从哪些渠道来快速发现风险事件呢? - -1. **实时大盘监控**:基于订单、用户维度,监控设备聚集性风险(LBS、Wi-Fi)、地域欺诈风险(如朋克村)。大盘监控对于识别黑中介风险、传销风险等团伙欺诈相对更有效,需要设置报警阈值,并人工介入分析。 -2. **信审催收反馈**:信审通过电话外呼,核验客户身份,咨询借款动机,往往会发现某些欺诈用户。例如,身份伪冒风险场景中,借款人支支吾吾无法正确回答问题。催收中发现失联用户等,这些兄弟部门的案件将反馈至调研组。因此,需要建设好案件管理平台,联通各部门。 -3. **论坛舆情监控**:通过对各大口子论坛、戒赌吧、上岸交流区等内容,提取近期市场动向。特别是需要去理解欺诈人群的心理特征、社会身份等。例如,2018年,在714高炮行业风险初见苗头时,论坛上就出现“青铜系”、“宁波系”等借贷口子系列。 -4. **黑产卧底调研**:线上渠道可尝试加撸口子QQ群、网贷中介微信等方式,利用老哥们的集体智慧,以及网贷中介的丰富经验。站在对方的立场上,你更会发现自己风控系统的弱点。线下渠道可去一些欺诈案件多发地,实地调研来学习黑产的手法。实地调研的难度相对较高。 - -![](images/Pasted%20image%2020221201161454.png) - -图 2 - 逾期老哥自述 - -我们以网贷黑中介识别场景来介绍风险规则提炼的方法。例如,案件调研同学在综合分析逾期用户数据、信审催收反馈后,总结出几条经验规则: - -1. 中介通讯录中常会存客户的号码,并加以备注。例如:贷客杨贵州社保。 -2. 由于需要联系客户,运营商数据中往往留下痕迹,多个相互陌生的人同时打给中介。 -3. 网贷申请操作时,中介操作手法更为熟练,埋点行为数据上显示页面停留时间会更短。 -4. 申贷设备关联时,Wi-Fi名称上可能存在一些“贷款”字眼。 -5. 人脸活体验证时,存在一些明显的照片翻拍、视频通话等现象。 - -## Part 3. 反欺诈算法 - -智能算法是反欺诈战场的技术部队。尽管专家规则具有高准确率的优点,但其所能覆盖的人群非常有限。要知道,如果上线一套规则,只能覆盖很少的群体,那么性价比就很低;也会导致线上规则集冗长,不利于维护。为了提高召回率,此时就需要借助人工智能算法这个杠杆,将风险点放大。 - -数据是反欺诈的基础。此时就需要算法同学去搜集、清洗相应的数据,并根据数据类型和场景的特点,寻找合适的算法。例如,对于网贷黑中介识别场景,我们分别可采用: - -1. 社交关系网络:基于通讯录、运营商数据,采用基于图的社区发现算法(如Louvain)来发现团伙。 -2. embedding:基于埋点行为数据,利用LSTM、Word2Vec等算法来生成行为特征。 -3. 文本分类:基于论坛文本、通讯录名称、Wi-Fi名称进行分类。通常还可以利用主动学习框架来迭代优化。 -4. 图像分类:利用CNN等深度学习框架、预训练完毕的神经网络迁移学习,对图像多分类。 - -我们可以发现,上述方式可总结为:**风险事件驱动,提炼案件规则,技术算法支持。**这个过程相对需要花费很多的精力和时间。综合考虑时间成本,同时应对部分的欺诈风险,我们有没有一套兜底的方案呢? - -从欺诈者的角度理解,好不容易在信贷分期平台撸到一笔钱,既然动机就是骗贷,第一期一般就不会还。因此,很多平台就把首逾定义为目标变量,也就是FPD(First Payment Deliquency)模型。入模变量一般是一些负面特征,如“安装赌博APP的数量”、“历史逾期次数”等。特征的提取和构造同样需要从拒绝、逾期、黑户人群样本。 - -FPD模型基于欺诈的还款表现作为理论支撑。当然,其也存在一些缺陷: - -1. 逾期标签滞后性,首逾标签存在至少一个月的滞后性,不利于快速响应。 -2. 缺少拒绝人群标签,因此只在放贷样本上所训练的模型存在选择偏差问题,将会低估风险。 - -## Part 4. 反欺诈策略 - -反欺诈策略是反欺诈战场的决策部队,一般工作包括: - -1. 综合多方变量:无论是调研同学所提炼的规则,还是FPD模型,对于策略而言都是可用的变量,需要进一步集成加工。 -2. 拦截阈值cutoff分析:高于cutoff的人群予以拒绝,反之通过。拒绝人群的bad rate相对于大盘将会有几倍的提升(lift)?cutoff需要设定拒绝多少比例的人群合适? -3. 拦截率的稳定性:每个月的拦截率是否稳定? -4. 新旧策略之间的swap set分析:新策略相对于旧策略swap out多少坏用户?swap in多少好用户? -5. 决策引擎策略包配置:规则引擎配置,并决策上线。 -6. 反欺诈监控报表制作:上线变量后,需要监控对当前风险事件的控制,对通过率的影响等。 - -## Part 5. 总结 - -反欺诈一般包括案件调研(及时发现)、算法支持(快速诊断)、策略上线(准确覆盖)等一整套解决方案。 - -![](images/Pasted%20image%2020221201161530.png) - -图 3 - 反欺诈体系 - -兵法言,知己知彼,百战不殆。这就要求我们: - -1. 熟悉产品风控流程,梳理每一个环节可能存在的风险漏洞,主动提高防御等级。 -2. 深入理解欺诈人群,通过卧底、调研等方式掌握其心理特征、行为特征等,从而制定针对性的风控规则。 -3. 加大技术研发投入,尤其是人工智能算法在反欺诈中的应用。 - -最后总结一句体会,反欺诈是一个不容易评估效益回报的工作。站在某些老板的视角:欺诈人群没来,拦了没反馈,养你们不如养猪;欺诈人群来了,没拦住,养你们不如养猪。 - -## 参考资料 -[^1]:信贷风控-反欺诈:https://zhuanlan.zhihu.com/p/77238851 \ No newline at end of file diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\346\220\255\345\273\272\347\224\250\346\210\267\346\240\207\347\255\276\344\275\223\347\263\273.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\346\220\255\345\273\272\347\224\250\346\210\267\346\240\207\347\255\276\344\275\223\347\263\273.md" deleted file mode 100644 index 58bab84..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\346\220\255\345\273\272\347\224\250\346\210\267\346\240\207\347\255\276\344\275\223\347\263\273.md" +++ /dev/null @@ -1,114 +0,0 @@ -???+note - - 本页面介绍了用户标签体系的搭建,以及用户标签的作用。 - - 本文转自《金融风控研究院-搭建用户标签体系》 - -## 一、用户标签是什么 - -用户标签是构成用户画像的核心因素,是将用户在平台内所产生的行为数据,分析提炼后生成具有差异性特征的形容词。即用户通过平台,在什么时间什么场景下做了什么行为,平台将用户所有行为数据提炼出来形成支撑业务实现的可视化信息。 - -如图所示,“个性”“佛系”等词都是我们90后这代人群的标签。 - -![](images/Pasted%20image%2020221201154722.png) - -标签来源: - -产品初期:在产品还没有用户的情况下,主要通过大量用户调研和行业调研,基于产品定位和业务需要梳理出初始目标用户标签,前期的人工工作量相对繁重,可对初始标签的设定准确性远高于凭空想象。 - -产品发展期:基于原有数据沉淀分析出来的精准性标签,与用户行为产生的数据进行清洗整合,提炼出相对完善的用户标签;基于原有数据梳理标签,要注意数据排重,避免标签过于同质化。 - -## 二、如何搭建用户标签体系 - -![](images/Pasted%20image%2020221201154756.png) - -**(用户标签搭建纬度)** - -### 1. 标签属性 - -标签分为三种属性:静态标签判断用户基础需求,动态标签提升用户体验,预测标签提升用户转化,提高产品价值。 - -- **第一种静态标签**:用户主动提供的数据:指用户不变的基础信息,多为用户固定数据,如姓名、性别、年龄、身高、体重、职业、地区、设备信息、来源渠道等。 -- **第二种动态标签**:平台介入的数据:指用户在平台内的特有标签,是平台根据用户行为给用户打上便于管理的标签。用户行为是指用户从启动APP到关闭APP阶段内,在APP内所有操作行为,如用户的点击、浏览行为、互动(评论、点赞、转发、收藏)行为等。 -- **第三种预测标签:**平台介入的数据,指根据用户在平台内的行为数据对用户未来行为或喜好进行预测;是设计千人千面和运营策略的关键;比如某电商平台,根据用户A“月均消费5单,且有数额过万的运动商品”的购物数据,平台会给用户A打“高频、品质敏感性、运动”的标签,后期会更多推荐高品质运动商品及相关运动品牌活动的精准推送。 - -### 2. “贴标签”方式 - -标签由平台运营团队创建,结合业务场景梳理出一批原始标签;注意标签创建要紧贴业务场景,为用户“贴标签”通常有两种形式,即用户是否感知到自己被“贴了标签”。 - -**第一种隐性标签:**后台给用户打标签,用户无法感知;后台结合用户前端的点击浏览行为等用户行为操作,自动为用户贴上相应类别标签,这种方式的好处在于用户行为真实度极高,平台易获取无修饰无加工的用户行为数据,不足之处对于平台来讲前期人工成本较高。 - -**第二种显性标签:**用户主动给自己打标签,即用户在产品前端页面手动选择自己感兴趣的标签,用户通过触发标签机制,后台机器匹配数据直接打标签。这种方式优点在于高效,不足之处在于数据真实度偏低(初始标签存在无法满足所有用户的风险,用户也许会选择近义词也许跳过不选)。这种方式一般陌生社交产品和社区产品使用较多,目的是提升千人千面的精准度,提升用户体验。 - -若选择第二种形式,需要注意标签机制的设计规则(如标签默认前台固定页面展示,需用户手动选择后,标签自动隐藏不再显示)。其次后台注意标签选择排重,如出现A用户的标签既是后台添加又是用户自己选择,则保留用户自己选择标签。 - -最后要牢记:“用户也不知道自己要什么”,不是用户自己选择标签之后就万事大吉了,要结合用户行为数据持续优化标签。 - -### 3. 标签的优化 - -**第一种机器优化**:机器根据数据反馈持续更新,优点在于机器的高效智能,不足之处在于投入的技术成本以及机器欠缺一定的精准性。这种方式比较适合产品发展期,用户量较多,且有一套成熟的标签体系,机器已经可以达到一般的智能化,只需运营抽样进行精准度测试和标签规则优化即可。 - -**第二种人工优化**:人工对标签规则调整优化,优点是精准度高,不足在于人工运营成本高。这种方式适合产品初期,用户量小机器识别还不是很成熟,可以达到准确优化。 - -两种方式的选择需要结合产品周期和用户体量运用,无论何种方式,人工都需要持续根据产品业务场景对标签的规则进行调整优化,切记图省事忽略标签体系的优化,标签数据模糊,用户画像自然也会立不住,产品设计也会差强人意。 - -### 4. 好的标签是怎么落地执行的? - -**4.1 在公司中谁来做这件事?** - -![](images/Pasted%20image%2020221201154841.png) - -PS.如果对时效性要求很高,可以委托专业第三方数据公司操作,可以达到高效、节省人工成本的目的。 - -**4.2 具体要怎么做?** - -核心关键是:收集需求-建立规则-填充数据 - -**收集需求:**给用户贴标签一般由运营部主要负责,在策划前期,需要明确标签的目的及作用,少不了多方沟通协调。 - -比如社区产品,产品考虑千人千面的精准度,更关注用户的“内容兴趣”标签。运营希望提升商品的转化率,则更关注“消费习惯”标签。技术会关注数据提取便捷度,最理想状态是每次新需求都可以在同一信息平台调取,方便高效……大致每个公司基本这三个部门的需求是离不开的,其余差异性需求根据公司情况各异。 - -**建立规则:**需求收集后需要对需求进行分析梳理,结合业务场景,判断需求和业务的匹配程度,确定标签制定的目的,统一标签定义。这里要注意标签务必要符合业务场景搭建,且对标签定义达成内部共识,比如“流失用户”。 - -这个标签定义是指卸载APP的用户还是指没有卸载但三个月都未启动APP的用户?诸如此类标签定义需要内部达成统一共识,避免增加沟通成本及后期进行大的改动。 - -**填充数据:**明确数据支持信息,即什么样的数据和标签相匹配,这些数据普遍指用户基础数据(注册时用户填写的个人信息)、用户行为数据、用户业务数据(如某阶段购买最多的商品类别等沉淀在业务场景下的数据)、补充数据(泛指和其他平台合作的数据或第三方数据平台沉淀的数据),其他数据因公司而异。 - -产品部门结合产品定位和业务场景审核标签合理性。 - -最后交给技术实现,收集数据、清洗数据、分析数据(有的公司会交给数据部门执行,具体执行部门因司而异)。 - -**4.3 如何维护标签** - -核心关键是:信息透明、信息优化、信息同步。 - -- **信息透明:**即标签的规则、创建者、适用范围、版本等信息充分透明化管理,减少任何人调取标签使用的难度。 -- **信息优化:**用户标签会随着业务场景、用户角色等变量因素改变,而产品价值依赖变量因素持续变化,所以标签信息的持续优化是重中之重;标签的新增与修改等操作要注意与之相关的业务场景需求及影响,尤其要注意避免因职业差异对某些标签的理解问题,多沟通很重要,减少不必要的风险发生概率。 -- **信息同步:**这要求时效性,一旦标签信息有变,及时更新同步,提高运营效率。 - -## 三、标签的作用 - -产品的本质是用户,用户画像的本质是标签,给用户“贴标签”,最主要的作用是构建产品的用户画像,而精准的用户画像是多方共赢的前提。 - -公司战略:公司可持续发展的核心,一方面使公司更具竞争壁垒,及时洞察市场风向,预测产品所占市场规模及前景发展,及时优化公司战略,避免过早陷入发展瓶颈;另一方面沉淀大批用户数据,既利于孵化创新产品,也丰富盈利模式(比如与第三方合作)。 - -产品设计:提升产品价值关键因素,基于精准人群的需求分析和功能设计,更容易得到用户认可,更容易打造产品亮点,提供精准个性化的服务,比如对于社区产品,内容个性化推荐将有效提升社区粘度。 - -运营管理:提高运营效率;如今的新用户获客成本居高不下的情况下,利用现有用户画像,做好存量用户的维护,通过精准营销策略,提升存量用户的留存与活跃。 - -## 四、总结 - -1. 用户标签是构成用户画像的核心因素,是将用户在平台内所产生的行为数据,分析提炼后生成具有差异性特征的形容词。即用户通过平台,在什么时间什么场景下做了什么行为,平台将用户所有行为数据提炼出来形成支撑业务实现的可视化信息。 -2. 标签分为三种属性:静态标签判断用户基础需求,动态标签提升用户体验,预测标签提升用户转化,提高产品价值。 -3. “贴标签”形式有两种:用户主动选择特定标签和平台结合用户行为给用户“贴标签”。 -4. 标签优化方式:机器优化和人工优化。 -5. 搭建标签体系流程:收集需求-建立规则-填充数据-标签维护。 -6. 在公司中,搭建标签需运营、产品、技术协调配合完成;运营负责制定规则,产品结合业务审核标签合理性,技术负责实现。 -7. 标签的作用:增强公司竞争壁垒,提升产品价值,提高运营效率。 - -**Tips:** - -1. 业务导向:用户标签要贴近产品业务场景及产品所处行业建立,避免标签脱离业务。 -2. 数据验证:标签的准确性和数据息息相关,不能只通过用户1、2次点击某商品或内容,就确定用户对此感兴趣,要结合数据趋势变化,不断验证,以免片面下结论导致用户画像不准确。 -3. 持续优化:伴随用户年龄、偏好等阶段变化,用户需求和在平台内的行为会不断变化,保持敏锐的用户嗅觉,利于产品优化迭代,利于公司可持续发展。 - diff --git "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\350\264\267\346\254\276\346\213\250\345\244\207\347\216\207\345\222\214\346\213\250\345\244\207\350\246\206\347\233\226\347\216\207.md" "b/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\350\264\267\346\254\276\346\213\250\345\244\207\347\216\207\345\222\214\346\213\250\345\244\207\350\246\206\347\233\226\347\216\207.md" deleted file mode 100644 index a4d936a..0000000 --- "a/docs/loan/03-\351\243\216\346\216\247\347\233\221\347\256\241/\344\277\241\350\264\267\351\243\216\346\216\247-\350\264\267\346\254\276\346\213\250\345\244\207\347\216\207\345\222\214\346\213\250\345\244\207\350\246\206\347\233\226\347\216\207.md" +++ /dev/null @@ -1,59 +0,0 @@ -???+note - - 本页面简要介绍了风险监管中的两个监管指标: - - - 拨备覆盖率 - - 贷款拨备率 - - 本文转自《金融风控研究院-风控-贷款拨备率和拨备覆盖率》 - -风险拨备即商业银行或者金融机构按五级分类标准所提取的贷款损失准备金,主要是商业银行或者金融机构为了补偿未来可能发生的损失而提前做好的资金储备,一般在商业银行或者金融机构中属于成本项。 - -五级分类的提取比率分别是正常1%、关注2%,次级25%、可疑50%、损失100%。 - -比如银行贷款给客户,但这些客户中可能会有一部分人会还不了钱,那么客户还不了的钱就会成为银行的坏账,坏账是要冲销的,就会从银行净利润中的一部份钱来做冲销。 - -**其中有两个非常重要的监管指标,一个是拨备覆盖率,另一个就是贷款拨备率。** - -银行作为提供金融服务,经营风险的企业,所承担的全部风险损失能够被补偿和消化是生存发展与稳健经营的前提和关键。正因为这样,对资产风险的预期损失是否足额拨备、资本充足率是否满足监管要求,就成了衡量银行抵御金融风险能力的重要指标。 - -## 一、贷款拨备率 - -贷款拨备率实际上就是呆、坏账准备金的提取比率;是指贷款损失准备计提余额与贷款余额的比率,是反映商业银行拨备计提水平的重要监管指标之一。 - -**计算方式:** - -**贷款拨备率=贷款损失准备金÷各项贷款余额 x 100%** - -设有10家房地产商,每家投资开发一楼盘需要11亿元资金,每家自有资金1亿元,每家向同一个银行贷款10亿元。合同规定年初银行贷款给房地产商,年底房地产商连本带息还给该银行。该银行共贷款100亿元给这10家房地产商,每家10亿元。 - -假设这是该银行的全部贷款。由于贷款尚未偿还,故这100亿元也称之为贷款余额。为了防范房地产商不能偿还贷款,该银行准备了10亿元贷款损失准备金,因为尚不存在偿还贷款的情况,这10亿元钱也称之为贷款损失准备金余额。由贷款拨备率的计算公式: - -**贷款拨备率= (贷款损失准备金余额/各项贷款余额) x 100% = (10/100)x100%=10%** - -那么这家银行的贷款拨备率为百分之十。 - -贷款拨备率主要反映商业银行拨备计提水平,拨备率的高低应适合风险程度,不能过低导致拨备金不足,利润虚增;也不能过高导致拨备金多余,利润虚降。 - -## 二、拨备覆盖率 - -拨备覆盖率(也称为“拨备充足率”)是实际上银行贷款可能发生的呆、坏账准备金的使用比率。不良贷款拨备覆盖率是衡量商业银行贷款损失准备金计提是否充足的一个重要指标。 - -**计算方式:** - -**拨备覆盖率=贷款损失准备金÷不良贷款余额** - -小王把100块钱分别借给A、B、C、D, 但非常担心借给A (6块)、B、C、D的钱收不上来。比如A的资产状况出了问题,那么小王为了提防这6块还上来而从自己的腰包中抽出10块放到指定的账户,将来A果真还不上钱,那么小王就从这个指定账户拿出钱来核销。 - -**在这个过程中,10块钱就是贷款损失准备金计提余额,6块钱是不良资产,10÷6= 1.667。就是拨备覆盖率。** - -那么再算收入时,小王只能把这笔钱算做10元贷款损失准备金计提余额,也就影响收益了。也可以简单理解为不良贷款可能损失10元,那么小王先剔除出10元,然后计算盈利水平。使实际盈利接近于真实状况。因为所有的贷款只要没到期之前,谁也不敢说是否能够还清,这是对损失的一种提前预测。 - -回到现实,假如银行a的贷款是100块,不良贷款为8元,如果按照此前的拨备覆盖率不得低于150%计算,那么银行需要计提12块钱的贷款损失准备金(这12块钱一般是从利润中提现),如果拨备覆盖率降到120%,那么同等8块钱的不良贷款下,银行a只需要计提9.6块的贷款损失准备金就够了。 - -拨备覆盖率主要反映商业银行对贷款损失的弥补能力和对贷款风险的防范能力,此项比率应不低于100%,否则为计提不足,存在准备金缺口,拨备覆盖率越高说明抵御风险的能力越强。 - -风险拨备是商业银行或者金融机构贷款损失准备和资产损失准备,对提高消化不良资产的能力具有关键性作用,所以其重要性可想而知。 - -## 参考资料 -[^1]:金融风控研究院-贷款拨备率和拨备覆盖率 \ No newline at end of file diff --git "a/docs/tools/editor/VIM\350\257\255\346\263\225.md" b/docs/tools/editor/vim-zen.md similarity index 66% rename from "docs/tools/editor/VIM\350\257\255\346\263\225.md" rename to docs/tools/editor/vim-zen.md index 1dc6fe5..7ccdab4 100644 --- "a/docs/tools/editor/VIM\350\257\255\346\263\225.md" +++ b/docs/tools/editor/vim-zen.md @@ -3,10 +3,10 @@ 动词代表了我们打算对文本进行什么操作。例如: - d 删除 delete -- r 替换 [replace](https://www.zhihu.com/search?q=replace&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D) +- r 替换 replace - c 修改 change - y 复制 yank -- v 选取 [visual select](https://www.zhihu.com/search?q=visual%20select&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D) +- v 选取 visual select ## **1.2 名词** 名词代表了我们即将处理的文本。Vim 中有一个专门的术语叫做[文本对象](https://www.zhihu.com/search?q=%E6%96%87%E6%9C%AC%E5%AF%B9%E8%B1%A1&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D)text object,示例: @@ -17,17 +17,17 @@ - t HTML标签tag - 引号或者各种括号所包含的文本称作一个文本块。 -## **1.3 介词 +## 1.3 介词 介词界定了待编辑文本的范围或者位置。例如: - i “在…之内”inside - a “环绕…”around - t “到…位置前”to -- f “到…位置上”[forward](https://www.zhihu.com/search?q=forward&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D) +- f “到…位置上forward -## **1.4 组词为句** +## 1.4 组词为句 [文本编辑](https://www.zhihu.com/search?q=%E6%96%87%E6%9C%AC%E7%BC%96%E8%BE%91&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D)命令的基本语法如下: **动词+介词+名词** @@ -41,7 +41,7 @@ - 删除文本直到字符“x”(包括字符“x”)delete forward x: dfx -## **1.5 数词** +## 1.5 数词 数词指定了待编辑文本对象的数量, 语法就成了这样: **动词+介词/数词+名词** @@ -54,5 +54,5 @@ **数词+动词+名词** 示例: -- 两次删除单词(等价于删除两个单词) [twice delete word](https://www.zhihu.com/search?q=twice%20delete%20word&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra=%7B%22sourceType%22%3A%22answer%22%2C%22sourceId%22%3A1733228460%7D): 2dw +- 两次删除单词(等价于删除两个单词) twice delete word: 2dw - 三次删除字符(等价于删除三个字符)three times delete character: 3x \ No newline at end of file diff --git a/docs/tools/images/latex-for-beginners-1.png b/docs/tools/images/latex-for-beginners-1.png deleted file mode 100644 index a35d798..0000000 Binary files a/docs/tools/images/latex-for-beginners-1.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-10.png b/docs/tools/images/latex-for-beginners-10.png deleted file mode 100644 index c198045..0000000 Binary files a/docs/tools/images/latex-for-beginners-10.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-11.png b/docs/tools/images/latex-for-beginners-11.png deleted file mode 100644 index eb1ee85..0000000 Binary files a/docs/tools/images/latex-for-beginners-11.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-12.png b/docs/tools/images/latex-for-beginners-12.png deleted file mode 100644 index 3339222..0000000 Binary files a/docs/tools/images/latex-for-beginners-12.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-13.png b/docs/tools/images/latex-for-beginners-13.png deleted file mode 100644 index d0beea2..0000000 Binary files a/docs/tools/images/latex-for-beginners-13.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-14.png b/docs/tools/images/latex-for-beginners-14.png deleted file mode 100644 index 2269d53..0000000 Binary files a/docs/tools/images/latex-for-beginners-14.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-15.png b/docs/tools/images/latex-for-beginners-15.png deleted file mode 100644 index 9ac0a5e..0000000 Binary files a/docs/tools/images/latex-for-beginners-15.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-2.png b/docs/tools/images/latex-for-beginners-2.png deleted file mode 100644 index aab6b70..0000000 Binary files a/docs/tools/images/latex-for-beginners-2.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-3.png b/docs/tools/images/latex-for-beginners-3.png deleted file mode 100644 index 01d5d6f..0000000 Binary files a/docs/tools/images/latex-for-beginners-3.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-4.png b/docs/tools/images/latex-for-beginners-4.png deleted file mode 100644 index 3733ab9..0000000 Binary files a/docs/tools/images/latex-for-beginners-4.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-5.png b/docs/tools/images/latex-for-beginners-5.png deleted file mode 100644 index ec007b5..0000000 Binary files a/docs/tools/images/latex-for-beginners-5.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-6.png b/docs/tools/images/latex-for-beginners-6.png deleted file mode 100644 index 94a89d1..0000000 Binary files a/docs/tools/images/latex-for-beginners-6.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-7.png b/docs/tools/images/latex-for-beginners-7.png deleted file mode 100644 index 2cbfe4b..0000000 Binary files a/docs/tools/images/latex-for-beginners-7.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-8.png b/docs/tools/images/latex-for-beginners-8.png deleted file mode 100644 index 0f88426..0000000 Binary files a/docs/tools/images/latex-for-beginners-8.png and /dev/null differ diff --git a/docs/tools/images/latex-for-beginners-9.png b/docs/tools/images/latex-for-beginners-9.png deleted file mode 100644 index 93a293f..0000000 Binary files a/docs/tools/images/latex-for-beginners-9.png and /dev/null differ diff --git a/docs/tools/lang/c-cpp.md b/docs/tools/lang/c-cpp.md deleted file mode 100644 index 8aeeb6c..0000000 --- a/docs/tools/lang/c-cpp.md +++ /dev/null @@ -1,87 +0,0 @@ -本文介绍 C 与 C++ 之间重要的或者容易忽略的区别。尽管 C++ 几乎是 C 的超集,C/C++ 代码混用一般也没什么问题,但是了解 C/C++ 间比较重要区别可以避免碰到一些奇怪的 bug。如果你是以 C 为主力语言的 OIer,那么本文也能让你更顺利地上手 C++。C++ 相比 C 增加的独特特性可以阅读 C++ 进阶 部分的教程。 - -## 宏与模板 - -C++ 的模板在设计之初的一个用途就是用来替换宏定义。学会模板编程是从 C 迈向 C++ 的重要一步。模板不同于宏的文字替换,在编译时会得到更全面的编译器检查,便于编写更健全的代码,利用 inline 关键字还能获得编译器充分的优化。模板特性在 C++11 后支持了可变长度的模板参数表,可以用来替代 C 中的可变长度函数并保证类型安全。 - -## 指针与引用 - -C++ 中你仍然可以使用 C 风格的指针,但是对于变量传递而言,更推荐使用 C++ 的 引用特性来实现类似的功能。由于引用指向的对象不能为空,因此可以避免一些空地址访问的问题。不过指针由于其灵活性,也仍然有其用武之处。值得一提的是,C 中的 `NULL` 空指针在 C++11 起有类型安全的替代品 `nullptr`。引用和指针之间可以通过 `*` 和 `&` 运算符 相互转换。 - -## bool - -与 C++ 不同的是,C 语言最初并没有布尔类型。 - -C99 标准加入了 `_Bool` 关键字(以及等效的 `bool` 宏)以及 `true` 和 `false` 两个宏。如果需要使用 `bool`,`true`,`false` 这三个宏,需要在程序中引入 `stdbool.h` 头文件。而使用 `_Bool` 则不需要引入任何额外头文件。 - -```c -bool x = true; // 需要引入 stdbool.h -_Bool x = 1; // 不需要引入 stdbool.h -``` - -C23 起,`true` 和 `false` 成为 C 语言中的关键字,使用它们不需要再引入 `stdbool.h` 头文件[^true-false-become-keyword]。 - -下表展示了 C 语言不同标准下,bool 类型支持的变化情况(作为对照,加入了 C++ 的支持情况): - -| 语言标准 | `bool` | `true`/`false` | `_Bool` | -| ------------ | --------------------------------- | ----------------------------------------------------- | ------------------------- | -| C89 | / | / | 保留[^reserved-identifiers] | -| C99 起,C23 以前 | 宏,与 `_Bool` 等价,需要 `stdbool.h` 头文件 | 宏,`true` 与 `1` 等价,`false` 与 `0` 等价,需要 `stdbool.h` 头文件 | 关键字 | -| C23 起 | 宏,与 `_Bool` 等价,需要 `stdbool.h` 头文件 | 关键字 | 关键字 | -| C++ | 关键字 | 关键字 | 保留[^reserved-identifiers] | - -## struct - -尽管在 C 和 C++ 中都有 struct 的概念,但是他们对应的东西是不能混用的!C 中的 struct 用来描述一种固定的内存组织结构,而 C++ 中的 struct 就是一种类,**它与类唯一的区别就是它的成员和继承行为默认是 public 的**,而一般类的默认成员是 private 的。这一点在写 C/C++ 混合代码时尤其致命。 - -另外,声明 struct 时 C++ 也不需要像 C 那么繁琐,C 版本: - -```c -typedef struct Node_t { - struct Node_t *next; - int key; -} Node; -``` - -C++ 版本 - -```cpp -struct Node { - Node *next; - int key; -}; -``` - -## const - -const 在 C 中只有限定变量不能修改的功能,而在 C++ 中,由于大量新特性的出现,const 也被赋予的更多用法。C 中的 const 在 C++ 中的继任者是 constexpr。 - -## 内存分配 - -C++ 中新增了 `new` 和 `delete` 关键字用来在“自由存储区”上分配空间,这个自由存储区可以是堆也可以是静态存储区,他们是为了配合“类”而出现的。其中 `delete[]` 还能够直接释放动态数组的内存,非常方便。`new` 和 `delete` 关键字会调用类型的构造函数和析构函数,相比 C 中的 `malloc()`、`realloc()`、`free()` 函数,他们对类型有更完善的支持,但是效率不如 C 中的这些函数。 - -简而言之,如果你需要动态分配内存的对象是基础类型或他们的数组,那么你可以使用 `malloc()` 进行更高效的内存分配;但如果你新建的对象是非基础的类型,那么建议使用 `new` 以获得安全性检查。值得注意的是尽管 `new` 和 `malloc()` 都是返回指针,但是 `new` 出来的指针 **只能** 用 `delete` 回收,而 `malloc()` 出来的指针也只能用 `free()` 回收,否则会有内存泄漏的风险。 - -## 变量声明 - -C99 前,C 的变量声明必须位于语句块开头,C++ 和 C99 后无此限制。 - -## 可变长数组 - -C99 后 C 语言支持 VLA(可变长数组),C++ 始终不支持。 - -## 结构体初始化 - -C99 后 C 语言支持结构体的 [指派符初始化](https://en.cppreference.com/w/c/language/struct_initialization)(但是在 C11 中为可选特性),C++ 直到 C++20 才支持有顺序要求的指派符初始化,且 C 语言支持的乱序、嵌套、与普通初始化器混用、数组的指派符初始化特性 C++ 都不支持[^cpp-designated-init]。 - -## 注释语法 - -C++ 风格单行注释 `//`,C 于 C99 前不支持。 - -## 参考资料 - -[^cpp-designated-init]: - -[^true-false-become-keyword]: 。 - -[^reserved-identifiers]: C 和 C++ 均规定,以一个下划线跟着一个大写字母开头的标识符是被保留的,详见 。 diff --git a/docs/tools/lang/images/python1.png b/docs/tools/lang/images/python1.png deleted file mode 100644 index 623b62f..0000000 Binary files a/docs/tools/lang/images/python1.png and /dev/null differ diff --git a/docs/tools/lang/images/python2.png b/docs/tools/lang/images/python2.png deleted file mode 100644 index 208707f..0000000 Binary files a/docs/tools/lang/images/python2.png and /dev/null differ diff --git a/docs/tools/lang/java.md b/docs/tools/lang/java.md deleted file mode 100644 index 44a1238..0000000 --- a/docs/tools/lang/java.md +++ /dev/null @@ -1,424 +0,0 @@ -## 关于 Java - -Java 是一种广泛使用的计算机编程语言,拥有 **跨平台**、**面向对象**、**泛型编程** 的特性,广泛应用于企业级 Web 应用开发和移动应用开发。 - -## 环境安装 - -### Windows - -可以在 [Oracle 官网](https://www.oracle.com/java/technologies/javase-downloads.html) 下载 Oracle JDK(需要登录 Oracle 账号)。推荐下载 EXE 安装包来自动配置环境变量。 - -如果需要使用 OpenJDK,可以使用 [AdoptOpenJDK](https://adoptopenjdk.net/) 提供的预编译包。如果下载较慢,可以使用 [清华大学 TUNA 镜像站](https://mirrors.tuna.tsinghua.edu.cn/AdoptOpenJDK/)。推荐下载 MSI 安装包来自动配置环境变量。 - -### Linux - -#### 使用包管理器安装 - -可以使用包管理器提供的 JDK。 - -如果是 Debian 及其衍生发行版(包括 Ubuntu),命令如下: - -```bash -sudo apt install default-jre -sudo apt install default-jdk -``` - -如同时安装了多个版本,可通过 `update-java-alternatives -l` 查看目前使用的版本,通过 `update-java-alternatives -s ` 更改使用的版本。 - -如果 CentOS 7 及以前则使用的是 `yum` 安装,命令如下: - -```bash -sudo yum install java-1.8.0-openjdk -``` - -在稍后询问是否安装时按下y继续安装,或是你已经下好了 `rpm` 文件,可以使用以下命令安装: - -```bash -sudo yum localinstall jre-9.0.4_linux_x64_bin.rpm #安装jre-9.0 -sudo yum localinstall jdk-9.0.4_linux-x64_bin.rpm #安装jdk-9.0 -``` - -如果 CentOS 8 则使用的是 `dnf` 安装,命令如下: - -```bash -sudo dnf install java-1.8.0-openjdk -``` - -在稍后询问是否安装时按下y继续安装,或是你已经下好了 `rpm` 文件,可以使用以下命令安装: - -```bash -sudo dnf install jre-9.0.4_linux_x64_bin.rpm #安装jre-9.0 -sudo dnf install jdk-9.0.4_linux-x64_bin.rpm #安装jdk-9.0 -``` - -如果是 Arch 及其衍生发行版(如 Manjaro),命令如下: - -```bash -sudo pacman -S jdk8-openjdk # 8可以替换为其他版本,不加则为最新版 -``` - -如同时安装了多个版本,可通过 `archlinux-java status` 查看目前使用的版本,通过 `archlinux-java set ` 更改使用的版本。 - -#### 手动安装 - -```bash -sudo mv jdk-14 /opt -``` - -并在 `.bashrc` 文件末尾添加: - -```bash -export JAVA_HOME="/opt/jdk-14" -export PATH=$JAVA_HOME/bin:$PATH -``` - -在控制台中输入命令 `source ~/.bashrc` 即可重载。如果是使用的 zsh 或其他命令行,在 `~/.zshrc` 或对应的文件中添加上面的内容。 - -### macOS - -如果是 macOS,你可以使用以下命令安装包: - -```bash -cd ~/Downloads -curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u121-b13/e9e7ea248e2c4826b92b3f075a80e441/jdk-8u121-macosx-x64.dmg > jdk-8u121-macosx-x64.dmg -hdiutil attach jdk-8u121-macosx-x64.dmg -sudo installer -pkg /Volumes/JDK\ 8\ Update\ 121/JDK\ 8\ Update\ 121.pkg -target / -diskutil umount /Volumes/JDK\ 8\ Update\ 121 -rm jdk-8u121-macosx-x64.dmg -``` - -或者直接在官方网站下载 `pkg` 包或 `dmg` 包安装。 - -## 基本语法 - -### 主函数 - -Java 类似 C/C++ 语言,需要一个函数(在面向对象中,这被称为方法)作为程序执行的入口点。 - -Java 的主函数的格式是固定的,形如: - -```java -class Test { - public static void main(String[] args) { - // 程序的代码 - } -} -``` - -一个打包的 Java 程序(名称一般是 `*.jar`)中可以有很多个类似的函数,但是当运行这个程序的时候,只有其中一个函数会被运行,这是定义在 `Jar` 的 `Manifest` 文件中的,在 OI 比赛中一般用不到关于它的知识。 - -### 注释 - -和 C/C++ 一样,Java 使用 `//` 和 `/* */` 分别注释单行和多行。 - -### 基本数据类型 - -| 类型名 | 意义 | -| :-----: | :---: | -| boolean | 布尔类型 | -| byte | 字节类型 | -| char | 字符型 | -| double | 双精度浮点 | -| float | 单精度浮点 | -| int | 整型 | -| long | 长整型 | -| short | 短整型 | -| null | 空 | - -### 声明变量 - -```java -int a = 12; // 设置 a 为整数类型,并给 a 赋值为 12 -String str = "Hello, OI-wiki"; // 声明字符串变量 str -char ch = 'W'; -double PI = 3.1415926; -``` - -### final 关键字 - -`final` 含义是这是最终的、不可更改的结果,被 `final` 修饰的变量只能被赋值一次,赋值后不再改变。 - -```java -final double PI = 3.1415926; -``` - -### 数组 - -```java -// 有十个元素的整数类型数组 -// 其语法格式为 数据类型[] 变量名 = new 数据类型[数组大小] -int[] ary = new int[10]; -``` - -### 字符串 - -- 字符串是 Java 一个内置的类。 - -```java -// 最为简单的构造一个字符串变量的方法如下 -String a = "Hello"; - -// 还可以使用字符数组构造一个字符串变量 -char[] stringArray = { 'H', 'e', 'l', 'l', 'o' }; -String s = new String(stringArray); -``` - -### 包和导入包 - -Java 中的类(`Class`)都被放在一个个包(`package`)里面。在一个包里面不允许有同名的类。在类的第一行通常要说明这个类是属于哪个包的。例如: - -```java -package org.oi-wiki.tutorial; -``` - -包的命名规范一般是:`项目所有者的顶级域.项目所有者的二级域.项目名称`。 - -通过 `import` 关键字来导入不在本类所属的包下面的类。例如下面要用到的 `Scanner`: - -```java -import java.util.Scanner; -``` - -如果想要导入某包下面所有的类,只需要把这个语句最后的分号前的类名换成 `*`。 - -### 输入 - -可以通过 `Scanner` 类来处理命令行输入。 - -```java -package org.oiwiki.tutorial; - -import java.util.Scanner; - -class Test { - public static void main(String[] args) { - Scanner scan = new Scanner(System.in); // System.in 是输入流 - int a = scan.nextInt(); - double b = scan.nextDouble(); - String c = scan.nextLine(); - } -} -``` - -### 输出 - -可以对变量进行格式化输出。 - -| 符号 | 意义 | -| :--: | :---: | -| `%f` | 浮点类型 | -| `%s` | 字符串类型 | -| `%d` | 整数类型 | -| `%c` | 字符类型 | - -```java -class Test { - public static void main(String[] args) { - int a = 12; - char b = 'A'; - double s = 3.14; - String str = "Hello world"; - System.out.printf("%f\n", s); - System.out.printf("%d\n", a); - System.out.printf("%c\n", b); - System.out.printf("%s\n", str); - } -} -``` - -### 更高速的输入输出 - -`Scanner` 和 `System.out.print` 在最开始会工作的很好,但是在处理更大的输入的时候会降低效率,因此我们会使用来自 Kattis 的 [Kattio.java](https://github.com/Kattis/kattio/blob/master/Kattio.java) 来提高 IO 效率。[^ref1] - -下方即为应包含在代码中的 IO 模板,由于 Kattis 的原 Kattio 包含一些并不常用的功能,下方的模板经过了一些调整(原 Kattio 使用 MIT 作为协议)。 - -```java -class Kattio extends PrintWriter { - private BufferedReader r; - private StringTokenizer st; - // 标准 IO - public Kattio() { this(System.in,System.out); } - public Kattio(InputStream i, OutputStream o) { - super(o); - r = new BufferedReader(new InputStreamReader(i)); - } - // 文件 IO - public Kattio(String intput, String output) throws IOException { - super(output); - r = new BufferedReader(new FileReader(intput)); - } - // 在没有其他输入时返回 null - public String next() { - try { - while (st == null || !st.hasMoreTokens()) - st = new StringTokenizer(r.readLine()); - return st.nextToken(); - } catch (Exception e) {} - return null; - } - public int nextInt() { return Integer.parseInt(next()); } - public double nextDouble() { return Double.parseDouble(next()); } - public long nextLong() { return Long.parseLong(next()); } -} -``` - -而下方代码简单展示了 Kattio 的使用: - -```java -class Test { - public static void main(String[] args) { - Kattio io = new Kattio(); - // 字符串输入 - String str = io.next(); - // int 输入 - int num = io.nextInt(); - // 输出 - io.println("Result"); - // 请确保关闭 IO 流以确保输出被正确写入 - io.close(); - } -} -``` - -### 控制语句 - -Java 的流程控制语句与 C++ 是基本相同的。 - -#### 选择 - -- if - -```java -class Test { - public static void main(String[] args) { - if ( /* 判断条件 */ ){ - // 条件成立时执行这里面的代码 - } - } -} -``` - -- if...else - -```java -class Test { - public static void main(String[] args) { - if ( /* 判断条件 */ ) { - // 条件成立时执行这里面的代码 - } else { - // 条件不成立时执行这里面的代码 - } - } -} -``` - -- if...else if...else - -```java -class Test { - public static void main(String[] args) { - if ( /* 判断条件 */ ) { - //判断条件成立执行这里面的代码 - } else if ( /* 判断条件2 */ ) { - // 判断条件2成立执行这里面的代码 - } else { - // 上述条件都不成立执行这里面的代码 - } - } -} -``` - -- switch...case - -```java -class Test { - public static void main(String[] args) { - switch ( /* 表达式 */ ){ - case /* 值 1 */: - // 当表达式取得的值符合值 1 执行此段代码 - break; // 如果不加上 break 语句,会让程序按顺序往下执行直到 break - case /* 值 2 */: - // 当表达式取得的值符合值 2 执行此段代码 - break; - default: - // 当表达式不符合上面列举的值的时候执行这里面的代码 - } - } -} -``` - -#### 循环 - -- for - -`for` 关键字有两种使用方法,其中第一种是普通的 `for` 循环,形式如下: - -```java -class Test { - public static void main(String[] args) { - for ( /* 初始化 */; /* 循环的判断条件 */; /* 每次循环后执行的步骤 */ ) { - // 当循环的条件成立执行循环体内代码 - } - } -} -``` - -第二种是类似 C++ 的 `foreach` 使用方法,用于循环数组或者集合中的数据,相当于把上一种方式中的循环变量隐藏起来了,形式如下: - -```java -class Test { - public static void main(String[] args) { - for ( /* 元素类型X */ /* 元素名Y */ : /* 集合Z */ ) { - // 这个语句块的每一次循环时,元素Y分别是集合Z中的一个元素。 - } - } -} -``` - -- while - -```java -class Test { - public static void main(String[] args) { - while ( /* 判定条件 */ ) { - // 条件成立时执行循环体内代码 - } - } -} -``` - -- do...while - -```java -class Test { - public static void main(String[] args) { - do { - // 需要执行的代码 - } while ( /* 循环判断条件 */ ); - } -} -``` - -## 注意事项 - -### 类名与文件名一致 - -创建 Java 源程序需要类名和文件名一致才能编译通过,否则编译器会提示找不到类。通常该文件名会在具体 OJ 中指定。 - -例: - -`Add.java` - -```java -class Add { - public static void main(String[] args) { - // ... - } -} -``` - -在该文件中需使用 `Add` 为类名方可编译通过。 - -## 参考资料 - -[^ref1]: [Input & Output - USACO Guide](https://usaco.guide/general/input-output?lang=java#method-3---io-template) diff --git a/docs/tools/lang/python.md b/docs/tools/lang/python.md deleted file mode 100644 index 0f5130e..0000000 --- a/docs/tools/lang/python.md +++ /dev/null @@ -1,742 +0,0 @@ -## 关于 Python - -Python 是一种目前已在世界上广泛使用的解释型面向对象语言,非常适合用来测试算法片段和原型,也可以用来刷一些 OJ。 - -### 为什么要学习 Python - -- Python 是一种 **解释型** 语言:类似于 PHP 与 Perl,它在开发过程中无需编译,即开即用,跨平台兼容性好。 -- Python 是一种 **交互式** 语言:您可以在命令行的提示符 `>>>` 后直接输入代码,这将使您的代码更易于调试。 -- Python 易学易用,且覆盖面广:从简单的输入输出到科学计算甚至于大型 WEB 应用,Python 可以帮助您在 **极低的学习成本** 下快速写出适合自己的程序,从而让您的程序生涯如虎添翼,为以后的学习和工作增加一项实用能力。 -- Python 易读性强,且在世界广泛使用:这意味着您能够在使用过程中比其他语言 **更快获得支持**,**更快解决问题**。 -- 哦,还有一个最重要的:它在各平台下的环境易于配置,并且目前市面上大部分流行的 Linux 发行版(甚至于 `NOI Linux`)中也大都 **内置** 了个版本比较旧的 Python,这意味着您能真正在考场上使用它,让它成为您的最佳拍档。 - -### 学习 Python 时需要注意的事项 - -- 目前的 Python 分为 Python 2 和 Python 3 两个版本,其中 Python 2 虽然 [几近废弃](https://pythonclock.org/),但是仍被一些老旧系统和代码所使用。我们通常不能确定在考场上可以使用的版本。此处 **介绍较新版本的 Python**。但还是建议读者确认考场环境,了解一下 Python 2 的相关语法,并比较两者之间的差异。 -- 如果您之前使用 C++ 语言,那么很遗憾地告诉您,Python 的语法结构与 C++ 差异还是比较大的,请注意使用的时候不要混淆。 -- 由于 Python 是高度动态的解释型语言,因此其程序运行有大量的额外开销。尤其是 **for 循环在 Python 中运行的奇慢无比**。因此在使用 Python 时若想获得高性能,尽量使用 `filter`,`map` 等内置函数,或者使用 [列表生成](https://www.pythonforbeginners.com/basics/list-comprehensions-in-python) 语法的手段来避免循环。 - -## 环境安装 - -### Windows - -访问 ,下载自己需要的版本并安装。 -另外为了方便,请务必勾选 `Add Python 3.x to PATH` 以确保将 Python 加入环境变量! -如在如下的 Python 3.7.4 安装界面中,应该如图勾选最下一项复选框。 - -![py3.7.4](./images/python1.png) - -安装完成后,您可以在开始菜单找到安装好的 Python。 - -![start](./images/python2.png) - -此外,您还可以在命令提示符中运行 Python。 - -正常启动后,它会先显示欢迎信息与版本信息以及版权声明,之后就会出现提示符 `>>>`,一般情况下如下所示: - -```console -$ python3 -Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)] on win32 -Type "help", "copyright", "credits" or "license" for more information. ->>> -``` - -这就是 Python 的 **IDLE**。 - -???+ note "何谓 [**IDLE**](https://docs.python.org/zh-cn/3/glossary.html#term-idle)?" - Python 的 IDE,“集成开发与学习环境”的英文缩写。是 Python 标准发行版附带的基本编程器和解释器环境。在其他 Python 发行版(如 Anaconda)中还包含 [IPython](https://ipython.org/),[Spyder](https://www.spyder-ide.org/) 等更加先进的 IDE。 - -额外地,可以在 Microsoft 商店 [免费获取 Python](https://www.microsoft.com/store/productId/9P7QFQMJRFP7)。 - -### macOS/Linux - -通常情况下,正如上文所说,大部分的 Linux 发行版中已经自带了 Python,如果您只打算学学语法并无特别需求,一般情况下不用再另外安装。通常而言,在 Linux 终端中运行 `python2` 进入的是 Python 2,而运行 `python3` 进入的是 Python 3。 - -而由于种种依赖问题(如 CentOS 的 yum ),自行编译安装后通常还要处理种种问题,这已经超出了本文的讨论范畴。可以使用 venv、conda、Nix 等工具来管理 Python、Python 工具链和 Python 软件包,避免出现依赖问题。 - -而在这种情况下您一般能直接通过软件包管理器来进行安装,如在 Ubuntu 下安装 `Python 3`: - -```bash -sudo apt install python3 -``` - -更多详情您可以直接在搜索引擎上使用关键字 `系统名称(标志版本) 安装 Python 2/3` 来找到对应教程。 - -???+ note "运行 `python` 还是 `python3` ?" - 根据 [Python 3 官方文档](https://docs.python.org/zh-cn/3/tutorial/interpreter.html) 的说法,在 Unix 系统中,`Python 3.X` 解释器 **默认安装**(指使用软件包管理器安装)后的执行文件并不一定叫作 `python`,以免与可能同时安装的 `Python 2.X` 冲突。同样的,默认安装的 pip 软件也是类似的情况,Python 3 包管理器的文件名为 `pip3`。`python` 这个名字指向 `python2` 还是 `python3` 则视系统和系统版本确定。所以,当使用 Python 3 有关的时,请使用 `python3` 和 `pip3` 以确保准确,同理,Python 2 最好使用 `python2` 和 `pip2`。 - -### 关于镜像和 pip - -目前国内关于 **源码** 的镜像缓存主要是 [北京交通大学](https://mirror.bjtu.edu.cn/python/) 和 [华为开源镜像站](https://repo.huaweicloud.com/python/) 在做,如果您有下载问题的话可以到那里尝试一下。 - -如果您还有使用 pip 安装其他模块的需求,请参照 [TUNA 的镜像更换帮助](https://mirrors.tuna.tsinghua.edu.cn/help/pypi/)。 - -???+ note "[**pip**](https://pypi.org/project/pip/) 是什么?" - Python 的默认包管理器,用来安装第三方 Python 库。它的功能很强大,能够处理版本依赖关系,还能通过 wheel 文件支持二进制安装。pip 的库现在托管在 [PyPI](https://pypi.org)(即“Python 包索引”)平台上,用户也可以指定第三方的包托管平台。 - -关于 PyPI 的镜像,可以使用如下大镜像站的资源: - -- [清华大学 TUNA 镜像站](https://mirrors.tuna.tsinghua.edu.cn/help/pypi/) -- [中国科学技术大学镜像站](http://mirrors.ustc.edu.cn/help/pypi.html) -- [豆瓣的 PyPI 源](https://pypi.douban.com/simple) -- [华为开源镜像站](https://mirrors.huaweicloud.com/) -- 针对教育网内的镜像站,您可以在 [MirrorZ](https://mirrorz.org/list/pypi) 上查看更多详情。 - -## 基本语法 - -Python 以其简洁易懂的语法而出名。它基本的语法结构可以非常容易地在网上找到,例如 [菜鸟教程](http://www.runoob.com/python/python-basic-syntax.html) 就有不错的介绍。这里仅介绍一些对 OIer 比较实用的语言特性。 - -### 关于注释 - -鉴于后文中会高频用到注释,我们先来了解一下注释的语法。 - -```python3 -# 用 # 字符开头的是单行注释 - -""" 跨多行字符串会用三个引号 - 包裹,但也常被用来做多 - 行注释. (NOTE: 在字符串中 - 不会考虑缩进问题) -""" -``` - -加入注释代码并不会对代码产生影响。我们鼓励加入注释来使您的代码更加易懂易用。 - -### 基本数据类型与运算 - -有人说,你可以把你系统里装的 Python 当作一个多用计算器,这是事实。 -你可以在提示符 `>>>` 后面输入一个表达式,就像其他大部分语言(如 C++)一样使用运算符 `+`、`-`、`*`、`/` 来对数字进行运算;还可以使用 `()` 来进行符合结合律的分组,例如: - -```python3 ->>> 233 # 整数就是整数 -233 - ->>> 5 + 6 # 算术也没有什么出乎意料的 -11 ->>> 50 - 4 * 8 -18 ->>> (50 - 4) * 8 -368 - ->>> 15 / 3 # 但是除法除外,它会永远返回浮点 float 类型 -5.0 ->>> (50 - 4 * 8) / 9 -2.0 ->>> 5 / 3 -1.6666666666666667 - ->>> 5.0 * 6 # 浮点数的运算结果也是浮点数 -30.0 -``` - -整数(比如 `5`、`8`、`16`)为 `int` 类型,有小数部分的(如 `2.33`、`6.0`)则为 `float` 类型。随着更深入的学习,你可能会接触到更多的类型,但是在速成阶段这些已经足够使用。 - -在上面的实践中也可以发现,除法运算(`/`)永远返回浮点类型(在 Python 2 中返回整数)。如果你想要整数或向下取整的结果的话,可以使用整数除法(`//`)。同样的,你也可以像 C++ 中一样,使用模(`%`)来计算余数。 - -```python3 ->>> 5 / 3 # 正常的运算会输出浮点数 -1.6666666666666667 ->>> 5 // 3 # 使用整数除法则会向下取整,输出整数类型 -1 ->>> -5 // 3 # 符合向下取整原则,注意与C/C++不同 --2 ->>> 5.0 // 3.0 # 如果硬要浮点数向下取整也可以这么做 -1.0 ->>> 5 % 3 # 取模 -2 ->>> -5 % 3 # 负数取模结果一定是非负数,这点也与C/C++不同,不过都满足 (a//b)*b+(a%b)==a -1 -``` - -特别的,Python 封装了乘方(`**`)的算法,还通过内置的 `pow(a, b, mod)` 提供了 快速幂的高效实现。 - -同时 Python 还提供大整数支持,但是浮点数与 C/C++ 一样存在误差。 - -```python3 ->>> 5 ** 2 -25 ->>> 2 ** 16 -65536 ->>> 2 ** 512 -13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096 ->>> pow(2, 512, 10000) # 即 2**512 % 10000 的快速实现 -4096 - ->>> 2048 ** 2048 # 在IDLE里试试大整数? -``` - -### 输入输出 - -Python 中的输入输出主要通过内置函数 `raw_input`(Python 2)/`input`(Python 3) 和 `print` 完成,这一部分内容可以参考 [Python 的官方文档](https://docs.python.org/3/tutorial/inputoutput.html)。`input` 函数用来从标准输入流中读取一行,`print` 则是向标准输出流中输出一行。在 Python 3 中对 `print` 增加了 `end` 参数指定结尾符,可以用来避免 `print` 自动换行。如果需要更灵活的输入输出操作,可以在引入 `sys` 包之后利用 `sys.stdin` 和 `sys.stdout` 操标准作输入输出流。 - -另外,如果要进行格式化的输出的话可以利用 Python 中字符串的语法。格式化有两种方法,一种是利用 `%` 操作符,另一种是利用 `format` 函数。前者语法与 C 兼容,后者语法比较复杂,可以参考 [官方文档](https://docs.python.org/3/library/string.html#formatstrings)。 - -```python3 ->>> print(12) -12 ->>> print(12, 12) # 该方法在 Python 2 和 Python 3 中的表现不同 -12 12 ->>> print("%d" % 12) # 与C语法兼容 -12 ->>> print("%04d %.3f" % (12, 1.2)) -0012 1.200 ->>> print("{name} is {:b}".format(5, name="binary of 5")) -binary of 5 is 101 -``` - -### 开数组 - -从 C++ 转过来的同学可能很迷惑怎么在 Python 中开数组,这里就介绍在 Python 开数组的语法。 - -#### 使用 `list` - -主要用到的是 Python 中列表(`list`)的特性,值得注意的是 Python 中列表的实现方式类似于 C++ 的 `vector`。 - -```python3 ->>> [] # 空列表 -[] ->>> [1] * 10 # 开一个10个元素的数组 -[1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ->>> [1, 1] + [2, 3] # 数组拼接 -[1, 1, 2, 3] ->>> a1 = list(range(8)) # 建立一个自然数数组 ->>> a1 -[0, 1, 2, 3, 4, 5, 6, 7] - ->>> [[1] * 3] * 3 # 开一个3*3的数组 -[[1, 1, 1], [1, 1, 1], [1, 1, 1]] ->>> [[1] * 3 for _ in range(3)] # 同样是开一个3*3的数组 -[[1, 1, 1], [1, 1, 1], [1, 1, 1]] ->>> a2 = [[1]] * 5; a2[0][0] = 2; # 猜猜结果是什么? ->>> a2 -[[2], [2], [2], [2], [2]] - ->>> # 以下是数组操作的方法 ->>> len(a1) # 获取数组长度 -8 ->>> a1.append(8) # 向末尾添加一个数 ->>> a1[0] = 0 # 访问和赋值 ->>> a1[-1] = 7 # 从末尾开始访问 ->>> a1[2:5] # 提取数组的一段 -[2, 3, 4] ->>> a1[5:2:-1] # 倒序访问 -[5, 4, 3] ->>> a1.sort() # 数组排序 - ->>> a2[0][0] = 10 # 访问和赋值二维数组 ->>> for i, a3 in enumerate(a2): - for j, v in enumerate(a3): - temp = v # 这里的v就是a[i][j] -``` - -注意上面案例里提到的多维数组的开法。由于列表的乘法只是拷贝引用,因此 `[[1]] * 3` 这样的代码生成的三个 `[1]` 实际上是同一个对象,修改其内容时会导致所有数组都被修改。所以开多维数组时使用 for 循环可以避免这个问题。 - -#### 使用 NumPy - -??? note "什么是 NumPy" - [NumPy](https://numpy.org/) 是著名的 Python 科学计算库,提供高性能的数值及矩阵运算。在测试算法原型时可以利用 NumPy 避免手写排序、求最值等算法。NumPy 的核心数据结构是 `ndarray`,即 n 维数组,它在内存中连续存储,是定长的。此外 NumPy 核心是用 C 编写的,运算效率很高。 - -下面的代码将介绍如何利用 NumPy 建立多维数组并进行访问。 - -```python3 ->>> import numpy as np # NumPy 是第三方库,需要安装和引用 - ->>> np.empty(3) # 开容量为3的空数组 -array([0.00000000e+000, 0.00000000e+000, 2.01191014e+180]) - ->>> np.empty((3, 3)) # 开3*3的空数组 -array([[6.90159178e-310, 6.90159178e-310, 0.00000000e+000], - [0.00000000e+000, 3.99906161e+252, 1.09944918e+155], - [6.01334434e-154, 9.87762528e+247, 4.46811730e-091]]) - ->>> np.zeros((3, 3)) # 开3*3的数组,并初始化为0 -array([[0., 0., 0.], - [0., 0., 0.], - [0., 0., 0.]]) - ->>> a1 = np.zeros((3, 3), dtype=int) # 开3×3的整数数组 ->>> a1[0][0] = 1 # 访问和赋值 ->>> a1[0, 0] = 1 # 更友好的语法 ->>> a1.shape # 数组的形状 -(3, 3) ->>> a1[:2, :2] # 取前两行、前两列构成的子阵,无拷贝 -array([[1, 0], - [0, 0]]) ->>> a1[0, 2] # 获取第1和3列,无拷贝 -array([[1, 0], - [0, 0], - [0, 0]]) - ->>> np.max(a1) # 获取数组最大值 -1 ->>> a1.flatten() # 将数组展平 -array([1, 0, 0, 0, 0, 0, 0, 0, 0]) ->>> np.sort(a1, axis=1) # 沿行方向对数组进行排序,返回排序结果 -array([[0, 0, 1], - [0, 0, 0], - [0, 0, 0]]) ->>> a1.sort(axis=1) # 沿行方向对数组进行原地排序 -``` - -## 类型检查和提示 - -无论是打比赛还是做项目,使用类型提示可以让你更容易地推断代码、发现细微的错误并维护干净的体系结构。Python 最新的几个版本允许你指定明确的类型进行提示,有些工具可以使用这些提示来帮助你更有效地开发代码。Python 的类型检查主要是用类型标注和类型注释进行类型提示和检查。对于 OIer 来说,掌握 Python 类型检查系统的基本操作就足够了,项目实操中,如果你想写出风格更好的、易于类型检查的代码,你可以参考 [Mypy 的文档](https://mypy.readthedocs.io/)。 - -### 动态类型检查 - -Python 是一个动态类型检查的语言,以灵活但隐式的方式处理类型。Python 解释器仅仅在运行时检查类型是否正确,并且允许在运行时改变变量类型。 - -```python3 ->>> if False: -... 1 + "two" # This line never runs, so no TypeError is raised -... else: -... 1 + 2 -... -3 - ->>> 1 + "two" # Now this is type checked, and a TypeError is raised -TypeError: unsupported operand type(s) for +: 'int' and 'str' -``` - -### 类型提示简例 - -我们首先通过一个例子来简要说明。假如我们要向函数中添加关于类型的信息,首先需要按如下方式对它的参数和返回值设置类型标注: - -```python3 -# headlines.py - -def headline(text: str, align: bool = True) -> str: - if align: - return f"{text.title()}\n{'-' * len(text)}" - else: - return f" {text.title()} ".center(50, "o") - -print(headline("python type checking")) -print(headline("use mypy", align=True)) -``` - -但是这样添加类型提示没有运行时的效果——如果我们用错误类型的 `align` 参数,程序依然可以在不报错、不警告的情况下正常运行。 - -```console -$ python headlines.py -Python Type Checking --------------------- -oooooooooooooooooooo Use Mypy oooooooooooooooooooo -``` - -因此,我们需要静态检查工具来排除这类错误(例如 [PyCharm](https://www.jetbrains.com/pycharm/) 中就包含这种检查)。最常用的静态类型检查工具是 [Mypy](http://mypy-lang.org/)。 - -```console -$ pip install mypy -Successfully installed mypy. - -$ mypy headlines.py -Success: no issues found in 1 source file -``` - -如果没有报错,说明类型检查通过;否则,会提示出问题的地方。*值得注意的是,类型检查可以向下(subtype not subclass)兼容,比如整数就可以在 Mypy 中通过浮点数类型标注的检查(int 是 double 的 subtype,但不是其 subclass)。* - -这种检查对于写出可读性较好的代码是十分有帮助的——Bernát Gábor 曾在他的 [The State of Type Hints in Python](https://www.bernat.tech/the-state-of-type-hints-in-python/) 中说过,“类型提示应当出现在任何值得单元测试的代码里”。 - -### 类型标注 - -类型标注是自 Python 3.0 引入的特征,是添加类型提示的重要方法。例如这段代码就引入了类型标注,你可以通过调用 `circumference.__annotations__` 来查看函数中所有的类型标注。 - -```python3 -import math - -def circumference(radius: float) -> float: - return 2 * math.pi * radius -``` - -当然,除了函数函数,变量也是可以类型标注的,你可以通过调用 `__annotations__` 来查看函数中所有的类型标注。 - -```python3 -pi: float = 3.142 - -def circumference(radius: float) -> float: - return 2 * pi * radius -``` - -变量类型标注赋予了 Python 静态语言的性质,即声明与赋值分离: - -```python3 ->>> nothing: str ->>> nothing -NameError: name 'nothing' is not defined - ->>> __annotations__ -{'nothing': } -``` - -### 类型注释 - -如上所述,Python 的类型标注是 3.0 之后才支持的,这说明如果你需要编写支持遗留 Python 的代码,就不能使用标注。为了应对这个问题,你可以尝试使用类型注释——一种特殊格式的代码注释——作为你代码的类型提示。 - -```python3 -import math - -pi = 3.142 # type: float - -def circumference(radius): - # type: (float) -> float - return 2 * pi * radius - -def headline(text, width=80, fill_char="-"): - # type: (str, int, str) -> str - return f" {text.title()} ".center(width, fill_char) - -def headline( - text, # type: str - width=80, # type: int - fill_char="-", # type: str -): # type: (...) -> str - return f" {text.title()} ".center(width, fill_char) - -print(headline("type comments work", width=40)) -``` - -这种注释不包含在类型标注中,你无法通过 `__annotations__` 找到它,同类型标注一样,你仍然可以通过 Mypy 运行得到类型检查结果。 - -## 装饰器 - -装饰器是一个函数,接受一个函数或方法作为其唯一的参数,并返回一个新函数或方法,其中整合了修饰后的函数或方法,并附带了一些额外的功能。简而言之,可以在不修改函数代码的情况下,增加函数的功能。相关知识可以参考 [官方文档](https://docs.python.org/3/glossary.html#term-decorator)。 - -部分装饰器在竞赛中非常实用,比如 [`lru_cache`](https://docs.python.org/3/library/functools.html#functools.lru_cache),可以为函数自动增加记忆化的能力,在递归算法中非常实用: - -`@lru_cache(maxsize=128,typed=False)` - -- 传入的参数有 2 个:`maxsize` 和 `typed`,如果不传则 `maxsize` 的默认值为 128,`typed` 的默认值为 `False`。 -- 其中 `maxsize` 参数表示的是 LRU 缓存的容量,即被装饰的方法的最大可缓存结果的数量。如果该参数值为 128,则表示被装饰方法最多可缓存 128 个返回结果;如果 `maxsize` 传入为 `None` 则表示可以缓存无限个结果。 -- 如果 `typed` 设置为 `True`,不同类型的函数参数将被分别缓存,例如,`f(3)` 和 `f(3.0)` 会缓存两次。 - -以下是使用 `lru_cache` 优化计算斐波那契数列的例子: - -```python -@lru_cache(maxsize=None) -def fib(n): - if n < 2: - return n - return fib(n-1) + fib(n-2) -``` - -## 常用内置库 - -在这里介绍一些写算法可能用得到的内置库,具体用法可以自行搜索或者阅读 [官方文档](https://docs.python.org/3/library/index.html)。 - -| 包名 | 用途 | -| ------------------------------------------------------------------- | ---------------- | -| [`array`](https://docs.python.org/3/library/array.html) | 定长数组 | -| [`argparse`](https://docs.python.org/3/library/argparse.html) | 命令行参数处理 | -| [`bisect`](https://docs.python.org/3/library/bisect.html) | 二分查找 | -| [`collections`](https://docs.python.org/3/library/collections.html) | 提供有序字典、双端队列等数据结构 | -| [`fractions`](https://docs.python.org/3/library/fractions.html) | 有理数 | -| [`heapq`](https://docs.python.org/3/library/heapq.html) | 基于堆的优先级队列 | -| [`io`](https://docs.python.org/3/library/io.html) | 文件流、内存流 | -| [`itertools`](https://docs.python.org/3/library/itertools.html) | 迭代器相关 | -| [`math`](https://docs.python.org/3/library/math.html) | 常用数学函数 | -| [`os.path`](https://docs.python.org/3/library/os.html) | 系统路径相关 | -| [`random`](https://docs.python.org/3/library/random.html) | 随机数 | -| [`re`](https://docs.python.org/3/library/re.html) | 正则表达式 | -| [`struct`](https://docs.python.org/3/library/struct.html) | 转换结构体和二进制数据 | -| [`sys`](https://docs.python.org/3/library/sys.html) | 系统信息 | - -## 对比 C++ 与 Python - -相信大部分算法竞赛选手已经熟练掌握了 C++98 的语法。接下来我们展示一下 Python 语法的一些应用。 - -接下来的例子是 [Luogu P4779「【模板】单源最短路径(标准版)」](https://www.luogu.com.cn/problem/P4779) 的代码。我们将 C++ 代码与 Python 代码做出对比: - -从声明一些常量开始: - -C++: - -```cpp -#include -using namespace std; -const int N = 1e5 + 5, M = 2e5 + 5; -``` - -Python: - -```python -try: # 引入优先队列模块 - import Queue as pq #python version < 3.0 -except ImportError: - import queue as pq #python3.* - -N = int(1e5 + 5) -M = int(2e5 + 5) -INF = 0x3f3f3f3f -``` - -然后是声明前向星结构体和一些其他变量。 - -C++: - -```cpp -struct qxx { - int nex, t, v; -}; - -qxx e[M]; -int h[N], cnt; - -void add_path(int f, int t, int v) { e[++cnt] = (qxx){h[f], t, v}, h[f] = cnt; } - -typedef pair pii; -priority_queue, greater> q; -int dist[N]; -``` - -Python: - -```python -class qxx: # 前向星类(结构体) - def __init__(self): - self.nex = 0 - self.t = 0 - self.v = 0 - -e = [qxx() for i in range(M)] # 链表 -h = [0 for i in range(N)] -cnt = 0 - -dist = [INF for i in range(N)] -q = pq.PriorityQueue() # 定义优先队列,默认第一元小根堆 - -def add_path(f, t, v): # 在前向星中加边 - # 如果要修改全局变量,要使用global来声明 - global cnt, e, h - # 调试时的输出语句,多个变量使用元组 - # print("add_path(%d,%d,%d)" % (f,t,v)) - cnt += 1 - e[cnt].nex = h[f] - e[cnt].t = t - e[cnt].v = v - h[f] = cnt -``` - -然后是求解最短路的 Dijkstra 算法代码: - -C++: - -```cpp -void dijkstra(int s) { - memset(dist, 0x3f, sizeof(dist)); - dist[s] = 0, q.push(make_pair(0, s)); - while (q.size()) { - pii u = q.top(); - q.pop(); - if (dist[u.second] < u.first) continue; - for (int i = h[u.second]; i; i = e[i].nex) { - const int &v = e[i].t, &w = e[i].v; - if (dist[v] <= dist[u.second] + w) continue; - dist[v] = dist[u.second] + w; - q.push(make_pair(dist[v], v)); - } - } -} -``` - -Python: - -```python3 -def nextedgeid(u): # 生成器,可以用在for循环里 - i = h[u] - while i: - yield i - i = e[i].nex - - -def dijkstra(s): - dist[s] = 0 - q.put((0, s)) - while not q.empty(): - u = q.get() # get函数会顺便删除堆中对应的元素 - if dist[u[1]] < u[0]: - continue - for i in nextedgeid(u[1]): - v = e[i].t - w = e[i].v - if dist[v] <= dist[u[1]]+w: - continue - dist[v] = dist[u[1]]+w - q.put((dist[v], v)) -``` - -最后是主函数部分 - -C++: - -```cpp -int n, m, s; - -int main() { - scanf("%d%d%d", &n, &m, &s); - for (int i = 1; i <= m; i++) { - int u, v, w; - scanf("%d%d%d", &u, &v, &w); - add_path(u, v, w); - } - dijkstra(s); - for (int i = 1; i <= n; i++) printf("%d ", dist[i]); - return 0; -} -``` - -Python: - -```python3 -# 如果你直接运行这个python代码(不是模块调用什么的)就执行命令 -if __name__ == '__main__': - # 一行读入多个整数。注意它会把整行都读进来 - n, m, s = map(int, input().split()) - for i in range(m): - u, v, w = map(int, input().split()) - add_path(u, v, w) - - dijkstra(s) - - for i in range(1, n+1): - # 两种输出语法都是可以用的 - print("{}".format(dist[i]), end=' ') - # print("%d" % dist[i],end=' ') - - print() # 结尾换行 -``` - -完整的代码如下: - -??? note "C++" - ```cpp - #include - using namespace std; - const int N = 1e5 + 5, M = 2e5 + 5; - - struct qxx { - int nex, t, v; - }; - - qxx e[M]; - int h[N], cnt; - - void add_path(int f, int t, int v) { e[++cnt] = (qxx){h[f], t, v}, h[f] = cnt; } - - typedef pair pii; - priority_queue, greater> q; - int dist[N]; - - void dijkstra(int s) { - memset(dist, 0x3f, sizeof(dist)); - dist[s] = 0, q.push(make_pair(0, s)); - while (q.size()) { - pii u = q.top(); - q.pop(); - if (dist[u.second] < u.first) continue; - for (int i = h[u.second]; i; i = e[i].nex) { - const int &v = e[i].t, &w = e[i].v; - if (dist[v] <= dist[u.second] + w) continue; - dist[v] = dist[u.second] + w; - q.push(make_pair(dist[v], v)); - } - } - } - - int n, m, s; - - int main() { - scanf("%d%d%d", &n, &m, &s); - for (int i = 1; i <= m; i++) { - int u, v, w; - scanf("%d%d%d", &u, &v, &w); - add_path(u, v, w); - } - dijkstra(s); - for (int i = 1; i <= n; i++) printf("%d ", dist[i]); - return 0; - } - ``` - -??? note "Python" - ```python3 - try: # 引入优先队列模块 - import Queue as pq # python version < 3.0 - except ImportError: - import queue as pq # python3.* - - N = int(1e5+5) - M = int(2e5+5) - INF = 0x3f3f3f3f - - class qxx: # 前向星类(结构体) - def __init__(self): - self.nex = 0 - self.t = 0 - self.v = 0 - - e = [qxx() for i in range(M)] # 链表 - h = [0 for i in range(N)] - cnt = 0 - - dist = [INF for i in range(N)] - q = pq.PriorityQueue() # 定义优先队列,默认第一元小根堆 - - def add_path(f, t, v): # 在前向星中加边 - # 如果要修改全局变量,要使用global来声名 - global cnt, e, h - # 调试时的输出语句,多个变量使用元组 - # print("add_path(%d,%d,%d)" % (f,t,v)) - cnt += 1 - e[cnt].nex = h[f] - e[cnt].t = t - e[cnt].v = v - h[f] = cnt - - def nextedgeid(u): # 生成器,可以用在for循环里 - i = h[u] - while i: - yield i - i = e[i].nex - - def dijkstra(s): - dist[s] = 0 - q.put((0, s)) - while not q.empty(): - u = q.get() - if dist[u[1]] < u[0]: - continue - for i in nextedgeid(u[1]): - v = e[i].t - w = e[i].v - if dist[v] <= dist[u[1]]+w: - continue - dist[v] = dist[u[1]]+w - q.put((dist[v], v)) - - # 如果你直接运行这个python代码(不是模块调用什么的)就执行命令 - if __name__ == '__main__': - # 一行读入多个整数。注意它会把整行都读进来 - n, m, s = map(int, input().split()) - for i in range(m): - u, v, w = map(int, input().split()) - add_path(u, v, w) - - dijkstra(s) - - for i in range(1, n+1): - # 两种输出语法都是可以用的 - print("{}".format(dist[i]), end=' ') - # print("%d" % dist[i],end=' ') - - print() # 结尾换行 - ``` - -## 参考文档 - -1. Python Documentation, -2. Python 官方中文教程, -3. Learn Python3 In Y Minutes, -4. Real Python Tutorials, -5. 廖雪峰的 Python 教程, -6. GeeksforGeeks: Python Tutorials, diff --git a/mkdocs.yml b/mkdocs.yml index 7bb6c3c..de31c61 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -32,7 +32,7 @@ nav: - 产品介绍: - 信贷产品简介: loan/02-产品介绍/信贷产品简介.md - 消费金融产品: - - 消费金融常见资金合作模式: loan/02-产品介绍/资金合作模式.md + - 联合贷和助贷: loan/02-产品介绍/联合贷和助贷.md - 政府融资平台: loan/02-产品介绍/政府融资平台.md - 风控监管: - 信贷主流风控模型: loan/03-风控监管/信贷主流风控模型.md @@ -46,23 +46,24 @@ nav: - 产品知识: - 产品思维: - 产品思维地图: product/产品思维地图.md - - 软件工程: - - 设计模式: - - DDD介绍: enginering/02-编程范式/DDD介绍.md - - MVC到DDD的架构演进: enginering/02-编程范式/MVC到DDD的架构演进.md - - 编程技巧: - - 45个小技巧优化代码: enginering/02-编程范式/45个小技巧优化代码.md + - 软件工程: + - DDD介绍: enginering/02-编程范式/DDD介绍.md + - MVC到DDD的架构演进: enginering/02-编程范式/MVC到DDD的架构演进.md + - 45个小技巧优化代码: enginering/02-编程范式/45个小技巧优化代码.md - 编程语言: - Java: enginering/03-编程语言/java.md - Python: enginering/03-编程语言/python.md - C&C++: enginering/03-编程语言/c-cpp.md + - LaTeX: enginering/03-编程语言/latex.md - 工具软件: - 编码工具: - VS Code: tools/editor/vscode.md - Vim: tools/editor/vim.md + - Vim之禅: tools/editor/vim-zen.md - 版本控制: - GIT: tools/git.md - + - 操作系统: + - WSL: tools/wsl.md # Config theme theme: