当前位置:首页 » 编程语言 » pythondefer

pythondefer

发布时间: 2024-09-18 18:42:20

Ⅰ 各种编程语言配置代理IP(python,php,java,nodejs,ruby...)

代理IP对于爬虫采集来说至关重要,它能够帮助我们绕过各种限制,让数据采集更加高效便捷。以下提供几种常见编程语言配置代理IP的方法,以供参考。

为了确保代码片段的实用性和可扩展性,本文将仅提供核心代码片段,具体的业务逻辑需要根据实际项目需求自行添加。

在配置代理IP前,请确保你已经准备好相应的代理资源。你可以选择使用如kuaidaili.com等代理服务提供商,或自行构建代理服务器

以下是部分编程语言配置代理IP的示例代码:

PHP配置代理IP:
php
$proxy = 'http://username:password@proxy-host:port';
$options = array(
'http' => array(
'proxy' => $proxy,
),
);

Python配置代理IP:
python
proxies = {
'http': 'http://username:password@proxy-host:port',
'https': 'http://username:password@proxy-host:port'
}

Java配置代理IP:
java
HttpClient httpclient = HttpClients.createDefault();
RequestConfig requestConfig = RequestConfig.custom()
.setProxy(new HttpHost("proxy-host", port, "http"))
.build();
HttpGet httpget = new HttpGet("http://www.example.com");
httpget.setConfig(requestConfig);
HttpResponse response = httpclient.execute(httpget);

Node.js配置代理IP:
javascript
const https = require('https');
const proxy = 'http://username:password@proxy-host:port';
const options = {
hostname: 'example.com',
port: 443,
path: '/path/to/resource',
method: 'GET',
headers: {
'Proxy-Authorization': `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
'User-Agent': 'nodejs-client'
}
};
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`);
});
req.on('data', (d) => {
process.stdout.write(d);
});
req.end();

Ruby配置代理IP:
ruby
require 'net/http'
uri = URI('http://example.com')
proxy_uri = URI('http://proxy-host:port')
proxy = Net::HTTP::Proxy.new(proxy_uri.host, proxy_uri.port)
req = Net::HTTP::Get.new(uri.request_uri)
req.proxy = proxy
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(req)
end

Golang配置代理IP:
go
import (
"net/http"
"net/url"
)
func main() {
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(&url.URL{
Scheme: "http",
Host: "username:password@proxy-host:port",
}),
},
}
resp, err := client.Get("http://www.example.com")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
}

Ⅱ python fetchone 取出的数据是什么类型

举例,首先看了pymysql里面的cursor类,关于execute、fetchone和fetchall定义如下:
#调用self._query方法进行查询
def execute(self, query, args=None):
"""Execute a query
:param str query: Query to execute.
:param args: parameters used with query. (optional)
:type args: tuple, list or dict
:return: Number of affected rows
:rtype: int
If args is a list or tuple, %s can be used as a placeholder in the query.
If args is a dict, %(name)s can be used as a placeholder in the query.
"""
while self.nextset():
pass
query = self.mogrify(query, args)
result = self._query(query)
self._executed = query
return result
#调用_do_get_result获取查询结果
def _query(self, q):
conn = self._get_db()
self._last_executed = q
self._clear_result()
conn.query(q)
self._do_get_result()
return self.rowcount
#这里获取结果
def _do_get_result(self):
conn = self._get_db()
self._result = result = conn._result
self.rowcount = result.affected_rows
self.description = result.description
self.lastrowid = result.insert_id
self._rows = result.rows
self._warnings_handled = False

if not self._defer_warnings:
self._show_warnings()
其实看到这里代码逻辑已经很清楚了,在调用cursor.execute执行SQL的时候,就将MySQL查询的结果放到result这个变量里了,也就是说结果集放到了客户端的内存变量里,那么获取数据的方式也就是从这个内存变量里去获取数据,只是获取的行为有所不同而已了。
def fetchone(self):
"""Fetch the next row"""
self._check_executed()
if self._rows is None or self.rownumber >= len(self._rows):
return None
result = self._rows[self.rownumber]
self.rownumber += 1
return result

def fetchmany(self, size=None):
"""Fetch several rows"""
self._check_executed()
if self._rows is None:
return ()
end = self.rownumber + (size or self.arraysize)
result = self._rows[self.rownumber:end]
self.rownumber = min(end, len(self._rows))
return result
def fetchall(self):
"""Fetch all the rows"""
self._check_executed()
if self._rows is None:
return ()
if self.rownumber:
result = self._rows[self.rownumber:]
else:
result = self._rows
self.rownumber = len(self._rows)
return result
口说无凭,我们直接通过Wireshark抓包来证明一下,首先我在本地执行脚本如下,然后我监听本地的网卡流量
import pymysql
conn = pymysql.connect(host='xxx', port=3306,
user='xucl', password='xuclxucl', database='xucl')
cursor = conn.cursor()
cursor.execute("select * from t")
注意,我这里并没有执行fetch操作,如果监听到的包里面包含了结果,那么就证明我们前面的分析是正确的,话不多说开始实验,Wireshark抓包如下:
果然跟我们之前的预测是一致的,即使没有进行fetch操作,MySQL也将结果集发送到客户端了。另外关于结果集发送,可以参考我另外一篇文章:《由一个抓瞎的SQL引申出去》

结论:
客户端执行SQL的时候,MySQL一次性将结果集发送给了客户端
客户端接收到结果集以后存储本地内存变量中
fetch结果只是从这个本地变量中获取,fetchone/fetchmany/fetchall只是获取行为的不通,因此对于MySQL来说并没有什么不通的。

Ⅲ python能把正常时间转化成毫秒级别的时间戳吗

可以啊,就是datetime转时间戳吧。
你可以参考一下这里的:http://defer.cn/2014/12/1657.html
不过time.time好像悄山斗是秒,如启磨唯姿果要毫秒,需要乘以1000

Ⅳ 从PHP 到Golang 的笔记 ( 转 )

———文章来源 YamiOdymel/PHP-to-Golang

PHP和模块之间的关系令人感到烦躁,假设你要读取 yaml 档案,你需要有一个 yaml 的模块,为此,你还需要将其编译然后将编译后的模块摆放至指定位置,之后换了一台服务器你还要重新编译,这点到现在还是没有改善;顺带一提之后出了PHP 7效能确实提升了许多(比Python 3快了些),但PHP仍令我感到臃肿,我觉得是时候
(转行)了。

PHP 和Golang 的效能我想毋庸置疑是后者比较快(而且是以倍数来算),也许有的人会认为两种不应该被放在一起比较,但Golang 本身就是偏向Web 开发的,所以这也是为什么我考虑转用Golang 的原因,起初我的考虑有几个:Node.js 和Rust 还有最终被选定的Golang;先谈谈Node.js 吧。

Node.js的效能可以说是快上PHP 3.5倍至6倍左右 ,而且撰写的语言还是JavaScript,蒸蚌,如此一来就不需要学习新语言了!搭配Babel更可以说是万能,不过那跟“跳跳虎”一样的Async逻辑还有那恐怖的Callback Hell,有人认为前者是种优点,这点我不否认,但是对学习PHP的我来说太过于"Mind Fuck",至于后者的Callback Hell虽然有Promise,但是那又是另一个“Then Hell”的故事了。相较于Golang之下,Node.js似乎就没有那么吸引我了。你确实可以用Node.js写出很多东西,不过那V8引擎的效能仍然有限,而且要学习新的事物,不就应该是“全新”的吗;)?

题外话: 为什么Node.js不适合大型和商业专案?

在抛弃改用Node.js 之后我曾经花了一天的时间尝试Rust 和Iron 框架,嗯⋯⋯Rust 太强大了,强大到让我觉得Rust 不应该用在这里,这想法也许很蠢,但Rust 让我觉得适合更应该拿来用在系统或者是部分底层的地方,而不应该是网路服务。

Golang是我最终的选择,主要在于我花了一天的时间来研究的时候意外地发现Golang夭寿简洁( 关键字只有25个 ),相较之下Rust太过于“强大”令我怯步;而且Golang带有许多工具,例如 go fmt 会自动帮你整理程式码、 go doc 会自动帮你生产文件、 go test 可以自动单元测试并生产覆盖率报表、也有 go get 套件管理工具(虽然没有版本功能),不过都很实用,而且也不需要加上分号( ; ),真要说不好的地方⋯⋯大概就是强迫你花括号不能换行放吧(没错,我就是花括号会换行放的人)。

当我在撰写这份文件的时候 我会先假设你有一定的基础 ,你可以先阅读下列的手册,他们都很不错。

你能够在PHP 里面想建立一个变数的时候就直接建立,夭寿赞,是吗?

蒸蚌!那么Golang 呢?在Golang 中变数分为几类:“新定义”、“预先定义”、“自动新定义”、“覆盖”。让我们来看看范例:

在PHP中你会很常用到 echo 来显示文字,像这样。

然而在Golang中你会需要 fmt 套件,关于“什么是套件”的说明你可以在文章下述了解。

这很简单,而且两个语言的用法相差甚少,下面这是PHP:

只是Golang 稍微聒噪了一点,你必须在函式后面宣告他最后会回传什么资料型别。

在PHP 中你要回传多个资料你就会用上阵列,然后将资料放入阵列里面,像这样。

然而在Golang 中你可以不必用到一个阵列,函式可以一次回传多个值:

两个语言的撰写方式不尽相同。

主要是PHP 的阵列能做太多事情了,所以在PHP 里面要储存什么用阵列就好了。

在Golang里⋯⋯没有这么万能的东西,首先要先了解Golang中有这些型态: array , slice , map , interface ,

你他妈的我到底看了三洨,首先你要知道Golang是个强型别语言,意思是你的阵列中 只能有一种型态 ,什么意思?当你决定这个阵列是用来摆放字串资料的时候,你就只能在里面放字串。没有数值、没有布林值,就像你没有女朋友一样。

先撇开PHP 的“万能阵列”不管,Golang 中的阵列既单纯却又十分脑残,在定义一个阵列的时候,你必须给他一个长度还有其内容存放的资料型态,你的阵列内容不一定要填满其长度,但是你的阵列内容不能超过你当初定义的长度。

切片⋯⋯这听起来也许很奇怪,但是你确实可以“切”他,让我们先谈谈“切片”比起“阵列”要好在哪里:“你不用定义其最大长度,而且你可以直接赋予值”,没了。

我们刚才有提到你可以“切”他,记得吗?这有点像是PHP中的 array_slice() ,但是Golang直接让Slice“内建”了这个用法,其用法是: slice[开始:结束] 。

在PHP中倒是没有那么方便,在下列PHP范例中你需要不断地使用 array_slice() 。

你可以把“映照”看成是一个有键名和键值的阵列,但是记住:“你需要事先定义其键名、键值的资料型态”,这仍限制你没办法在映照中存放多种不同型态的资料。

在Golang里可就没这么简单了,你需要先用 make() 宣告 map 。

也许你不喜欢“接口”这个词,但用“接口”我怕会误导大众,所以,是的,接下来我会继续称其为“接口”。还记得你可以在PHP 的关联阵列里面存放任何型态的资料吗,像下面这样?

现在你有福了!正因为Golang中的 interface{} 可以接受任何内容,所以你可以把它拿来存放任何型态的资料。

有时候你也许会有个不定值的变数,在PHP 里你可以直接将一个变数定义成字串、数值、空值、就像你那变心的女友一样随时都在变。

在Golang中你必须给予变数一个指定的资料型别,不过还记得刚才提到的:“Golang中有个 interface{} 能够 存放任何事物 ”吗( 虽然也不是真的任何事物啦⋯⋯ )?

当我们程式中不需要继续使用到某个资源或是发生错误的时候,我们索性会将其关闭或是抛弃来节省资源开销,例如PHP 里的读取档案:

在Golang中,你可以使用 defer 来在函式结束的时候自动执行某些程式(其执行方向为反向)。所以你就不需要在函式最后面结束最前面的资源。

defer 可以被称为“推迟执行”,实际上就是在函式结束后会“反序”执行的东西,例如你按照了这样的顺序定义 defer : A->B->C->D ,那么执行的顺序其实会是 D->C->B->A ,这用在程式结束时还蛮有用的,让我们看看Golang如何改善上述范例。

这东西很邪恶,不是吗?又不是在写BASIC,不过也许有时候你会在PHP 用上呢。但是拜托,不要。

Golang中仅有 for 一种回圈但却能够达成 foreach 、 while 、 for 多种用法。普通 for 回圈写法在两个语言中都十分相近。

在Golang请记得:如果你的 i 先前并不存在,那么你就需要定义它,所以下面这个范例你会看见 i := 0 。

在PHP里, foreach() 能够直接给你值和键名,用起来十分简单。

Golang里面虽然仅有 for() 但却可以使用 range 达成和PHP一样的 foreach 方式。

一个 while(条件) 回圈在PHP里面可以不断地执行区块中的程式,直到 条件 为 false 为止。

在Golang里也有相同的做法,但仍是透过 for 回圈,请注意这个 for 回圈并没有任何的分号( ; ),而且一个没有条件的 for 回圈会一直被执行。

PHP中有 do .. while() 回圈可以先做区块中的动作。

在Golang中则没有相关函式,但是你可以透过一个无止尽的 for 回圈加上条件式来让他结束回圈。

要是你真的希望完全符合像是PHP那样的设计方式,或者你可以在Golang中使用很邪恶的 goto 。

在PHP中我们可以透过 date() 像这样取得目前的日期。

在Golang就稍微有趣点了,因为Golang中并不是以 Y-m-d 这种格式做为定义,而是 1 、 2 、 3 ,这令你需要去翻阅文件,才能够知道 1 的定义是代表什么。

俗话说:“爆炸就是艺术”,可爱的PHP用词真的很大胆,像是: explode() (爆炸)、 die() (死掉),回归正传,如果你想在PHP里面将字串切割成阵列,你可以这么做。

简单的就让一个字串给“爆炸”了,那么Golang 呢?

对了,记得引用 strings 套件。

这真的是很常用到的功能,就像物件一样有着键名和键值,在PHP 里面你很简单的就能靠阵列(Array)办到。

真是太棒了,那么Golang呢?用 map 是差不多啦。如果有必要的话,你可以稍微复习一下先前提到的“多资料储存型态-Stores”。

你很常会在PHP里面用 isset() 检查一个索引是否存在,不是吗?

在Golang里面很简单的能够这样办到(仅适用于 map )。

指针(有时也做参照)是一个像是“变数别名”的方法,这种方法让你不用整天覆盖旧的变数,让我们假设 A = 1; B = A; 这个时候 B 会复制一份 A 且两者不相干,倘若你希望修改 B 的时候实际上也会修改到 A 的值,就会需要指针。

指针比起复制一个变数,他会建立一个指向到某个变数的记忆体位置,这也就是为什么你改变指针,实际上是在改变某个变数。

在Golang你需要用上 * 还有 & 符号。

有些时候你会回传一个阵列,这个阵列里面可能有资料还有错误代号,而你会用条件式判断错误代号是否非空值。

在Golang中函式可以一次回传多个值。为此,你不需要真的回传一个阵列,不过要注意的是你将会回传一个属于 error 资料型态的错误,所以你需要引用 errors 套件来帮助你做这件事。

该注意的是Golang没有 try .. catch ,因为 Golang推荐这种错误处理方式 ,你应该在每一次执行可能会发生错误的程式时就处理错误,而非后来用 try 到处包覆你的程式。

在 if 条件式里宣告变数会让你只能在 if 内部使用这个变数,而不会污染到全域范围。

也许你在PHP中更常用的会是 try .. catch ,在大型商业逻辑时经常看见如此地用法,实际上这种用法令人感到聒噪(因为你会需要一堆 try 区块):

Golang中并没有 try .. catch ,实际上Golang也 不鼓励这种行为 (Golang推荐逐一处理错误的方式),倘若你真想办倒像是捕捉异常这样的方式,你确实可以使用Golang中另类处理错误的方式(可以的话尽量避免使用这种方式): panic() , recover() , defer 。

你可以把 panic() 当作是 throw (丢出错误),而这跟PHP的 exit() 有87%像,一但你执行了 panic() 你的程式就会宣告而终,但是别担心,因为程式结束的时候会呼叫 defer ,所以我们接下来要在 defer 停止 panic() 。

关于 defer 上述已经有提到了,他是一个反向执行的宣告,会在函式结束后被执行,当你呼叫了 panic() 结束程式的时候,也就会开始执行 defer ,所以我们要在 defer 内使用 recover() 让程式不再继续进行结束动作,这就像是捕捉异常。

recover() 可以看作 catch (捕捉),我们要在 defer 里面用 recover() 解决 panic() ,如此一来程式就会回归正常而不会被结束。

还记得在PHP里要引用一堆档案的日子吗?到处可见的 require() 或是 include() ?到了Golang这些都不见了,取而代之的是“套件(Package)”。现在让我们来用PHP解释一下。

这看起来很正常对吧?但假设你有一堆档案,这马上就成了 Include Hell ,让我们看看Golang怎么透过“套件”解决这个问题。

“ 蛤???杀小??? ”你可能如此地说道。是的, main.go 中除了引用 fmt 套件( 为了要输出结果用的套件 )之外完全没有引用到 a.go 。

“ 蛤???杀小?????? ”你仿佛回到了几秒钟前的自己。

既然没有引用其他档案,为什么 main.go 可以输出 foo 呢?注意到了吗, 两者都是属于 main 套件 ,因此 他们共享同一个区域 ,所以接下来要介绍的是什么叫做“套件”。

套件是每一个 .go 档案都必须声明在Golang原始码中最开端的东西,像下面这样:

这意味着目前的档案是属于 main 套件( 你也可以依照你的喜好命名 ),那么要如何让同个套件之间的函式沟通呢?

接着是Golang;注意!你不需要引用任何档案,因为下列两个档案同属一个套件。

一个由“套件”所掌握的世界,比起PHP的 include() 和 require() 还要好太多了,对吗?

在Golang 中没有引用单独档案的方式,你必须汇入一整个套件,而且你要记住:“一定你汇入了,你就一定要使用它”,像下面这样。

假如你不希望使用你汇入的套件,你只是为了要触发那个套件的 main() 函式而引用的话⋯⋯,那么你可以在前面加上一个底线( _ )。

如果你的套件出现了名称冲突,你可以在套件来源前面给他一个新的名称。

现在你知道可以汇入套件了,那么什么是“汇出”?同个套件内的函式还有共享变数确实可以直接用,但那 并不表示可以给其他套件使用 ,其方法取决于 函式/变数的“开头大小写”

是的。 Golang依照一个函式/变数的开头大小写决定这个东西是否可供“汇出”

这用在区别函式的时候格外有用,因为小写开头的任何事物都是不供汇出的,反之,大写开头的任何事物都是用来汇出供其他套件使用的。

一开始可能会觉得这是什么奇异的规定,但写久之后,你就能发现比起JavaScript和Python以“底线为开头的命名方式”还要来得更好;比起成天宣告 public 、 private 、 protected 还要来得更快。

在Golang 中没有类别,但有所谓的“建构体(Struct)”和“接口(Interface)”,这就能够满足几乎所有的需求了,这也是为什么我认为Golang 很简洁却又很强大的原因。

让我们先用PHP 建立一个类别,然后看看Golang 怎么解决这个问题。

虽然Golang没有类别,但是“建构体(Struct)”就十分地堪用了,首先你要知道在Golang中“类别”的成员还有方法都是在“类别”外面所定义的,这跟PHP在类别内定义的方式有所不同,在Golang中还有一点,那就是他们没有 public 、 private 、 protected 的种类。

在PHP中,当有一个类别被 new 的时候会自动执行该类别内的建构子( __construct() ),通常你会用这个来初始化一些类别内部的值。

但是在Golang 里因为没有类别,也就没有建构子,不巧的是建构体本身也不带有建构子的特性,这个时候你只能自己在外部建立一个建构用函式。

让我们假设你有两个类别,你会把其中一个类别传入到另一个类别里面使用,废话不多说!先上个PHP 范例(为了简短篇幅我省去了换行)。

在Golang中你也有相同的用法,但是请记得:“ 任何东西都是在“类别”外完成建构的 ”。

在PHP 中没有相关的范例,这部分会以刚才“嵌入”章节中的Golang 范例作为解说对象。

你可以看见Golang在进行 Foo 嵌入 Bar 的时候,会自动将 Foo 的成员暴露在 Bar 底下,那么假设“双方之间有相同的成员名称”呢?

这个时候被嵌入的成员就会被“遮蔽”,下面是个实际范例,还有你如何解决遮蔽问题:

虽然都是呼叫同一个函式,但是这个函式可以针对不同的资料来源做出不同的举动,这就是多形。你也能够把这看作是:“讯息的意义由接收者定义,而不是传送者”。

目前PHP 中没有真正的“多形”,不过你仍可以做出同样的东西。

嗯⋯⋯那么Golang呢?实际上更简单而且更有条理了,在Golang中有 interface 可以帮忙完成这个工作。

如果你对Interface还不熟悉,可以试着查看“ 解释Golang中的Interface到底是什么 ”文章。

谢谢你看到这里,可惜这篇文章却没有说出Golang 最重要的卖点:“Goroutine”和“Channel”

Ⅳ 驳狗屎文 "我为什么放弃Go语言

此篇文章流传甚广, 其实里面没啥干货, 而且里面很多观点是有问题的. 这个文章在 golang-china 很早就讨论过了.
最近因为 Rust 1.0 和 1.1 的发布, 导致这个文章又出来毒害读者.
所以写了这篇反驳文章, 指出其中的问题.

有好几次,当我想起来的时候,总是会问自己:我为什么要放弃Go语言?这个决定是正确的吗?是明智和理性的吗?其实我一直在认真思考这个问题。
开门见山地说,我当初放弃Go语言(golang),就是因为两个“不爽”:第一,对Go语言本身不爽;第二,对Go语言社区里的某些人不爽。毫无疑问,这是非常主观的结论。但是我有足够详实的客观的论据,用以支撑这个看似主观的结论。
文末附有本文更新日志。
确实是非常主观的结论, 因为里面有不少有问题的观点(用来忽悠Go小白还行).
第0节:我的Go语言经历
先说说我的经历吧,以避免被无缘无故地当作Go语言的低级黑。
2009年底,Go语言(golang)第一个公开版本发布,笼罩着“Google公司制造”的光环,吸引了许多慕名而来的尝鲜者,我(Liigo)也身居其中,笼统的看了一些Go语言的资料,学习了基础的教程,因对其语法中的分号和花括号不满,很快就遗忘掉了,没拿它当一回事。
在2009年Go刚发布时, 确实是因为“Google公司制造”的光环而吸引了(包括文章作者和诸多IT记者)很多低级的尝鲜者.
还好, 经过5年的发展, 这些纯粹因为光环来的投机者所剩已经不多了(Google趋势).
目前, 真正的Go用户早就将Go用于实际的生产了.
说到 其语法中的分号和花括号不满, 我想说这只是你的 个人主观感受, 还有很多人对Go的分号和花括号很满意,
包括水果公司的的 Swift 的语言设计者也很满意这种风格(Swift中的分号和花括号和Go基本相同).
如果只谈 个人主观感受, 我也可以说 Rust 的 fn 缩写也很蛋疼!
两年之后,2011年底,Go语言发布1.0的计划被提上日程,相关的报道又多起来,我再次关注它,重新评估之后决定深入参与Go语言。我订阅了其users、nuts、dev、commits等官方邮件组,坚持每天阅读其中的电子邮件,以及开发者提交的每一次源代码更新,给Go提交了许多改进意见,甚至包括修改Go语言编译器源代码直接参与开发任务。如此持续了数月时间。
这个到是事实, 在 golang-china 有不少吵架的帖子, 感兴趣的可以去挖下, 我就不展开说了.
到2012年初,Go 1.0发布,语言和标准库都已经基本定型,不可能再有大幅改进,我对Go语言未能在1.0定型之前更上一个台阶、实现自我突破,甚至带着诸多明显缺陷走向1.0,感到非常失望,因而逐渐疏远了它(所以Go 1.0之后的事情我很少关心)。后来看到即将发布的Go 1.1的Release Note,发现语言层面没有太大改变,只是在库和工具层面有所修补和改进,感到它尚在幼年就失去成长的动力,越发失望。外加Go语言社区里的某些人,其中也包括Google公司负责开发Go语言的某些人,其态度、言行,让我极度厌恶,促使我决绝地离弃Go语言。
真的不清楚楼主说的可以在 Go1.0 之前短时间内能实现的 重大改进和诸多明显缺陷 是什么.
如果是楼主说前面的 其语法中的分号和花括号不满 之类的重大改进, 我只能说这只是你的 个人主观感受 而已,
你的很多想法只能说服你自己, 没办法说服其他绝大部分人(不要以为像C++或Rust那样什么特性都有就NB了, 各种NB特性加到一起只能是 要你命3000, 而绝对不会是什么 银弹).
Go 1.1的Release Note,发现语言层面没有太大改变. 语言层没有改变是是因为 Go1 作出的向后兼容的承诺. 对于工业级的语言来说, Go1 这个只能是优点. 如果连语言层在每个版本都会出现诸多大幅改进, 那谁还敢用Go语言来做生产开发呢(我承认Rust的改动很大胆, 但也说明了Rust还处于比较幼稚和任性的阶段)?
说 Go语言社区里的某些人固执 的观点我是同意的. 但是这些 固执 的人是可以讲道理的, 但是他们对很多东西的要求很高(特别是关于Go的设计哲学部分).
只要你给的建议有依据(语言的设计哲学是另外一回事情), 他们绝对不会盲目的拒绝(只是讨论的周期会比较长).
关于楼主提交的给Go文件添加BOM的文章, 需要补充说明下.
在Go1.0发布的时候, Go语言的源文件(.go)明确要求必须是UTF8编码的, 而且是无BOM的UTF8编码的.
注意: 这个 无BOM的UTF8编码 的限制仅仅是 针对 Go语言的源文件(.go).
这个限制并不是说不允许用户处理带BOM的UTF8的txt文件!
我觉得对于写Go程序来说, 这个限制是没有任何问题的, 到目前为止, 我还从来没有使用过带BOM的.go文件.
不仅是因为带BOM的.go文件没有太多的意义, 而且有很多的缺陷.
BOM的原意是用来表示编码是大端还是小端的, 主要用于UTF16和UTF32. 对于 UTF8 来说, BOM 没有任何存在的意义(正是Go的2个作者发明了UTF8, 彻底解决了全球的编码问题).
但是, 在现实中, 因为MS的txt记事本, 对于中文环境会将txt(甚至是C/C++源文件)当作GBK编码(GBK是个烂编码),
为了区别到底是GBK还是UTF8, MS的记事本在前面加了BOM这个垃圾(被GBK占了茅坑), 这里的bom已经不是表示字节序本意了. 不知道有没有人用ms的记事本写网页, 然后生成一个带bom的utf8网页肯定很有意思.
这是MS的记事本的BUG: 它不支持生成无BOM的UTF8编码的文本文件!
这些是现实存在的带BOM的UTF8编码的文本文件, 但是它们肯定都不是Go语言源文件!
所以说, Go语言的源文件即使强制限制了无BOM的UTF8编码要求, 也是没有任何问题的(而且我还希望有这个限制).
虽然后来Go源文件接受带BOM的UTF8了, 但是运行 go fmt 之后, 还是会删除掉BOM的(因为BOM就是然并卵). 也就是说 带 BOM 的 Go 源文件是不符合 Go语言的编码风格的, go fmt 会强制删除 BOM 头.
前面说了BOM是MS带来的垃圾, 但是BOM的UTF8除了然并卵之外还有很多问题, 因为BOM在string的开头嵌入了垃圾,
导致正则表达式, string的链接运算等操作都被会被BOM这个垃圾所污染. 对于.go语言, 即使代码完全一样, 有BOM和无BOM会导致文件的MD5之类的校验码不同.
所以, 我觉得Go用户不用纠结BOM这个无关紧要的东西.
在上一个10年,我(Liigo)在我所属的公司里,深度参与了两个编程语言项目的开发。我想,对于如何判断某个编程语言的优劣,或者说至少对于如何判断某个编程语言是否适合于我自己,我应该还是有一点发言权的。
第1节:我为什么对Go语言不爽?
Go语言有很多让我不爽之处,这里列出我现在还能记起的其中一部分,排名基本上不分先后。读者们耐心地看完之后,还能淡定地说一句“我不在乎”吗?
1.1 不允许左花括号另起一行
关于对花括号的摆放,在C语言、C++、Java、C#等社区中,十余年来存在持续争议,从未形成一致意见。在我看来,这本来就是主观倾向很重的抉择,不违反原则不涉及是非的情况下,不应该搞一刀切,让程序员或团队自己选择就足够了。编程语言本身强行限制,把自己的喜好强加给别人,得不偿失。无论倾向于其中任意一种,必然得罪与其对立的一群人。虽然我现在已经习惯了把左花括号放在行尾,但一想到被禁止其他选择,就感到十分不爽。Go语言这这个问题上,没有做到“团结一切可以团结的力量”不说,还有意给自己树敌,太失败了。
我觉得Go最伟大的发明是 go fmt, 从此Go用户不会再有花括号的位置这种无聊争论了(当然也少了不少灌水和上tiobe排名的机会).
是这优点, Swift 语言也使用和 Go 类似的风格(当然楼主也可能鄙视swift的作者).
1.2 编译器莫名其妙地给行尾加上分号
对Go语言本身而言,行尾的分号是可以省略的。但是在其编译器(gc)的实现中,为了方便编译器开发者,却在词法分析阶段强行添加了行尾的分号,反过来又影响到语言规范,对“怎样添加分号”做出特殊规定。这种变态做法前无古人。在左花括号被意外放到下一行行首的情况下,它自动在上一行行尾添加的分号,会导致莫名其妙的编译错误(Go 1.0之前),连它自己都解释不明白。如果实在处理不好分号,干脆不要省略分号得了;或者,Scala和JavaScript的编译器是开源的,跟它们学学怎么处理省略行尾分号可以吗?
又是楼主的 个人主观感受, 不过我很喜欢这个特性. Swift 语言也是类似.
1.3 极度强调编译速度,不惜放弃本应提供的功能
程序员是人不是神,编码过程中免不了因为大意或疏忽犯一些错。其中有一些,是大家集体性的很容易就中招的错误(Go语言里的例子我暂时想不起来,C++里的例子有“基类析构函数不是虚函数”)。这时候编译器应该站出来,多做一些检查、约束、核对性工作,尽量阻止常规错误的发生,尽量不让有潜在错误的代码编译通过,必要时给出一些警告或提示,让程序员留意。编译器不就是机器么,不就是应该多做脏活累活杂活、减少人的心智负担么?编译器多做一项检查,可能会避免数十万程序员今后多年内无数次犯同样的错误,节省的时间不计其数,这是功德无量的好事。但是Go编译器的作者们可不这么想,他们不愿意自己多花几个小时给编译器增加新功能,觉得那是亏本,反而减慢了编译速度。他们以影响编译速度为由,拒绝了很多对编译器改进的要求。典型的因噎废食。强调编译速度固然值得赞赏,但如果因此放弃应有的功能,我不赞成。
编译速度是很重要的, 如果编译速度够慢, 语言再好也不会有人使用的.
比如C/C++的增量编译/预编译头文件/并发编译都是为了提高编译速度.
Rust1.1 也号称 比 1.0 的编译时间减少了32% (注意: 不是运行速度).
当然, Go刚面世的时候, 编译速度是其中的一个设计目标.
不过我想楼主, 可能想说的是因为编译器自己添加分号而导致的编译错误的问题.
我觉得Go中 { 不能另起一行是语言特性, 如果修复这个就是引入了新的错误.
其他的我真想不起来还有哪些 调编译速度,不惜放弃本应提供的功能 (不要提泛型, 那是因为还没有好的设计).
1.4 错误处理机制太原始
在Go语言中处理错误的基本模式是:函数通常返回多个值,其中最后一个值是error类型,用于表示错误类型极其描述;调用者每次调用完一个函数,都需要检查这个error并进行相应的错误处理:if err != nil { /*这种代码写多了不想吐么*/ }。此模式跟C语言那种很原始的错误处理相比如出一辙,并无实质性改进。实际应用中很容易形成多层嵌套的if else语句,可以想一想这个编码场景:先判断文件是否存在,如果存在则打开文件,如果打开成功则读取文件,如果读取成功再写入一段数据,最后关闭文件,别忘了还要处理每一步骤中出现错误的情况,这代码写出来得有多变态、多丑陋?实践中普遍的做法是,判断操作出错后提前return,以避免多层花括号嵌套,但这么做的后果是,许多错误处理代码被放在前面突出的位置,常规的处理逻辑反而被掩埋到后面去了,代码可读性极差。而且,error对象的标准接口只能返回一个错误文本,有时候调用者为了区分不同的错误类型,甚至需要解析该文本。除此之外,你只能手工强制转换error类型到特定子类型(静态类型的优势没了)。至于panic - recover机制,致命的缺陷是不能跨越库的边界使用,注定是一个半成品,最多只能在自己的pkg里面玩一玩。Java的异常处理虽然也有自身的问题(比如Checked Exceptions),但总体上还是比Go的错误处理高明很多。
话说, 软件开发都发展了半个世纪, 还是无实质性改进. 不要以为弄一个异常的语法糖就是革命了.
我只能说错误和异常是2个不同的东西, 将所有错误当作异常那是SB行为.
正因为有异常这个所谓的银弹, 导致很多等着别人帮忙擦屁股的行为(注意 shit 函数抛出的绝对不会是一种类型的 shit, 而被其间接调用的各种 xxx_shit 也可能抛出各种类型的异常, 这就导致 catch 失控了):
int main() {
try {
shit();
} catch( /* 到底有几千种 shit ? */) {
...
}
}

Go的建议是 panic - recover 不跨越边界, 也就是要求正常的错误要由pkg的处理掉.
这是负责任的行为.
再说Go是面向并发的编程语言, 在海量的 goroutine 中使用 try/catch 是不是有一种不伦不类的感觉呢?
1.5 垃圾回收器(GC)不完善、有重大缺陷
在Go 1.0前夕,其垃圾回收器在32位环境下有内存泄漏,一直拖着不肯改进,这且不说。Go语言垃圾回收器真正致命的缺陷是,会导致整个进程不可预知的间歇性停顿。像某些大型后台服务程序,如游戏服务器、APP容器等,由于占用内存巨大,其内存对象数量极多,GC完成一次回收周期,可能需要数秒甚至更长时间,这段时间内,整个服务进程是阻塞的、停顿的,在外界看来就是服务中断、无响应,再牛逼的并发机制到了这里统统失效。垃圾回收器定期启动,每次启动就导致短暂的服务中断,这样下去,还有人敢用吗?这可是后台服务器进程,是Go语言的重点应用领域。以上现象可不是我假设出来的,而是事实存在的现实问题,受其严重困扰的也不是一家两家了(2013年底ECUG Con 2013,京东的刘奇提到了Go语言的GC、defer、标准库实现是性能杀手,最大的痛苦是GC;美团的沈锋也提到Go语言的GC导致后台服务间隔性停顿是最大的问题。更早的网络游戏仙侠道开发团队也曾受Go垃圾回收的沉重打击)。在实践中,你必须努力减少进程中的对象数量,以便把GC导致的间歇性停顿控制在可接受范围内。除此之外你别无选择(难道你还想自己更换GC算法、甚至砍掉GC?那还是Go语言吗?)。跳出圈外,我近期一直在思考,一定需要垃圾回收器吗?没有垃圾回收器就一定是历史的倒退吗?(可能会新写一篇博客文章专题探讨。)
这是说的是32位系统, 这绝对不是Go语言的重点应用领域!! 我可以说Go出生就是面向64位系统和多核心CPU环境设计的. (再说 Rust 目前好像还不支持 XP 吧, 这可不可以算是影响巨大?)
32位当时是有问题, 但是对实际生产影响并不大(请问楼主还是在用32位系统吗, 还只安装4GB的内存吗). 如果是8位单片机环境, 建议就不要用Go语言了, 直接C语言好了.
而且这个问题早就不存在了(大家可以去看Go的发布日志).
Go的出生也就5年时间, GC的完善和改进是一个持续的工作, 2015年8月将发布的 Go1.5将采用并行GC.
关于GC的被人诟病的地方是会导致卡顿, 但是我以为这个主要是因为GC的实现还不够完美而导致的.
如果是完美的并发和增量的GC, 那应该不会出现大的卡顿问题的.
当然, 如果非要实时性, 那用C好了(实时并不表示性能高, 只是响应时间可控).
对于Rust之类没有GC的语言来说, 想很方便的开发并发的后台程序那几乎是不可能的.
不要总是吹Rust能代替底层/中层/上层的开发, 我们要看有谁用Rust真的做了什么.
1.6 禁止未使用变量和多余import
Go编译器不允许存在被未被使用的变量和多余的import,如果存在,必然导致编译错误。但是现实情况是,在代码编写、重构、调试过程中,例如,临时性的注释掉一行代码,很容易就会导致同时出现未使用的变量和多余的import,直接编译错误了,你必须相应的把变量定义注释掉,再翻页回到文件首部把多余的import也注释掉,……等事情办完了,想把刚才注释的代码找回来,又要好几个麻烦的步骤。还有一个让人蛋疼的问题,编写数据库相关的代码时,如果你import某数据库驱动的pkg,它编译给你报错,说不需要import这个未被使用的pkg;但如果你听信编译器的话删掉该import,编译是通过了,运行时必然报错,说找不到数据库驱动;你看看程序员被折腾的两边不是人,最后不得不请出大神:import _。对待这种问题,一个比较好的解决方案是,视其为编译警告而非编译错误。但是Go语言开发者很固执,不容许这种折中方案。
这个问题我只能说楼主的吐槽真的是没水平.
为何不使用的是错误而不是警告? 这是为了将低级的bug消灭在编译阶段(大家可以想下C/C++的那么多警告有什么卵用).
而且, import 即使没有使用的话, 也是用副作用的, 因为 import 会导致 init 和全局变量的初始化.
如果某些代码没有使用, 为何要执行 init 这些初始化呢?
如果是因为调试而添加的变量, 那么调试完删除不是很正常的要求吗?
如果是因为调试而要导入fmt或log之类的包, 删除调试代码后又导致 import 错误的花,
楼主难道不知道在一个独立的文件包装下类似的辅助调试的函数吗?
import (
"fmt"
"log"
)

func logf(format string, a ...interface{}) {
file, line := callerFileLine()
fmt.Fprintf(os.Stderr, "%s:%d: ", file, line)
fmt.Fprintf(os.Stderr, format, a...)
}

func fatalf(format string, a ...interface{}) {
file, line := callerFileLine()
fmt.Fprintf(os.Stderr, "%s:%d: ", file, line)
fmt.Fprintf(os.Stderr, format, a...)
os.Exit(1)
}

import _ 是有明确行为的用法, 就是为了执行包中的 init 等函数(可以做某些注册操作).
将警告当作错误是Go的一个哲学, 当然在楼主看来这是白痴做法.
1.7 创建对象的方式太多令人纠结
创建对象的方式,调用new函数、调用make函数、调用New方法、使用花括号语法直接初始化结构体,你选哪一种?不好选择,因为没有一个固定的模式。从实践中看,如果要创建一个语言内置类型(如channel、map)的对象,通常用make函数创建;如果要创建标准库或第三方库定义的类型的对象,首先要去文档里找一下有没有New方法,如果有就最好调用New方法创建对象,如果没有New方法,则退而求其次,用初始化结构体的方式创建其对象。这个过程颇为周折,不像C++、Java、C#那样直接new就行了。
C++的new是狗屎. new导致的问题是构造函数和普通函数的行为不一致, 这个补丁特性真的没啥优越的.
我还是喜欢C语言的 fopen 和 malloc 之类构造函数, 构造函数就是普通函数, Go语言中也是这样.
C++中, 除了构造不兼容普通函数, 析构函数也是不兼容普通函数. 这个而引入的坑有很多吧.
1.8 对象没有构造函数和析构函数
没有构造函数还好说,毕竟还有自定义的New方法,大致也算是构造函数了。没有析构函数就比较难受了,没法实现RAII。额外的人工处理资源清理工作,无疑加重了程序员的心智负担。没人性啊,还嫌我们程序员加班还少吗?C++里有析构函数,Java里虽然没有析构函数但是有人家finally语句啊,Go呢,什么都没有。没错,你有个defer,可是那个defer问题更大,详见下文吧。
defer 可以覆盖析构函数的行为, 当然 defer 还有其他的任务. Swift2.0 也引入了一个简化版的 defer 特性.
1.9 defer语句的语义设定不甚合理
Go语言设计defer语句的出发点是好的,把释放资源的“代码”放在靠近创建资源的地方,但把释放资源的“动作”推迟(defer)到函数返回前执行。遗憾的是其执行时机的设置似乎有些不甚合理。设想有一个需要长期运行的函数,其中有无限循环语句,在循环体内不断的创建资源(或分配内存),并用defer语句确保释放。由于函数一直运行没有返回,所有defer语句都得不到执行,循环过程中创建的大量短暂性资源一直积累着,得不到回收。而且,系统为了存储defer列表还要额外占用资源,也是持续增加的。这样下去,过不了多久,整个系统就要因为资源耗尽而崩溃。像这类长期运行的函数,http.ListenAndServe()就是典型的例子。在Go语言重点应用领域,可以说几乎每一个后台服务程序都必然有这么一类函数,往往还都是程序的核心部分。如果程序员不小心在这些函数中使用了defer语句,可以说后患无穷。如果语言设计者把defer的语义设定为在所属代码块结束时(而非函数返回时)执行,是不是更好一点呢?可是Go 1.0早已发布定型,为了保持向后兼容性,已经不可能改变了。小心使用defer语句!一不小心就中招。
前面说到 defer 还有其他的任务, 也就是 defer 中执行的 recover 可以捕获 panic 抛出的异常.
还有 defer 可以在 return 之后修改命名的返回值.
上面2个工作要求 defer 只能在函数退出时来执行.
楼主说的 defer 是类似 Swift2.0 中 defer 的行为, 但是 Swift2.0 中 defer 是没有前面2个特性的.
Go中的defer是以函数作用域作为触发的条件的, 是会导致楼主说的在 for 中执行的错误用法(哪个语言没有坑呢?).
不过 for 中 局部 defer 也是有办法的 (Go中的defer是以函数作用域):
for {
func(){
f, err := os.Open(...)
defer f.Close()
}()
}

在 for 中做一个闭包函数就可以了. 自己不会用不要怪别人没告诉你.
1.10 许多语言内置设施不支持用户定义的类型
for in、make、range、channel、map等都仅支持语言内置类型,不支持用户定义的类型(?)。用户定义的类型没法支持for in循环,用户不能编写像make、range那样“参数类型和个数”甚至“返回值类型和个数”都可变的函数,不能编写像channel、map那样类似泛型的数据类型。语言内置的那些东西,处处充斥着斧凿的痕迹。这体现了语言设计的局限性、封闭性、不完善,可扩展性差,像是新手作品——且不论其设计者和实现者如何权威。延伸阅读:Go语言是30年前的陈旧设计思想,用户定义的东西几乎都是二等公民(Tikhon Jelvis)。
说到底, 这个是因为对泛型支持的不完备导致的.
Go语言是没啥NB的特性, 但是Go的特性和工具组合在一起就是好用.
这就是Go语言NB的地方.
1.11 没有泛型支持,常见数据类型接口丑陋
没有泛型的话,List、Set、Tree这些常见的基础性数据类型的接口就只能很丑陋:放进去的对象是一个具体的类型,取出来之后成了无类型的interface{}(可以视为所有类型的基础类型),还得强制类型转换之后才能继续使用,令人无语。Go语言缺少min、max这类函数,求数值绝对值的函数abs只接收/返回双精度小数类型,排序接口只能借助sort.Interface无奈的回避了被比较对象的类型,等等等等,都是没有泛型导致的结果。没有泛型,接口很难优雅起来。Go开发者没有明确拒绝泛型,只是说还没有找到很好的方法实现泛型(能不能学学已经开源的语言呀)。现实是,Go 1.0已经定型,泛型还没有,那些丑陋的接口为了保持向后兼容必须长期存在着。
Go有自己的哲学, 如果能有和目前哲学不冲突的泛型实现, 他们是不会反对的.
如果只是简单学学(或者叫抄袭)已经开源的语言的语法, 那是C++的设计风格(或者说C++从来都是这样设计的, 有什么特性就抄什么), 导致了各种脑裂的编程风格.
编译时泛型和运行时泛型可能是无法完全兼容的, 看这个例子:
type Adder<T> interface {
Add(a, b T) T
}

Ⅵ 编程语言Python有哪些好的Web框架

Python web五大主流框架:

1.Django

热点内容
云服务器网关系列 发布:2024-11-25 01:00:42 浏览:971
图灵姬编程 发布:2024-11-25 00:52:40 浏览:314
编译好的程序不闪一下就没了 发布:2024-11-25 00:48:51 浏览:549
ts设置编译输出目录 发布:2024-11-25 00:43:28 浏览:448
元神比较好的云服务器 发布:2024-11-25 00:43:20 浏览:190
草人御魂怎么配置 发布:2024-11-25 00:30:37 浏览:738
ftp上传流程 发布:2024-11-25 00:18:27 浏览:90
安卓服光遇什么时候上线的 发布:2024-11-25 00:13:22 浏览:919
80万能买到酷路泽的什么配置 发布:2024-11-25 00:10:57 浏览:337
新浪微博中如何修改密码 发布:2024-11-25 00:10:52 浏览:101