面试官:为什么Vue中的v-if和v-for不建议一起用?

thbcm阅读(164)

一、作用

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染

v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组或者对象,而 item 则是被迭代的数组元素的别名

在 v-for 的时候,建议设置key值,并且保证每个key值是独一无二的,这便于diff算法进行优化

两者在用法上

<Modal v-if="isShow" />

<li v-for="item in items" :key="item.id">
  {{ item.label }}
</li>

二、优先级

v-if 与 v-for 都是 vue 模板系统中的指令

在vue模板编译的时候,会将指令系统转化成可执行的render函数

示例 编写一个 p 标签,同时使用 v-if 与 v-for

<div id="app">
   <p v-if="isShow" v-for="item in items">
      {{ item.title }}
   </p>
</div>

创建 vue 实例,存放 isShow 与 items 数据

const app = new Vue({
 el: "#app",
 data() {
   return {
     items: [
      { title: "foo" },
      { title: "baz" }]
  }
},
 computed: {
   isShow() {
     return this.items && this.items.length > 0
  }
}
})

模板指令的代码都会生成在 render 函数中,通过 app.$options.render 就能得到渲染函数

ƒ anonymous() {
 with (this) { return
   _c('div', { attrs: { "id": "app" } },
   _l((items), function (item)
  { return (isShow) ? _c('p', [_v("\n" + _s(item.title) + "\n")]) : _e() }), 0) }
}

_l 是 vue 的列表渲染函数,函数内部都会进行一次 if 判断

初步得到结论:v-for 优先级是比 v-if 高

再将 v-for 与 v-if 置于不同标签

<div id="app">
   <template v-if="isShow">
       <p v-for="item in items">{{item.title}}</p>
   </template>
</div>

再输出下 render 函数

ƒ anonymous() {
 with(this){return
   _c('div',{attrs:{"id":"app"}},
  [(isShow)?[_v("\n"),
   _l((items),function(item){return _c('p',[_v(_s(item.title))])})]:_e()],2)}
}

这时候我们可以看到,v-for 与 v-if 作用在不同标签时候,是先进行判断,再进行列表的渲染

我们再在查看下 vue 源码

源码位置:\vue-dev\src\compiler\codegen\index.js

export function genElement (el: ASTElement, state: CodegenState): string {
 if (el.parent) {
   el.pre = el.pre || el.parent.pre
}
 if (el.staticRoot && !el.staticProcessed) {
   return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
   return genOnce(el, state)
} else if (el.for && !el.forProcessed) {
   return genFor(el, state)
} else if (el.if && !el.ifProcessed) {
   return genIf(el, state)
} else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
   return genChildren(el, state) || 'void 0'
} else if (el.tag === 'slot') {
   return genSlot(el, state)
} else {
   // component or element
   ...
}

在进行if判断的时候,v-for 是比 v-if 先进行判断

最终结论:v-for 优先级比 v-if 高

三、注意事项

1.永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)

2.如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环

<template v-if="isShow">
   <p v-for="item in items">
</template>

3.如果条件出现在循环内部,可通过计算属性 computed 提前过滤掉那些不需要显示的项

computed: {
//过滤出满足条件后的数据再渲染
   items: function() {
     return this.list.filter(function (item) {
       return item.isShow
    })
  }
}

普通人学Python有什么用?

thbcm阅读(171)

随着技术不断发展,人类的社会活动呈现一个明显的趋势:人和人之间的交流越来越少,越来越简洁,而人与机器设备的交流越来越多,很多年轻人花在手机和电脑上的时间已经远远超过了花在别人甚至是最亲近的人身上的时间。

尽管大家都在吐槽和抵制这样的趋势,可是谁都无法改变这样的趋势,因为本质上这就是人类发展科技所盼望达成的效果。

所以识时务者只能学一点和机器交流的方法,学会计算机的语言,这样一来,万一哪一天机器完全奴役了人类,好歹也能比其他人死得稍微明白一点,要是技术还不错,说不定还能加入人类反叛军,制造出属于自己的终结者,为人类的自由一战。

扯得有点远,还是回归咱普通人吧。

一、python是比较适合普通人的一门语言

为什么这么说呢?拿造房子打比方:一个原始人要造现代化的房子的难度是极大的,因为他得先学会烧砖、制水泥、炼钢、制造玻璃,要学会基本的建筑力学、焊接技术,还要借助现代化的各种机械,每一样都必不可少。

而对于零基础的非专业人士来说,要用其它任何语言在短时间内学会编写一个像样的程序就和原始人学会建造现代化的房子差不多,知识体系太庞杂,要记要背的东西也太多,上手难度太大。

和大学读计算机专业不同,平时的学习纯粹是出于兴趣和一些简单的工作需要,没有考试,没有必学不可的压迫感,所以冗长的基础学习步骤会让绝大多数人失去学习兴趣。

而 python 的优势就在于它本身是基于程序工作者们大量的前期工作,已经把砖块烧好,把钢筋炼好,把组装好的机械设备放在了我们面前,让初学者直接从原始社会跳到了现代社会,只需要用接近人类的语言和思维方式,就能很快学会如何建造大楼。

所以学 python 能很快找到成就感,用不了多少时间就可以独立写出能够有意思的小程序。

二、学习Python可以锻炼思维

平时生活工作中我们会做无数的重复劳动,这些劳动除了浪费生命之外其实是没有太大意义的,文人们当然喜欢把这样无意义的重复称为”这就是生活”,可在程序员大佬们看来,一切重复的劳动都是可以优化的。

比如你要制作一张九九乘法表给自己读幼儿园的孩子学习,像下面这样把数字一个个打到文档上,就是一件重复无意义的工作:

当然你可以把这些无意义的工作想得很有意义,这是对孩子无私的奉献,哪怕写个 90*90 乘法表,你也愿意花上一整天去做。

可是在程序员们看来,不管是9乘以9还是90乘以90,都可以通过自己的思考运用代码来快速完成:

下面学习8天之后能够独立写出的程序:

试想一下,这种思维逻辑远比练手速更有意义。

三、提升工作效率

目前来说,很多人出现加班的情况都是因为效率低下,把大部分时间都浪费在重复操作上,然后还不断学习如何管理时间,显然是治标不治本。

比如说:

客服可以用 python 编写自动回复系统,回复大部分常规性问题;

分析师可以根据自己的需求编写爬虫程序去网上自动收集大量的相关资料并自动归类和分析;

老总可以编写个人自动发邮件程序,定时定人分类收发大批量的工作邮件。

不管哪个行业,都能找到 python 的用武之地,能把学到的东西用到现实工作中的人一定能比别人省出更多的自由时间,去做自己喜欢的、更有意义的事。

最后要说一点,Python 起步容易,学深很难,可我们不是程序员不需要对自己提太高的要求,保持兴趣才是学习最重要的事。

java接口是什么

thbcm阅读(210)

接口概念

    官方解释:Java 接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。

    我的解释:接口可以理解为一种特殊的类,里面全部是由全局常量和公共的抽象方法所组成。接口是解决 Java 无法使用多继承的一种手段,但是接口在实际中更多的作用是制定标准的。或者我们可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)

接口的特点

    就像一个类一样,一个接口也能够拥有方法和属性,但是在接口中声明的方法默认是抽象的。(即只有方法标识符,而没有方法体)。

  • 接口指明了一个类必须要做什么和不能做什么,相当于类的蓝图。
  • 一个接口就是描述一种能力,比如“运动员”也可以作为一个接口,并且任何实现“运动员”接口的类都必须有能力实现奔跑这个动作(或者 implement move()方法),所以接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力。
  • 如果一个类实现了一个接口中要求的所有的方法,然而没有提供方法体而仅仅只有方法标识,那么这个类一定是一个抽象类。(必须记住:抽象方法只能存在于抽象类或者接口中,但抽象类中却能存在非抽象方法,即有方法体的方法。接口是百分之百的抽象类)
  • 一个 JAVA 库中接口的例子是:Comparator 接口,这个接口代表了“能够进行比较”这种能力,任何类只要实现了这个Comparator 接口的话,这个类也具备了“比较”这种能力,那么就可以用来进行排序操作了。

为什么要用接口

  1.     接口被用来描述一种抽象。
  2. 因为 Java 不像C++一样支持多继承,所以 Java 可以通过实现接口来弥补这个局限。
  3. 接口也被用来实现解耦。
  4. 接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非 final 的变量,但是在接口中存在的变量一定是 final,public,static 的。

接口的语法实现

    为了声明一个接口,我们使用 interface 这个关键字,在接口中的所有方法都必须只声明方法标识,而不要去声明具体的方法体,因为具体的方法体的实现是由继承该接口的类来去实现的,因此,接口并不用管具体的实现。接口中的属性默认为 Public Static Final.一个类实现这个接口必须实现这个接口中定义的所有的抽象方法。

    一个简单的接口就像这样:拥有全局变量和抽象方法。

    为了实现这个接口,我们使用 implements 关键词去实现接口:

其中 testClass 类实现了我们上面刚才定义的 in1 这个接口,既然你要实现接口,也就是实现接口代表的一种能力,那么你就必须去实现接口给你规定的方法,只有把接口给你规定的抽象方法都给实现了,才承认你这个类实现了这个接口,实现了这个接口代表的某种功能。上图实现了接口中规定的 display()方法。

    写一个测试类,用来测试一下我们刚才实现的这个接口,因为testclass类的对象t实现了接口规定的 display 方法,那么自然而然就可以调用 display()方法咯。

    有兴趣的同学可以去这个在线IDE亲自试一试:点击打开链接

 

 

接口的进一步理解

 

    我们知道,如果某个设备需要向电脑中读取或者写入某些东西,这些设备一般都是采用 USB 方式与电脑连接的,我们发现,只要带有 USB 功能的设备就可以插入电脑中使用了,那么我们可以认为USB就是一种功能,这种功能能够做出很多的事情(实现很多的方法),其实 USB 就可以看做是一种标准,一种接口,只要实现了USB标准的设备我就认为你已经拥有了 USB 这种功能。(因为你实现了我 USB 标准中规定的方法),下面是具体的例子:

 

先声明USB接口:其中规定了要实现USB接口就必须实现接口规定实现的 read( )和 write( )这两个方法。

interface USB {    void read();    void write();}

然后在写一个U盘类和一个键盘类,这两个类都去实现 USB 接口。(实现其中的方法)

class YouPan implements USB {   

@Override    

public void read() {       

System.out.println(“U盘正在通过USB功能读取数据”);    }    

@Override    

public void write() {       

System.out.println(“U盘正在通过USB功能写入数据”);    }}

这是U盘的具体实现。

class JianPan implements USB {    

@Override    

public void read() {       

System.out.println(“键盘正在通过USB功能读取数据”);    }    

@Override    

public void write() {       

System.out.println(“键盘正在通过USB功能写入数据”);    }}

 

这是键盘的具体实现。

那么,现在U盘和键盘都实现了 USB 功能,也就是说 U 盘和键盘都能够调用 USB 接口中规定的方法,并且他们实现的方式都不一样。

我们在写一个测试,来看看具体的实现:

public class Main {    

public static void main(String[] args) {        

//生成一个实现可USB接口(标准)的U盘对象        

YouPan youPan = new YouPan();        

//调用U盘的read( )方法读取数据        

youPan.read();        

//调用U盘的write( )方法写入数据        

youPan.write();        

//生成一个实现可USB接口(标准)的键盘对象        

JianPan jianPan = new JianPan();        

//调用键盘的read( )方法读取数据        

jianPan.read();        

//调用键盘的write( )方法写入数据        

jianPan.write();    }} 

 

结果如下:

 

 

    感兴趣的同学可以去在线IDE平台自己验证一下:点击打开链接

关于接口的几个重点

  1. 我们不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的,这样怎么可能产生具体的实例呢?但是,我们可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。因此,上图中最后的方法调用我们还可以这样写:(实际上就是使用了 Java 中多态的特性)

public class Main {    

public static void main(String[] args) {        

//生成一个实现可USB接口(标准)的U盘对象       

//但是使用一个接口引用指向对象       

//USB接口类引用可以指向一个实现了USB接口的对象        

USB youPan = new YouPan();        

//调用U盘的read( )方法读取数据        

youPan.read();        

//调用U盘的write( )方法写入数据        

youPan.write();        

//生成一个实现可USB接口(标准)的键盘对象       

//但是使用一个接口引用指向对象       

//USB接口类引用可以指向一个实现了USB接口的对象        

USB jianPan = new JianPan();        

//调用键盘的read( )方法读取数据        

jianPan.read();        

//调用键盘的write( )方法写入数据        

jianPan.write();    }}                                                                                                                                     

 

2.一个类可以实现不止一个接口。

3.一个接口可以继承于另一个接口,或者另一些接口,接口也可以继承,并且可以多继承。

4.一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有方法。

5.接口中所有的方法都是抽象的和 public 的,所有的属性都是 public,static,final 的。

6.接口用来弥补类无法实现多继承的局限。

7.接口也可以用来实现解耦。

接口的通俗理解

 

    前面我们讲多态的时候用“空调”——“遥控器”的方式去理解多态,实际上在上面的的几个重点中的第一条讲的也是多态的实现,比如,我们可以把“节能”作为一种标准,或者说节能就是一个“接口”,这个接口中有一个方法,叫做变频方法,任何空调,如果要称得上叫做节能空调的话,那么必须实现“节能”这个接口,实现“节能”这个接口,也就必须实现“节能”接口中规定实现的“变频”方法,这样才算是真正的实现了“节能”这个接口,实现了“节能”这个功能。

    当某个空调实现了“节能”接口后,这个空调就具备了节能的功能,那么我们也可以不用空调类的引用指向空调对象,我们可以直接使用一个“节能”接口类型引用的“遥控器”去指向“空调”,虽然这个“遥控器”上面只有一个按键,只有一个“变频”的方法,但是“遥控器”所指向的空调是实现了“节能”这个接口的,是有“变频”方法的实现的,我们用这个只有一个“变频”方法的遥控器去命令空调调用“变频”方法,也是行得通的。

 

接口的标识用法

    虽然接口内部定义了一些抽象方法,但是并不是所有的接口内部都必须要有方法,比如 Seriallizable 接口,Seriallizable 接口的作用是使对象能够“序列化”,但是 Seriallizable 接口中却没有任何内容,也就是说,如果有一个类需要实现“序列化”的功能,则这个类必须去实现 Seriallizable 接口,但是却并不用实现方法(因为接口中没有方法),此时,这个 Serilizable 接口就仅仅是一个“标识”接口,是用来标志一个类的,标志这个类具有这个“序列化”功能。具体的实现请参考我的另一篇文章——JAVA 之 IO 流。

 

接口在生活中的思想体现

其实,在我们的生活当中,有很多地方都体现了“接口”的思想,想必,正在阅读这篇博文的你,是不是也喜欢摄影呢?

玩摄影的童鞋都知道,单反由相机和镜头组成,相机分不同的型号,有半画幅的,也有全画幅的。镜头也是一样的,分长焦,短焦;还有定焦和变焦。每种镜头都有各自特定的发挥场景。正是因为镜头的多元化,使得我们的摄影能够“术业有专攻”。大家想一想,如果我们的单反相机部分和镜头部分是固定在一起的,不能够更换镜头,那么将会多么的糟糕啊!

因此,每个相机品牌为了能够兼容不同的镜头,各自发布了一套镜头卡口的标准,这套标准就好比我们前面提到的“接口”,都是某种“约束”。举个栗子,我们佳能的相机,不管你是哪一家镜头生产厂商,腾龙也好,适马也好,只要你按照我佳能卡口的标准来生产镜头,你生产的镜头都能够很好的在我佳能相机上面驱动。

因此,当我们打开“某东”,准备给自己的新相机买镜头的时候,就不难发现,我们需要根据自己相机的品牌来挑选特定卡口的镜头,这样的镜头才能被我们的相机正常驱动。

回到 Java 上面来说,其实接口给我们带来的最大的好处就是“解耦”了,相机能够搭配不同的镜头,才能有各种各样的搭配玩法,变得更加的灵活。在软件系统中也是一样的,接口可以有很多不同“特色”的实现类,我们只需要声明同一个接口,却可以引用很多个该“接口”引申出来的“子类”,这不也大大增强了我们软件系统中组件的灵活性吗?

聪明的你,对于“接口”的理解是不是又更加的深入了呢?

 

什么是HTM或HTML文件?如何打开、编辑和转换HTM和HTML文件?

thbcm阅读(165)

什么是HTML / HTM文件?他们相差一个字母有什么区别吗,如何查看或编辑源代码以及如何转换成其他格式,例如DOCX,PDF,JPG 等,针对这些问题编程狮W3Cschool整理以下资料希望能对你有所帮助:

什么是HTM或HTML文件?

HTM / HTML 文件是超文本标记语言(Hyper Text Markup Language)文件,是 Internet 上的标准网页文件类型。

由于 HTM 文件是纯文本文件,因此它们仅包含文本(例如您现在正在阅读的内容)以及对其他外部文件的文本引用(例如本文中的配图)。

HTM 和 HTML 文件还可以引用其他文件,例如视频,CSS JS 文件。

HTM与HTML的区别

HTM 与 HTML 没有本质意义的区别,只是为了满足 DOS 仅能识别 8+3 的文件名而已,因为一些老的系统 (win32) 不能识别四位文件名,所以某些网页服务器要求 index.html 最后一个 l 不能省略。MSIE 能自动识别和打开这些文件,但编写网页地址的时候必须是完全对应的,也就是说 index.htmindex.html 是两个不同的文件,对应着不同的地址。值得一提的是 UNIX 系统中对大小写敏感,不吻合的话就可能报没有文件或者找不到文件。

如何打开HTM或HTML文件?

任何 Web 浏览器,例如 Edge,Firefox,Chrome,Opera,IE,360 安全浏览器等,都可以打开并正确显示 HTM 和 HTML 文件。换句话说,在浏览器中打开这些文件并“解码(decode)” HTM 或 HTML 文件使其能正确显示。

现在有很多简化编辑和创建 HTM / HTML 文件的工具。一些著名的免费 HTML 编辑器包括 Eclipse Komodo Edit Bluefish 。另一个流行的具有许多高级功能的 HTM / HTML 编辑器是 Adobe Dreamweaver ,不过它是收费的。

虽然 Windows 系统自带的记事本等简单的文本编辑器的功能不如专用的 HTM 编辑器那么丰富,但是对 HTM 或 HTML 文件进行简单编辑修改还是可以的。不过,W3Cschool还是建议大家使用专用的编辑器,如 WebStorm、VS Code 等,它具更多专业功能。

这是一个非常简单的 HTML 页面以文本形式显示的示例:

源码:

<!doctype html>
<html>

    
<head>
<meta charset="utf-8">
<title>什么是HTM或HTML文件? - 编程狮(w3cschool.cn)</title>
</head>


<body>
    <h1>什么是HTM或HTML文件?</h1>
    <p>HTM / HTML 文件是超文本标记语言(Hyper Text Markup Language)文件,是 Internet 上的标准网页文件类型。</p>
    <p>由于 HTM 文件是纯文本文件,因此它们仅包含文本(例如您现在正在阅读的内容)以及对其他外部文件的文本*引用*(例如本文中的配图)。</p>
    <p>HTM 和 HTML 文件还可以引用其他文件,例如视频,CSS 或 JS 文件。</p>   
</body>

    
</html>

当 Web 浏览器呈现信息时,HTML 文件的源代码被“转换”为真实的网页(尽管源代码已很精简了)。

如何转换HTML和HTM文件?

HTM 文件以特定的语法(规则)构成,以使其中的代码和文本在浏览器中打开时能够正确显示。因此,将 HTM / HTML 文件转换为另一种格式可能会丢失页面上的所有功能。

如果你想要做的是将一个 HTM / HTML 文件转换为方便离线查看的文件,这时图片或 PDF 格式会方便很多。

在 Chrome 中,鼠标右键单击网页,出现的选项菜单中进入 “打印(P)…”(快捷键:CTRL + P) ,在打印选项中选择另存为 PDF,以将窗口中的页面转换为 PDF 文件。Chrome 浏览器的扩展功能也称为“全屏截屏”,可将 Chrome 浏览器中所有打开的 HTM / HTML 文件转换为 PNG 文件。

其他浏览器具有类似的功能,例如 Firefox 的 “另存为 PDF” 加载项。

您也可以使用专门用于 HTM / HTML 进行图像文件转换的网站,例如iWeb2Shot Web-capture

一个免费的文件转换器可以用来转换并保存 HTM / HTML 文件到您的计算机。如 FileZigZag 是一个免费的文档转换器网站,可将 HTM 转换为RTF,EPS,CSV,PDF 和许多其他格式。

HTM / HTML 文件不能转换为文本文件格式以外的任何格式。例如,HTML 文件永远不能转换为 MP3 音频文件。

文件打不开?

HTML / HTM 文件应该很容易打开,因为它们只是任何 Web 浏览器都可以查看的文本文件。如果您的文件没有从上面建议的任何程序打开,则很有可能正在打开的这个文件并非超文本标记语言文件。

某些文件格式使用的文件扩展名与 HTML / HTM 非常相似,但实际上并非相同。一个主要的示例是用于压缩 HTML 电子书文件的 HTMLZ 文件扩展名。有 HTML 文件在内的 HTMLZ 文件,但整个包的格式为 ZIP,不会在 Web 浏览器或文本编辑器打开。

在此示例中,您需要特定的 HTMLZ 文件查看器,例如Caliber 。或者,由于此文件格式实际上是存档,因此您可以使用 7-Zip 之类的文件解压缩器将其打开,然后您可以使用网络浏览器或上述任何其他 HTML 查看器/编辑器打开任何单独的 HTML 文件。

TMLANGUAGE 是另一个可能与 HTML / HTM 文件混淆的文件扩展名。这些实际上是TextMate 用于 macOS 的 TextMate 语言语法文件。

以上就是编程狮W3Cschool为你整理的关于《什么是HTM或HTML文件?如何打开、编辑和转换HTM和HTML文件?》的全部内容,现希望可以帮到你~

JAVA多线程编程实例

thbcm阅读(208)

1.三个售票窗口同时出售20张票

程序分析: (1)票数要使用同一个静态值 (2)为保证不会出现卖出同一个票数,要 java 多线程同步锁。 设计思路: (1)创建一个站台类Station,继承 Thread,重写 run方法,在 run 方法里面执行售票操作!售票要使用同步锁:即有一个站台卖这张票时,其他站台要等这张票卖完! (2)创建主方法调用类

(一)创建一个站台类,继承 Thread

package com.xykj.threadStation;
public class Station extends Thread {
   // 通过构造方法给线程名字赋值
   public Station(String name) {
      super(name);// 给线程名字赋值
  }
   // 为了保持票数的一致,票数要静态
   static int tick = 20;    
   // 创建一个静态钥匙
   static Object ob = "aa";//值是任意的
   // 重写run方法,实现买票操作
   @Override
   public void run() {
     while (tick > 0) {
         synchronized (ob) {// 这个很重要,必须使用一个锁,
         // 进去的人会把钥匙拿在手上,出来后才把钥匙拿让出来
         if (tick > 0) {
           System.out.println(getName() + "卖出了第" + tick + "张票");
           tick--;
        } else {
           System.out.println("票卖完了");
        }
      }
       try {
           sleep(1000);//休息一秒
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    }
}
}

(二)创建主方法调用类

package com.xykj.threadStation;
public class MainClass {
 /**
 * java多线程同步锁的使用
  * 示例:三个售票窗口同时出售10张票
  * */
 public static void main(String[] args) {
     //实例化站台对象,并为每一个站台取名字
    Station station1=new Station("窗口1");
    Station station2=new Station("窗口2");
    Station station3=new Station("窗口3");
   // 让每一个站台对象各自开始工作
    station1.start();
    station2.start();
    station3.start();
}
}

程序运行结果:

窗口1卖出了第20张票
窗口2卖出了第19张票
窗口3卖出了第18张票
窗口3卖出了第17张票
窗口1卖出了第16张票
窗口2卖出了第15张票
窗口3卖出了第14张票
窗口1卖出了第13张票
窗口2卖出了第12张票
窗口2卖出了第11张票
窗口1卖出了第10张票
窗口3卖出了第9张票
窗口3卖出了第8张票
窗口1卖出了第7张票
窗口2卖出了第6张票
窗口3卖出了第5张票
窗口1卖出了第4张票
窗口2卖出了第3张票
窗口3卖出了第2张票
窗口1卖出了第1张票
票卖完了

可以看到票数是不会有错的!

2.两个人AB通过一个账户A在柜台取钱和B在ATM机取钱!

程序分析:

钱的数量要设置成一个静态的变量,两个人要取的同一个对象值。 (一)创建一个 Bank 类

package com.thread.demo.demo2;
import java.util.Objects;
public class Bank {
// 假设一个账户有1000块钱  
static double money = 1000;
// 柜台Counter取钱的方法  
private void Counter(double money) {
Bank.money -= money;
System.out.println("柜台取钱" + money + "元,还剩" + Bank.money + "元!");
}
// ATM取钱的方法  
private void ATM(double money) {
Bank.money -= money;
System.out.println("ATM取钱" + money + "元,还剩" + Bank.money + "元!");
}
//提供一个对外取款途径,防止直接调取方法同时取款时,并发余额显示错误
public synchronized void outMoney(double money, String mode) throws Exception{
if(money > Bank.money){
//校验余额是否充足
throw new Exception("取款金额"+money+",余额只剩"+Bank.money+",取款失败");
}
if(Objects.equals(mode, "ATM")){
ATM(money);
} else {
Counter(money);
}
}
}

(二)创建一个 PersonA 类

package com.thread.demo.demo2;
public class PersonA extends Thread {
Bank bank;
String mode;
public PersonA(Bank bank, String mode) {
this.mode = mode;
this.bank = bank;
}
while(bank.money >= 100){
try {
bank.outMoney(100, mode);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

(三)创建一个 PersonB 类

package com.thread.demo.demo2;
public class PersonB extends Thread {
Bank bank;
String mode;
public PersonB(Bank bank, String mode) {
this.bank = bank;
this.mode = mode;
}
public void run() {
while (bank.money >= 200) {
try {
bank.outMoney(200, mode);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

(四)创建主方法的调用类

package com.thread.demo.demo2;
/**
* 两个人AB通过一个账户A在柜台取钱和B在ATM机取钱
* */
public class MainClass {
public static void main(String[] args) {
Bank bank = new Bank();
// 实例化两个人,传入同一个银行的对象
PersonA a = new PersonA(bank, "Counter");
PersonB b = new PersonB(bank, "ATM");
a.start();
b.start();
}
}

运行结果:


可以看到取完就停止运行了。

3.龟兔赛跑问题

龟兔赛跑:2000米
要求:
 (1)兔子每 0.1 秒 5 米的速度,每跑20米休息1秒;
 (2)乌龟每 0.1 秒跑 2 米,不休息;
 (3)其中一个跑到终点后另一个不跑了!
程序设计思路:
 (1)创建一个 Animal 动物类,继承Thread,编写一个 running 抽象方法,重写 run 方法,把 running 方法在 run 方法里面调用。
 (2)创建 Rabbit 兔子类和 Tortoise 乌龟类,继承动物类
 (3)两个子类重写 running 方法
 (4)本题的第3个要求涉及到线程回调。需要在动物类创建一个回调接口,创建一个回调对象。

(一)创建 Animal 动物类

package com.thread.demo.demo3;
public abstract class Animal extends Thread {
public int length = 2000;// 比赛长度
public abstract void runing();
@Override
public void run() {
super.run();
while (length > 0) {
runing();
}
}
// 在需要回调数据的地方(两个子类需要),声明一个接口
public static interface Calltoback {
public void win();
}
// 2.创建接口对象
public Calltoback calltoback;
}

(二)创建 Rabbit 兔子类

package com.thread.demo.demo3;
public class Rabbit extends Animal {
public Rabbit() {
setName("兔子");
}
@Override
public void runing() {
//兔子速度
int dis = 5;
length -= dis;
System.out.println("兔子跑了" + dis + "米,距离终点还有" + length + "米");
if (length <= 0) {
length = 0;
System.out.println("兔子获得了胜利");
// 给回调对象赋值,让乌龟不要再跑了
if (calltoback != null) {
calltoback.win();
}
}
try {
if ((2000 - length) % 20 == 0) { // 每20米休息一次,休息时间是1秒
sleep(1000);
} else { //没0.1秒跑5米
sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

(三)创建 Tortoise 乌龟类

package com.thread.demo.demo3;
public class Tortoise extends Animal {
public Tortoise() {
setName("乌龟");// Thread的方法,给线程赋值名字
}
// 重写running方法,编写乌龟的奔跑操作
@Override
public void runing() {
// 乌龟速度
int dis = 2;
length -= dis;
System.out.println("乌龟跑了" + dis + "米,距离终点还有" + length + "米");
if (length <= 0) {
length = 0;
System.out.println("乌龟获得了胜利");
// 让兔子不要在跑了
if (calltoback != null) {
calltoback.win();
          }
}
try {
sleep(100); //没0.1秒跑2米
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

(四)创建一个让动物线程停止的类,这里要实现回调接口

package com.thread.demo.demo3;
import com.thread.demo.demo3.Animal.Calltoback;
public class LetOneStop implements Calltoback {
// 动物对象
Animal an;
// 获取动物对象,可以传入兔子或乌龟的实例
public LetOneStop(Animal an) {
this.an = an;
}
// 让动物的线程停止
@Override
public void win() {
// 线程停止
an.stop();
}
}

(五)创建一个主方法调用类

package com.thread.demo.demo3;
public class MainClass {
/**
* 龟兔赛跑:2000米
*/
public static void main(String[] args) {
// 实例化乌龟和兔子
Tortoise tortoise = new Tortoise();
Rabbit rabbit = new Rabbit();
// 回调方法的使用,谁先调用calltoback方法,另一个就不跑了
LetOneStop letOneStop1 = new LetOneStop(tortoise);
// 让兔子的回调方法里面存在乌龟对象的值,可以把乌龟stop
rabbit.calltoback = letOneStop1;
LetOneStop letOneStop2 = new LetOneStop(rabbit);
// 让乌龟的回调方法里面存在兔子对象的值,可以把兔子stop
tortoise.calltoback = letOneStop2;
// 开始跑
tortoise.start();
rabbit.start();
}
}

运行结果:

4. 线程示例总结

(1)代码块锁是一个防止数据发生错误的一个重要手段;

(2)对象的统一性是非常重要的,这要想到对象的传入问题,要操作的对象只能new一次,其他的操作都是对这个传入的对象进行的,才能保证数据一致性,完整性和正确性。

php是什么?PHP能干什么?

thbcm阅读(197)

1.什么php?

一种服务器端的 HTML 脚本/编程语言,是一种简单的、面向对象的、解释型的、健壮的、安全的、性能非常之高的、独立于架构的、可移植的、动态的脚本语言。是一种广泛用于 Open Source(开放源代码)的尤其适合 Web 开发并可以嵌入 HTML 的多用途脚本语言。它的语法接近 C,Java 和 Perl,而且容易学习。该语言让 Web 开发人员快速的书写动态生成的网页。

PHP含义早期PHP:Personal HomePage,Rasmus Lerdorf后期PHP:PHP:Hypertext Preprocessor,超文本预处理器

PHP是一种脚本语言。编程语言:在执行前需要先进行编译的语言脚本语言:是一种解释型语言

2.PHP能做什么?

PHP 什么都能做,但是很多情况下需要借助其他插件。PHP是做动态网站的。(web)web1.0:静态网站(都是请求已经存在的静态页,不需要和数据库进行任何交互),通常请求文件都是以路径+文件名.html/htmweb2.0:动态网站,用户能够与服务器进行交互(服务器能够与数据库进行交互)

PHP负责处理用户提交的请求,与数据库进行关联,由PHP操作数据库进行数据的交互。

3.PHP发展史

1994:1.0:个人主页,perl(脚本语言)1996:2.0:C 语言底层 1998:3.0:zendEngine(zend公司开发)2000:4.0:session+输出缓冲等 2004:5.0:zend 引擎2代(完善PHP的面向对象变成)

4.PHP在哪运行?

PHP 是一种服务器端的脚本语言。

5.什么是服务器?

装有服务器软件的电脑。服务器软件:Apache,tomcat,iis,ftp,http,SVN

装有 Apache 的电脑称之为web服务器。

6.软件结构不论哪种结构都需要联网才能够工作。

c/s:client/server,客户端/服务端,必须同时运行客户端和服务端才能够使用软件。b/s:browser/server,浏览器/服务器(端),只要有浏览器就可以进行访问(一种特殊的c/s结构)

7.电脑间的通信IP:

唯一标识电脑的一个地址域名:Domain Name,对IP地址的别名,是为了方便用户去访问对应的“电脑”hosts:本地的域名解析器域名服务器:通过域名找到域名对应的IP地址

8.html是干嘛的?

用来规范数据的显示格式,保证每个用户看到的结果都是一样的。

web工作原理网站:多个网页组成的集合。
用户访问:URL:互联网的绝对路径 
网站管理员:一个网站就是一个文件夹(本地的绝对路径)

静态页的请求

请求步骤:

  1. 用户在浏览器中输入需要访问的网站的域名以及具体要请求的网页文件
  2. 域名解析:先找本地hosts文件,再找互联网上的DNS
  3. web服务器接收请求,获取请求文件index.html
  4. web服务器返回index.html
  5. 浏览器解析html代码,显示数据

动态页的请求:

请求步骤:

  1. 用户在浏览器中输入需要访问的网站的域名以及具体要请求的网页文件
  2. 域名解析:先找本地 hosts 文件,再找互联网上的 DNS
  3. web服务器接收请求,获取请求文件 index.php
  4. 将 index.php 文件交给 php 引擎处理
  5. php 引擎解析 php 代码,如果要连接数据库的话就调用 mysql 扩展,去操作数据库,最终解析完变成 html 文件
  6. php 引擎将生成的 html 文件交给 Apache
  7. web 服务器返回 index.php 得到的最终 html 文件
  8. 浏览器解析 html 代码,显示数据

修改 php 的时区在 php 的配置文件中去修改。/php/php.ini

注意:需要重启 Apache 后生效

Java线程之三种实现方式

thbcm阅读(198)

继承 Thread 类创建线程类

Thread 的实现步骤:

  1. 定义 Thread 的子类,重写 run()方法,run()方法代表了线程要完成的任务,run()方法称为线程执行体。
  2. 创建 Thread 子类的实例,子类对象就是线程。
  3. 调用线程对象的 start()方法来启动线程。
public class ThreadDemo extends Thread{

  public void run() {
      for(int i=0;i<10;i++) {
          System.out.println(currentThread().getName()+":" + i);
      }
  }

  public static void main(String args[]) {
      new ThreadDemo().start();
      new ThreadDemo().start();
  }
}

运行结果:
  

实现 Runnable 接口创建线程类

Runnable的实现步骤:

  1. 定义 Runnable 接口实现类,重写 run()方法,run() 方法代表了线程要完成的任务,run()方法称为线程执行体。
  2. 创建 Runnable 实现类的实例,Runnable 本身就是 Thread 类的方法,所以创建线程还要实现一个 Thread 类来包装 Runnable 对象。
  3.  调用线程对象的 start() 方法来启动线程。
public class RunnableDemo implements Runnable{

  String threadName;

  public RunnableDemo(String threadName) {
      this.threadName = threadName;
  }

  @Override
  public void run() {
      for(int i=0;i<10;i++) {
          System.out.println(threadName+":" + i);
      }
  }

  public static void main(String args[]) {
      new Thread(new RunnableDemo("A")).start();
      new Thread(new RunnableDemo("B")).start();
  }
}

运行结果:
  

实现 Callable 接口创建线程类

从 Java5 开始就提供了 Callable 接口,该接口是 Runnable 接口的增强版,Callable 接口提供一个 call() 方法作为线程执行体,call()方法可以有返回值,call() 方法可以声明抛出异常。

  • boolean cancel(boolean may) ​试图取消该 Future 里关联的 Callable 任务。
  • V get() ​返回 Call 任务里 call() 方法的返回值。调用该方法会照成线程阻塞,必须等待子线程结束后才会得到返回值。
  • V get(long timeout,TimeUnit unit) ​返回 Call 任务里 call() 方法的返回值。该方法让程序最多阻塞 timeout 和 unit 指定的时间,如果经过指定的时间,如果经过指定的时间依然没有返回值,将会抛出 TimeoutException 异常。
  • boolean isCancelled() ​如果在 Callable 任务正常完成前被取消,则返回 true。
  • boolean isDone() ​如果 Callable 任务已完成,则返回 true。

Runnable的实现步骤:

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法作为线程的执行体,call() 方法有返回值。
  2. 使用 FutrueTask 类包装 Callable 对象。
  3. 使用 FutrueTask 对象作为Thread 对象的 target 创建并启动新线程。
  4. 启用 FutrueTask 对象的 get() 方法来获得子线程的返回值。
public class CallableDemo implements Callable<Integer> {
  public static void main(String args[]) {
      FutureTask<Integer> futureTask = new FutureTask<Integer>(new CallableDemo());
      new Thread(futureTask).start();
      try {
          System.out.println("子线程返回值:" + futureTask.get());
      } catch (InterruptedException e) {
          e.printStackTrace();
      } catch (ExecutionException e) {
          e.printStackTrace();
      }
      if (futureTask.isDone()) {
          System.out.println("线程结束");
      }
  }

  @Override
  public Integer call() throws Exception {
      System.out.println("线程开始");
      int ss = 0;
      for (int i = 0; i < 20; i++) {
          ss += i;
      }
      return ss;
  }
}

运行结果:

python爬虫有什么实际作用

thbcm阅读(198)

小编说:网络爬虫是一种伴随着互联网诞生与演化的”古老”的网络技术,随着互联网进入大数据时代,爬虫技术迎来了一波新的振兴浪潮。 本文通过企业内部与互联网两个场景向大家讲书爬虫发挥了哪些重要作用。本文选自《虫术——Python绝技》一书。

在大数据架构中,数据收集与数据存储占据了极为重要的地位,可以说是大数据的核心基础。而爬虫技术在这两大核心技术层次中占有了很大的比例。为何有此一说?我们不妨通过一个实际应用场景来看看爬虫到底发挥了哪些作用?

主动——爬虫的重点在于”爬取”(Crawl),这是一种主动性的行为。换句话说,它是一个可以独立运行且能按照一定规则运作的应用程序。

自动化——由于处理的数据可能很分散,数据的存留具有一定的时效性,所以它是一套无人值守的自动化程序。

在我接近20年的IT从业生涯中,企业管理系统是我参与过的项目或产品中占比最大的。在这些项目与产品的开发过程中,我观察到很多企业内部其实有非常多的数据处理场景可以用爬虫技术进行处理,从而能以惊人的效率取代原有的人工化的操作。

以我近年来在电商企业内部所见为例,阿里巴巴(简称阿里)已显现出它在电子商务一统全球的实力与地位,几乎可以将电商与阿里之间划一个等号。阿里为各个店铺和商家提供了各种各样优秀的运营工具。我们会理所当然地认为电商企业内部的信息化管理程度一定很高,不是吗?然而事实恰恰相反,我见过的多数中小型的电商企业甚至是三板挂牌企业内部的信息化水平仍然非常落后,不少企业仍然依赖Excel这样基于大量人力为主导的表格处理。那么问题来了,为何阿里巴巴、京东这些电商平台已经提供了大量优质运营工具,而电商企业的信息化水平却很低,还需要靠劳动密集型的方式进行运营呢?

首先,电商企业不会只在某一平台上开店,通常都会在多个平台同时开多个店铺以拓宽市场的销售渠道;其次,电商企业之间、电商与供货商之间缺乏统一的数据交换标准,通常只依赖于一些技术陈旧的 ERP 来维持日常的运营。

电商企业通常只能通过某一平台上提供的专用工具监测某些产品的价格波动和销售情况,而无法全面、统一地了解他们所销售的产品在各大平台的具体表现如何。然而这样的需求很明显是迫切的,因为只有了解销售数据的变化才能实时调节销售的策略。我见过最多的做法就是企业安排一位专人从各大电商平台中导出运行的数据,然后合并到 Excel 中,再进行一番统计,手工做出各种统计报表作为分析依据,这种做法往往对某一个单品就得做一次!

(1)缺乏统一的数据来源——这是不可调和的,因为电商运行的数据源本来就具有多样性。

(2)结构化数据与非结构化数据并存——企业间最常见的数据交互格式是Excel,交互工具是微信和QQ。

(3)一个数据存在多种时间版本——QQ或者微信上的同一个文件修改多了且重复传会出现各种的 data.xlsx、data(1).xlsx…data(n).xlsx。

(4)数据结构可能存在随意性——Excel文件内很少会看见用英文命名的列,甚至相同作用的列很有可能会采用不同的中文名。

(5)数据查找变得困难——在电商企业与供货商之间要找出某个时段相同的数据副本可能是一件极为可怕的事件。

我们不妨来大胆地假设一下,如果将这些事情换成让爬虫去处理,那么情况会变成什么样子呢?

(1)每天爬虫在一个固定的时间到淘宝、京东或者其他电商平台上自动下载商家当前的营业数据。

(3)从内网的某台PC的指定文件夹中下载每天从其他经销商发来的Excel文件,整理后保存到数据库。

(4)发现某些商品库存不足自动生成供货商规定格式的订货单,通过电子邮件发出。

(5)决策者(运营经理/老板)在手机或 PC 中通过数据可视化工具查看每天的数据统计结果,或者由爬虫系统直接生成统计报表发到他们的邮箱中。

此时你可能会产生这样的疑问:爬虫不是单单爬取数据的吗?为何还能处理这么多的事情呢?这还是爬虫的技术领域吗?答案是肯定的,上面这个例子是由我经历过的一个项目中的真实案例简化而来的,爬虫的这些行为融合了对爬取数据的后处理与Python自动化后得到的效果。其实爬虫能做到的事情可以更多,具体的实现与企业内部的实际需求相关。而在互联网中,它更像是一个具有”智能”的机器人。

企业内网爬虫只是互联网爬虫的一个小范围的应用,是爬虫技术与自动化技术的一种综合性应用,而且自动化技术的占比可能会比爬虫技术手段更多一些。

与企业爬虫相比,互联网爬虫就显得更为单一与常见,在这个数据唾手可得的时代,在数据中用爬虫淘金并不鲜见。如搜索引擎本身就是”虫术大师”,只要是它们想爬的网站,几乎是没有爬不穿的。App Store 上最火的内容性 App 总是某些新闻类的聚合应用,大多数网站开发者都知道那只是一个聚合了各种新闻网站链接的综合性平台,它们的内容也是靠”放虫”才可能在各大新闻门户中获取第一手的新闻信息。更重要的是,这些新闻信息都是”免费”的,任何一个用户都可以轻易地从互联网上获取,这个用户当然也可以包括”虫子”。

互联网中存在大量如新闻资讯一类的免费内容,或是政府、企业、第三方机构、团体甚至个人共享的各种数据。例如,我们可以轻易地到气象局的网站上获取近十年某个地区的降雨量信息,或者从证券交易所获取当天各支股票的价格走势,又或者到微博上获知当天最具有传播性的某个事件的详情。换句话说,只要有清晰的目标数据源,只要你具有对数据源具有访问的权限,那么你也可以让爬虫为你代劳,一次性从数据源上获取所有你想要的数据。

要通过爬虫顺利地从互联网中爬取数据,那么就得了解这些数据的特质,然后采取针对性的手段才可能做到无往不利。一般来说,互联网中可爬取的数据可分为以下几种:

(1)一般性的网页——符合W3C规范的网页都可视为一种半结构化的内容,可以通过一些页面元素分析工具从网页中读取指定数据,由于网页开发的自由度极大,几乎没有哪个网站的结构是完全相同的。而且可变因素也很多,可能网页读取要通过权限的审查,或者网页由客户端的JavaScript进行绘制才能呈现最终效果,甚至网页可能来源于CDN,其内容未必是最新的,只是某个网络缓存的副本,等等。不过不用担心,当你完全掌握了虫术,这一切对你将不再是阻挡。

(2)API资源——API资源是最适合爬取的数据源(没有之一),因为 RESTful API 都是结构化数据,会以 XML 或者 JSON 的形式进行调用或者返回,这些数据内容即使没有API说明手册一般也能读懂。

(3)文件资源——文件资源属于最麻烦的数据源了,除非爬取的文件是以结构化数据格式呈现的,否则作为自由文本,由于是非结构化的,我们需要对文本的内容进行一些后处理,要让爬虫”读懂”这些文本内容,再判断哪些内容是获取的目标。

(4)媒体资源——如图片和视频等,其爬取的动作基本与文件类似,只是由于图片与视频等资源一般来说都比较大,可能还需要对文件的元信息进行一些分析以判断其是否具有爬取的价值,以避免让爬虫过多地消耗不必要的网络流量与爬取时间。

爬虫涉及的技术领域很多,运用的技术也非常庞杂,从基本的网络访问到复杂的机器学习,可能会让初入门径者有望而却步的想法。为了让大家有一个全面的认识,我们特意将初级、中级、高级三个阶段中所要学习与使用的技术归纳成下图以作参考。

互联网最激烈的对抗战场,除了安全专家与黑客之间,大概就是爬虫与反爬虫领域了。据统计,爬虫流量早已超过了人类真实访问请求流量。互联网充斥着形形色色的爬虫,云上、传统行业都有不同规模的用户被爬虫爱好者盯上,这些爬虫从哪里来?爬取了谁的数据?数据将被用于何处? 

0基础学python有多难

thbcm阅读(208)

0基础学 Python 有多难?该怎么入门?零基础学 Python 并不难,因为 Python 是一门非常适合初学者入门的编程语言。Python 语法简单明了,代码可读性很高,容易入门。但 Python 对代码的要求非常严谨,而对于初学者更利于养成良好的代码习惯。

对于初学者规范自己的学习有很大的帮助,同时还可以帮助初学者看懂别人的代码。Python 语法设计非常优秀,思想较现代化,可以更快了解为现代编程语言的一些思想,最重要的是 Python 在各大领域具有非常好的作用,对于学一门语言作为工具来说 Python 非常合适选择。该如何学习 Python 呢?

选择学习方向,学习 Python 主要目的是用语言来解决问题,而不是了解这门语言。Python 应用方向有很多,Python 基础知识学习完后,应用方向不同需求也不同;虽然 Python 需要系统化的学习,但是在学习 Python 的时候,想要告诉大家还是需要提前确定一下自己感兴趣的方向,有针对性的学习更为重要。

规划学习路线,当确定好自己的发展方向之后,下一步就是顺着方向去学习,建立好自己的学习路线。要有系统化的学习路线,需要完成什么样的目标,需要学习哪些知识,需要懂哪些知识,这样每次学习一个部分,就可以有实际的结果输出,结果的输出才可以鼓励进行下一步的学习。

合理规划时间,划好自己的学习时间,每天进度是什么,每天学习几个小时都是需要提前确定的,有计划有规划的去学习,坚持下来才会有意外的收获。

用任何编程语言来开发程序,都是为了让计算机工作。目前有很多种流行的编程语言,如难学的 C 语言,普遍的 Java 语言,适合初学者的 Basic 语言,适合网页编程的 JavaScript 语言等,Python 适合初学者的一种计算机程序设计语言。

掌握一门编程语言小编建议找老师带你学习,遇到问题可以请教老师或者其他同学一起讨论。所以0基础能不能学会 Python 重点在于学习方法和自身努力程度,掌握正确的学习方法0基础也可以学会 Python。

推荐好课:Python3入门Python3零基础入门到爬虫实战

为何python不好找工作?

thbcm阅读(192)

这是读者在微信上问我的一个问题,我当时给他的回复是 Python 挺火的,学 Python 就好。但当我在网上看某 Python 视频后,深感懊悔,觉得自己给出的建议是不负责任的。

意识到自己的问题之后,我就赶紧给读者发了一条信息道歉。另外,回想起之前还有一些读者问过我类似的问题,我的答案都不够严谨,因此打算特意写一篇文章来反省一下。

视频里面分享的内容还是非常严谨的,他认为,Python 应用的方向主要有 5 个方面:

  1. 人工智能和机器学习
  2. 数据分析
  3. 爬虫
  4. Web 开发
  5. 自动化测试

有理有据,所以我完全认同他的观点。

1、人工智能和机器学习

人工智能和机器学习是 Python 应用的重头戏,但这方面的岗位对学历的要求非常高,高到我自己都应聘不上,非常残酷。

在招聘网站上大致浏览了一下,我发现,这方面的岗位不算多,但工资挺给力的,在 15K- 30K。不过,招聘信息上直接说了,”我们的程序员小伙伴都毕业于 211/985 学校”,就这一条,我就会被拒之门外。学历硬伤啊,所以应聘”人工智能和机器学习”这方面的岗位很难,扎心,谁叫咱不是学霸呢。

考虑到我的读者已经蔓延到了初中生群体,我得郑重其事地说一句,”如果你喜欢学习,那就好好学,别在该学习的年纪浪费了青春。”哎呀,我去,说这句话真有点拿自己做反面教材的感觉。

我上小学的时候,一直是第一名,因为学校的招生范围就我们村那么大,一共也就三四十名学生。等到上了初中,一直保持前四,因为学校的招生范围就我们乡那么大,一共也就三四百名学生。等到上了高中,一直保持学校前十,但在整个县城是没有任何优势的。

真的是天外有天,人外有人,大部分人都是平凡的,普通的,所以这方面的岗位竞争真的很难。

2、数据分析

一般的小公司,比如说我就职过的公司,完全就没有数据分析的必要性,因为重点是在产品上,如何做好产品吸引来用户才是重点。如果说产品的用户数量少,数据就完全发挥不出价值。

那也就意味着,数据分析工程师的岗位会相对较少,毕竟有大数据的公司屈指可数。但说实话,这个岗位的薪资还是非常给力的,发展前景也好。如果学习能力强的话,硬指标过关的话,可以尝试。

工资高,通常的原因是供不应求,也就是说岗位多,但人才少。但实际情况是,数据分析的岗位少,符合要求的人才更少。在公司只是在重复操作 SQL、Excel 等基础工具的数据分析员很容易被自动化工具替代,又扎心了。

大专院校把 Python 作为主语言来教的话,我想肯定不是奔着这两个方向(人工智能、机器学习和数据分析)来的。第一个原因就是学历的问题,第二个原因就是教师不一定能教得会,更别说学生能不能学会了。

3、爬虫

关于爬虫,不得不提一下羊哥视频评论区的一句话,不管是不是段子,我觉得挺值得深思的。我有个同学搞爬虫被带走了,还好他不是主犯,就是登记了一下。

爬虫是近些年非常火热的一个话题,连我都买了一本爬虫入门的书,准备学一学,无奈 Java 方面可写的素材越来越多,这个计划一直未能成行。

什么是爬虫呢?可能有些不是程序员的读者不太清楚,我找百科问了问,它说,”爬虫,又称网页蜘蛛,是一种按照一定规则,自动抓取互联网信息的程序或者脚本。”

在知识付费的大环境下,这种爬虫就有点麻烦。拿我来说吧,我希望自己的文章只发表在我希望发表的平台下,假如其他平台在未经我的授权下,就把我的文章爬走,放在自家平台上,我就觉得知识产权受到了破坏。

文章还好,是我愿意公开的,如果涉及到一些隐私信息被爬取,那就更糟糕了,是吧?

现在很多平台都在做反爬,并且做得越来越好,这就在一定程度上有点”魔高一尺道高一丈”的意味,所以,爬虫方面的工程师还是蛮不容易的。

4、Web 开发

用 Python 做 Web 开发的大型互联网公司我听说的不多,羊哥说豆瓣以前用的是 Python,现在也不用了。

不管怎么说,如果拿 Java 来和 Python 相比的话,显然在 Web 开发方面的优势巨大。不管是从技术框架上,还是性能上,以及应用的规模上,同等条件下,Java 工程师显然更吃香啊。

很多培训机构夸赞 Python 在 Web 开发方面有着巨大的优势,开发效率高,速度快。嗯,其实我觉得应该是因为 Python 的语法简单,容易教——这恐怕是主要原因啊,我这样说会不会被社会毒打?

5、自动化测试

说句实在话,Python 的自动化测试还是应用非常广泛的,考虑到框架的脚本质量,测试用例的简单性,以及运行模块可能存在的技术弱点,我给大家推荐五款 Python 的测试框架。

1)Robot Framework,主要用于测试驱动类型的开发与验收中。

2)Pytest,特点是开源、易学。

3)PyUnit,针对单元测试的 Python 类自动化测试框架,收到 Junit 的启发。

4)Behave,允许团队执行 BDD(行为驱动开发,behavior-driven development) 测试。

5)Lettuce,专注于具有行为驱动开发特征的普通任务。

6、总结 

以上观点都是我个人主观给出的,不一定正确哈,仅做参考。

如果说,有些读者的学历非常牛逼,然后学习能力也非常强,那么选择人工智能、机器学习、数据分析,我觉得前途是光明的,既能赚钱,待遇又好,还不可替代,不学 Python 绝对亏。

如果说,有些读者学历一般,做程序员仅仅是为了糊口饭吃,那么我觉得可以把 Python 作为第二语言来学,不要当做主语言。搞点范围许可内的爬虫,自动化测试,我就觉得挺好的。况且 Python 这门语言本身是非常优秀的,不然怎么搞人工智能,海量数据分析,对吧?

在此推荐几个我认为很不错的Python教程供大家学习:

联系我们