Python关键字yield的解释

提问者的问题​ Python关键字yield的作用是什么?用来干什么的? 比如,我正在试图理解下面的代码:def node._get_child_candidates(self, distance, min_dist, max_dist): if ...
继续阅读 »


提问者的问题​


Python关键字yield的作用是什么?用来干什么的?
比如,我正在试图理解下面的代码:
def node._get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
下面的是调用:
result, candidates = list(), [self]
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
当调用 _get_child_candidates 的时候发生了什么?返回了一个链表?返回了一个元素?被重复调用了么? 什么时候这个调用结束呢?


回答部分


为了理解什么是 yield,你必须理解什么是生成器。在理解生成器之前,让我们先走近迭代。


可迭代对象


当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象:
>>> mylist = [1, 2, 3]
[quote]>> for i in mylist :
... print(i)
1
2
3
mylist 是一个可迭代的对象。当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代的对象:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist :
... print(i)
0
1
4
所有你可以使用 for .. in .. 语法的叫做一个迭代器:链表,字符串,文件……你经常使用它们是因为你可以如你所愿的读取其中的元素,但是你把所有的值都存储到了内存中,如果你有大量数据的话这个方式并不是你想要的。


生成器


生成器是可以迭代的,但是你 只可以读取它一次 ,因为它并不把所有的值放在内存中,它是实时地生成数据:
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator :
... print(i)
0
1
4
看起来除了把  换成 () 外没什么不同。但是,你不可以再次使用 for i inmygenerator , 因为生成器只能被迭代一次:先计算出0,然后继续计算1,然后计算4,一个跟一个的…


yield关键字


yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器。
>>> def createGenerator() :
... mylist = range(3)
... for i in mylist :
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!

>>> for i in mygenerator:
... print(i)
0
1
4
这个例子没什么用途,但是它让你知道,这个函数会返回一大批你只需要读一次的值.
 
为了精通 yield ,你必须要理解:当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象,这有点蹊跷不是吗。
 
那么,函数内的代码什么时候执行呢?当你使用for进行迭代的时候.
 
现在到了关键点了!
 
第一次迭代中你的函数会执行,从开始到达 yield 关键字,然后返回 yield 后的值作为第一次迭代的返回值. 然后,每次执行这个函数都会继续执行你在函数内部定义的那个循环的下一次,再返回那个值,直到没有可以返回的。
 
如果生成器内部没有定义 yield 关键字,那么这个生成器被认为成空的。这种情况可能因为是循环进行没了,或者是没有满足 if/else 条件。


回到你的代码


(译者注:这是回答者对问题的具体解释)
生成器:
# Here you create the method of the node object that will return the generator
def node._get_child_candidates(self, distance, min_dist, max_dist):[/quote]

# Here is the code that will be called each time you use the generator object :

# If there is still a child of the node object on its left
# AND if distance is ok, return the next child
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild

# If there is still a child of the node object on its right
# AND if distance is ok, return the next child
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild

# If the function arrives here, the generator will be considered empty
# there is no more than two values : the left and the right children
调用者:
# Create an empty list and a list with the current object reference
result, candidates = list(), [self]

# Loop on candidates (they contain only one element at the beginning)
while candidates:

# Get the last candidate and remove it from the list
node = candidates.pop()

# Get the distance between obj and the candidate
distance = node._get_dist(obj)

# If distance is ok, then you can fill the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)

# Add the children of the candidate in the candidates list
# so the loop will keep running until it will have looked
# at all the children of the children of the children, etc. of the candidate
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

return result
这个代码包含了几个小部分:
    []我们对一个链表进行迭代,但是迭代中链表还在不断的扩展。它是一个迭代这些嵌套的数据的简洁方式,即使这样有点危险,因为可能导致无限迭代。candidates.extend(node._get_child_candidates(distance, min_dist,max_dist)) 穷尽了生成器的所有值,但 while 不断地在产生新的生成器,它们会产生和上一次不一样的值,既然没有作用到同一个节点上.[/][]extend() 是一个迭代器方法,作用于迭代器,并把参数追加到迭代器的后面。[/]
通常我们传给它一个链表参数:
>>> a = [1, 2][quote]>> b = [3, 4]>>> a.extend(b)>>> print(a)[1, 2, 3, 4]
但是在你的代码中的是一个生成器,这是不错的,因为:
    []你不必读两次所有的值[/][]你可以有很多子对象,但不必叫他们都存储在内存里面。[/]

并且这很奏效,因为Python不关心一个方法的参数是不是个链表。Python只希望它是个可以迭代的,所以这个参数可以是链表,元组,字符串,生成器... 这叫做 ducktyping,这也是为何Python如此棒的原因之一,但这已经是另外一个问题了...
 
你可以在这里停下,来看看生成器的一些高级用法


控制生成器的穷尽


>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # crisis is coming, no more money!
>>> print(corner_street_atm.next())

>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
>>> print(wall_street_atm.next())

>>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())

>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> for cash in brand_new_atm :
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
对于控制一些资源的访问来说这很有用。


Itertools,你最好的朋友


itertools包含了很多特殊的迭代方法。是不是曾想过复制一个迭代器?串联两个迭代器?把嵌套的链表分组?不用创造一个新的链表的 zip/map?[/quote]

只要 import itertools

需要个例子?让我们看看比赛中4匹马可能到达终点的先后顺序的可能情况:
>>> horses = [1, 2, 3, 4]
[quote]>> races = itertools.permutations(horses)
>>> print(races)

>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]


了解迭代器的内部机理


迭代是一个实现可迭代对象(实现的是 __iter__() 方法)和迭代器(实现的是__next__() 方法)的过程。可迭代对象是你可以从其获取到一个迭代器的任一对象。迭代器是那些允许你迭代可迭代对象的对象。
更多见这个文章: http://effbot.org/zone/python-for-statement.htm
翻译编辑原文:http://pyzh.readthedocs.org/en/latest/the-python-yield-keyword-explained.html[/quote] 收起阅读 »

mac 终端python tab键自动补全(亲测可以)

#!/usr/bin/env python # encoding: utf-8 import readline,rlcompleter [size=16]# Indenting [/size] class TabCompleter(rlcompl...
继续阅读 »
#!/usr/bin/env python
# encoding: utf-8

import readline,rlcompleter

[size=16]# Indenting
[/size]
class TabCompleter(rlcompleter.Completer):
"""Completer that supports indenting"""
def complete(self, text, state):
if not text:
return (' ', None)[state]
else:
return rlcompleter.Completer.complete(self, text, state)

readline.set_completer(TabCompleter().complete)

[size=16]# Add autocompletion
[/size]
if 'libedit' in readline.__doc__:
readline.parse_and_bind("bind -e")
readline.parse_and_bind("bind '\t' rl_complete")
else:
readline.parse_and_bind("tab: complete")

[size=16]# Add history
[/size]
import os
histfile = os.path.join(os.environ["HOME"], ".pyhist")
try:
readline.read_history_file(histfile)
except IOError:
pass
import atexit
atexit.register(readline.write_history_file, histfile)
del histfile
pythontab.png
收起阅读 »

学习python的几个好习惯

随着Python在国内的发展,特别是在自动化运维领域,运维开发者99%使用python开发自动化运维平台;在软件行业里面使用python编程语言的公司会越来越多,那么在学习Python的过程中需要养成几个好习惯。下面我给大家分享几条: 缩进 由于跟其他编程...
继续阅读 »
随着Python在国内的发展,特别是在自动化运维领域,运维开发者99%使用python开发自动化运维平台;在软件行业里面使用python编程语言的公司会越来越多,那么在学习Python的过程中需要养成几个好习惯。
下面我给大家分享几条:


缩进


由于跟其他编程语言的区别性,缩进在python编程中显得十分重要;在Python的代码块中必须使用相同数目的行首缩进空格数,否则会造成脚本运行错误,提示你格式不正确之类的信息。因此,在使用python语言写脚本的时候,保证缩进的一致性相当重要。
sj.jpg


空格


虽然在python编程过程中,空行并不是Python语法的必需部分,但是,保持函数之间或类的方法之间用空行分隔,可以使得代码看起来更加清晰明了,也有利于后期的代码维护或重构。

kge.jpg


注释


注释相对经常使用编程语言的人来说应该不是很陌生吧,主要因为注释不仅使得阅读代码的人容易理解,也让代码作者更好地定位代码函数等。python跟其它语言一样,注释在一些该注释的地方,可以让效率事半功倍。
zs.jpg


源代码


python作为完全开源的语言,代码对于任何人都可以随意浏览。这种方式可以更好地帮助人们发现有利精简扼要的代码,在很多方面可以省去不必要的时间,因为觉得合适可以直接拿过来使用或者简单修改。经常看一下好的源代码,不仅会让你学习别人的编程方式,还在另一方面大大的帮助你更好地学习。


编程思想


使用任何一门编程语言,都需要保持很好的编程思想,对python来说也是一样的。学会创造使用适合自己的编程思想是至关重要的,因此,去多读一些讲解编程思想之类的书籍来充实自己吧。
bcsx.png


多实践


学习任何一门编程语言都需要多做多写多看,通过不同的项目,来让自己得到更好的锻炼,相信是一件很棒的事情。在业余时间,经常的去敲写一些代码,也是很有意思的。
jdit.png


兴趣


兴趣是成功的一半,兴趣促使你更好地去使用学习编程语言,而不单单为了忙碌的工作。很多创造出编程语言的人来说,正时因为兴趣的使然,才成就了如此好的一些编程语言。
xq.png
收起阅读 »

Python单行函数lambda(小米)加reduce、map、filter(步枪)应用

什么是lambda?lambda定义匿名函数,并不会带来程序运行效率的提高,只会使代码更简洁。为了减少单行函数的定义而存在的。lambda的使用大量简化了代码,使代码简练清晰。但是值得注意的是,这会在一定程度上降低代码的可读性。如果不是非常熟悉Python的人...
继续阅读 »
什么是lambda?
lambda定义匿名函数,并不会带来程序运行效率的提高,只会使代码更简洁。为了减少单行函数的定义而存在的。
lambda的使用大量简化了代码,使代码简练清晰。但是值得注意的是,这会在一定程度上降低代码的可读性。如果不是非常熟悉Python的人也许会对此很难理解。
如果可以使用for...in...if来完成的,坚决不用lambda。
如果使用lambda,lambda内不要包含循环,如果有,宁愿定义函数来完成,使代码获得可重用性和更好的可读性。如果你对你就喜欢用lambda来做,那也无可厚非,但是有内置函数减弱了代码的可读性!
好了介绍完成了lambda,那就让我们来实际用一下,实例如下:
lambda.png

 
下面我们再来看看小米加上步枪的结合使用。
1、reduce + lambda
What is reduce?
Python中的reduce内建函数是一个二元操作函数,他用来将一个数据集合(列表,元组等)中的所有数据进行如下操作:传给reduce中的函数func() (必须是一个二元操作函数)先对集合中的第1,2个数据进行操作,得到的结果再与第三个数据用func()函数运算,最后得到一个结果。
关于python reduce的详细解析,后续详细介绍,下面我们介绍一下reduce + lambda的应用案例:
reduce.png

 
2、map + lambda
What is map?
map函数应用于每一个可迭代的项,返回的是一个结果list。如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理。map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回。
格式:map(func, seq1[, seq2...] )
Python函数式编程中的map()函数是将func作用于seq中的每一个元素,并用一个列表给出返回值。如果func为None,作用同zip()。

详细应用code如下:
imap.png


这里需要注意的是:升级到python3的时候,map函数有一个变化那就是,如果不在map前加上list,lambda函数根本就不会执行。


在python2中,map会直接返回结果:
py2.png

而再python3下面,返回的就是一个map对象:
如果要得到结果,必须用list作用于这个map对象。
 
3、filter + map
What is filter?
filter()函数可以对序列做过滤处理,就是说可以使用一个自定的函数过滤一个序列,把序列的每一项传到自定义的过滤函数里处理,并返回结果做过滤。最终一次性返回过滤后的结果。
和map()类似,filter()也接收一个函数和一个序列。和map()不同的时,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

简单应用如下:
filter.png

这里简单介绍一下python内置函数小米加步枪,更详细的介绍再会,打完收工! 收起阅读 »

Hbase的Python API模块Starbase介绍

The following guest post is provided by Artur Barseghyan, a web developer currently employed by Goldmund, Wyldebeast & Wunderliebe...
继续阅读 »
The following guest post is provided by Artur Barseghyan, a web developer currently employed by Goldmund, Wyldebeast & Wunderliebe in The Netherlands.

Python is my personal (and primary) programming language of choice and also happens to be the primary programming language at my company. So, when starting to work with a new technology, I prefer to use a clean and easy (Pythonic!) API.

After studying tons of articles on the web, reading (and writing) white papers, and doing basic performance tests (sometimes hard if you’re on a tight schedule), my company recently selected Cloudera for our Big Data platform (including using Apache HBase as our data store for Apache Hadoop), with Cloudera Manager serving a role as “one console to rule them all.”

However, I was surprised shortly thereafter to learn about the absence of a working Python wrapper around the REST API for HBase (aka Stargate). I decided to write one in my free time, and the result, ladies and gentlemen, wasStarbase (GPL).

In this post, I will provide some code samples and briefly explain what work has been done on Starbase. I assume that reader of this blog post already has some basic understanding of HBase (that is, of tables, column families, qualifiers, and so on).


一、安装


Next, I’ll show you some frequently used commands and use cases. But first, install the current version of Starbase from CheeseShop (PyPi).
# pip install starbase
导入模块:
>>> from starbase import Connection
…and create a connection instance. Starbase defaults to 127.0.0.1:8000; if your settings are different, specify them here.
>>> c = Connection()


二、API 操作实例


2.1 显示所有的表
假设有两个现有的表名为table1和table2表,以下将会打印出来。
>>> c.tables()
['table1', 'table2']
2.2 表的设计操作
每当你需要操作的表,你需要先创建一个表的实例。
创建一个表实例(注意,在这一步骤中没有创建表):
>>> t = c.table('table3')
Create a new table:
Create a table with columns ‘column1′, ‘column2′, ‘column3′ (here the table is actually created):
>>> t.create('column1', 'column2', 'column3')
201
检查表是否存在:
>>> t.exists()
True
查看表的列:
>>> t.columns()
['column1', 'column2', 'column3']
将列添加到表,(‘column4’,‘column5’,‘column6’,‘column7’):
>>> t.add_columns('column4', 'column5', 'column6', 'column7')
200
删除列表,(‘column6’, ‘column7’):
>>> t.drop_columns('column6', 'column7')
201
删除整个表:
>>> t.drop()
200
2.3 表的数据操作
将数据插入一行:
>>> t.insert(
[quote]>> 'my-key-1',
>>> {
>>> 'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
>>> 'column2': {'key21': 'value 21', 'key22': 'value 22'},
>>> 'column3': {'key32': 'value 31', 'key32': 'value 32'}
>>> }
>>> )
200
请注意,您也可以使用“本地”的命名方式列和细胞(限定词)。以下的结果等于前面的例子的结果。
>>> t.insert(
>>> 'my-key-1a',
>>> {
>>> 'column1:key11': 'value 11', 'column1:key12': 'value 12', 'column1:key13': 'value 13',
>>> 'column2:key21': 'value 21', 'column2:key22': 'value 22',
>>> 'column3:key32': 'value 31', 'column3:key32': 'value 32'
>>> }
>>> )
200
更新一排数据:
>>> t.update(
>>> 'my-key-1',
>>> {'column4': {'key41': 'value 41', 'key42': 'value 42'}}
>>> )
200
Remove a row cell (qualifier):
>>> t.remove('my-key-1', 'column4', 'key41')
200
Remove a row column (column family):
>>> t.remove('my-key-1', 'column4')
200
Remove an entire row:
>>> t.remove('my-key-1')
200
Fetch a single row with all columns:
>>> t.fetch('my-key-1')
{
'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
'column2': {'key21': 'value 21', 'key22': 'value 22'},
'column3': {'key32': 'value 31', 'key32': 'value 32'}
}
Fetch a single row with selected columns (limit to ‘column1′ and ‘column2′ columns):
>>> t.fetch('my-key-1', ['column1', 'column2'])
{
'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
'column2': {'key21': 'value 21', 'key22': 'value 22'},
}
Narrow the result set even more (limit to cells ‘key1′ and ‘key2′ of column `column1` and cell ‘key32′ of column ‘column3′):
>>> t.fetch('my-key-1', {'column1': ['key11', 'key13'], 'column3': ['key32']})
{
'column1': {'key11': 'value 11', 'key13': 'value 13'},
'column3': {'key32': 'value 32'}
}
Note that you may also use the native means of naming the columns and cells (qualifiers). The example below does exactly the same thing as the example above.
>>>  t.fetch('my-key-1', ['column1:key11', 'column1:key13', 'column3:key32'])
{
'column1': {'key11': 'value 11', 'key13': 'value 13'},
'column3': {'key32': 'value 32'}
}
If you set the perfect_dict argument to False, you’ll get the native data structure:
>>>  t.fetch('my-key-1', ['column1:key11', 'column1:key13', 'column3:key32'], perfect_dict=False)
{
'column1:key11': 'value 11', 'column1:key13': 'value 13',
'column3:key32': 'value 32'
}
2.4 对表数据批处理操作
Batch operations (insert and update) work similarly to routine insert and update, but are done in a batch. You are advised to operate in batch as much as possible.[/quote]

In the example below, we will insert 5,000 records in a batch:  
>>> data = {
[quote]>> 'column1': {'key11': 'value 11', 'key12': 'value 12', 'key13': 'value 13'},
>>> 'column2': {'key21': 'value 21', 'key22': 'value 22'},
>>> }
>>> b = t.batch()
>>> for i in range(0, 5000):
>>> b.insert('my-key-%s' % i, data)
>>> b.commit(finalize=True)
{'method': 'PUT', 'response': [200], 'url': 'table3/bXkta2V5LTA='}
In the example below, we will update 5,000 records in a batch:
>>> data = {
>>> 'column3': {'key31': 'value 31', 'key32': 'value 32'},
>>> }
>>> b = t.batch()
>>> for i in range(0, 5000):
>>> b.update('my-key-%s' % i, data)
>>> b.commit(finalize=True)
{'method': 'POST', 'response': [200], 'url': 'table3/bXkta2V5LTA='}
Note: The table batch method accepts an optional size argument (int). If set, an auto-commit is fired each the time the stack is full.
2.5 表数据搜索(行扫描)
A table scanning feature is in development. At the moment it’s only possible to fetch all rows from a table. The result set returned is a generator.[/quote]

注意:表数据扫描功能正在开发中。目前仅支持取出表中所有数据(Full Table Scan),暂不支持范围扫描(RowKey Range Scan),其结果以一个迭代器形式返回。
>>> t.fetch_all_rows()
就介绍到这里了,没有时间翻译,聽简单的英文! 收起阅读 »

Python访问hbase数据操作脚本分享

#!/usr/bin/python import getopt,sys,time from thrift.transport.TSocket import TSocket from thrift.transport.TTransport import TB...
继续阅读 »
#!/usr/bin/python

import getopt,sys,time
from thrift.transport.TSocket import TSocket
from thrift.transport.TTransport import TBufferedTransport
from thrift.protocol import TBinaryProtocol
from hbase import Hbase

def usage():
print '''Usage :
-h: Show help information;
-l: Show all table in hbase;
-t {table} Show table descriptors;
-t {table} -k {key} : show cell;
-t {table} -k {key} -c {coulmn} : Show the coulmn;
-t {table} -k {key} -c {coulmn} -v {versions} : Show more version;
(write by liuhuorong@koudai.com)
'''

class geilihbase:
def __init__(self):
self.transport = TBufferedTransport(TSocket("127.0.0.1", "9090"))
self.transport.open()
self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
self.client = Hbase.Client(self.protocol)
def __del__(self):
self.transport.close()
def glisttable(self):
for table in self.client.getTableNames():
print table
def ggetColumnDescriptors(self,table):
rarr=self.client.getColumnDescriptors(table)
if rarr:
for (k,v) in rarr.items():
print "%-20s\t%s" % (k,v)
def gget(self,table,key,coulmn):
rarr=self.client.get(table,key,coulmn)
if rarr:
print "%-15s %-20s\t%s" % (rarr[0].timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(rarr[0].timestamp/1000)),rarr[0].value)
def ggetrow(self,table,key):
rarr=self.client.getRow(table, key)
if rarr:
for (k,v) in rarr[0].columns.items():
print "%-20s\t%-15s %-20s\t%s" % (k,v.timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(v.timestamp/1000)),v.value)
def ggetver(self, table, key, coulmn, versions):
rarr=self.client.getVer(table,key,coulmn, versions);
if rarr:
for row in rarr:
print "%-15s %-20s\t%s" % (row.timestamp,time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(row.timestamp/1000)),row.value)

def main(argv):
tablename=""
key=""
coulmn=""
versions=""
try:
opts, args = getopt.getopt(argv, "lht:k:c:v:", ["help","list"])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit(0)
elif opt in ("-l", "--list"):
ghbase=geilihbase()
ghbase.glisttable()
sys.exit(0)
elif opt == '-t':
tablename = arg
elif opt == '-k':
key = arg
elif opt == '-c':
coulmn = arg
elif opt == '-v':
versions = int(arg)
if ( tablename and key and coulmn and versions ):
ghbase=geilihbase()
ghbase.ggetver(tablename, key, coulmn, versions)
sys.exit(0)
if (tablename and key and coulmn ):
ghbase=geilihbase()
ghbase.gget(tablename, key, coulmn)
sys.exit(0)
if (tablename and key ):
ghbase=geilihbase()
ghbase.ggetrow(tablename, key)
sys.exit(0)
if (tablename ):
ghbase=geilihbase()
ghbase.ggetColumnDescriptors(tablename)
sys.exit(0)
usage()
sys.exit(1)

if __name__ == "__main__":
main(sys.argv[1:])
收起阅读 »

JAVA日志那点事

前言 日志这东西在语言里算基础组件了吧,可惜Java界第三方框架向来比原生组件好用也是事实,缺点是框架太多混战江湖,今天我们就理一理这些日志框架。Java的日志框架分为门面(Facade),或者叫通用日志接口,还有日志实现。日志接口不用说,就是定下的日志方...
继续阅读 »


前言


日志这东西在语言里算基础组件了吧,可惜Java界第三方框架向来比原生组件好用也是事实,缺点是框架太多混战江湖,今天我们就理一理这些日志框架。Java的日志框架分为门面(Facade),或者叫通用日志接口,还有日志实现。日志接口不用说,就是定下的日志方法规范,需要具体日志组件去实现的(为啥Sun当年没有定义这东西,看看JPA、JDBC、JMS这些规范定义的多好,或者定义了被抛弃了?)。日志实现就是具体的日志组件了,可以实现日志打印到控制台、文件、数据库等等。下面咱们就具体说说这些东西。


Java日志框架分类


日志门面(Facade)
    []Slf4j[/]
全称Simple Logging Facade for JAVA,真正的日志门面,只提供接口方法,当配合特定的日志实现时,需要引入相应的桥接包
    []Common-logging[/]
Apache提供的一个通用的日志接口,common-logging会通过动态查找的机制,在程序运行时自动找出真正使用的日志库,自己也自带一个功能很弱的日志实现。
差别:[list=1][]Common-logging动态查找日志实现(程序运行时找出日志实现),Slf4j则是静态绑定(编译时找到实现),动态绑定因为依赖ClassLoader寻找和载入日志实现,因此类似于OSGI那种使用独立ClassLoader就会造成无法使用的情况。(呵呵,我一个插件用一个日志框架不行啊,土豪多任性,不过说实话,没用过OSGI,这个我还真没有概念)[/][]Slf4j支持参数化的log字符串,避免了之前为了减少字符串拼接的性能损耗而不得不写的if(logger.isDebugEnable()),现在你可以直接写:logger.debug(“current user is: {}”, user)。[/]日志实现
    []Log4j[/]
Log4j可能是Java世界里最出名的日志框架了,支持各种目的地各种级别的日志输出,从我刚接触日志就知道这个框架(呵呵,我一直不知道还有JDK Logging这个东西)。最近(也不近了……)Log4j2发布正式版了,没看到谁用,听说也很不错。
    []LogBack[/]
Log4j作者的又一力作(听说是受不了收费文档搞了个开源的,不需要桥接包完美适配Slf4j),个人感觉迄今为止最棒的日志框架了,一直都在用,配置文件够简洁,性能足够好(估计是看自己的Log4j代码差劲了,更新不能解决问题,直接重构了)。
    []JDK Logging 从JDK1.4开始引入,不得不说,你去Google下这个JDK自带的日志组件,并不如Log4j和LogBack之类好用,木有配置文件,日志级别不好理解,想顺心的用估计还得自己封装下,总之大家已经被Log4j惯坏了,JDK的设计并不能被大家认同,唯一的优点我想就是不用引入新额jar包了。[/]


为什么会有门面


看了以上介绍,如果你不是混迹(深陷)Java多年的老手,估计会蒙圈儿了吧,那你肯定会问,要门面干嘛。有了手机就有手机壳、手机膜,框架也一样,门面的作用更多的还是三个字:解耦合。说白了,加入一个项目用了一个日志框架,想换咋整啊?那就一行一行的找日志改呗,想想都是噩梦。于是,门面出来了,门面说啦, 你用我的格式写日志,把日志想写哪儿写哪儿,例如Slf4j-api加上后,想换日志框架,直接把桥接包一换就行。方便极了。
说实话,现在Slf4j基本可以是Java日志的一个标准了,按照它写基本可以实现所有日志实现通吃,但是就有人不服,还写了门面的门面(没错,这个人就是我)。


门面的门面


如果你看过Netty的源码,推荐你看下io.netty.util.internal.logging这个包里内容,会发现Netty又对日志封装了一层,于是灵感来源于此,我也对各大日志框架和门面做了封装。


Hutool-log模块


无论是Netty的日志模块还是我的Hutool-log模块,思想类似于Common Logging,做动态日志实现查找,然后找到相应的日志实现来写入日志,核心代码如下:
/**
* 决定日志实现
* @return 日志实现类
*/
public static Class detectLog(){
List> logClassList = Arrays.asList(
Slf4jLog.class,
Log4jLog.class,
Log4j2Log.class,
ApacheCommonsLog.class,
JdkLog.class
);
for (Class clazz : logClassList) {
try {
clazz.getConstructor(Class.class).newInstance(LogFactory.class).info("Use Log Framework: [{}]", clazz.getSimpleName());
return clazz;
} catch (Error | Exception e) {
continue;
}
}
return JdkLog.class;
}
详细代码可以看这里
说白了非常简单,按顺序实例化相应的日志实现,如果实例化失败(一般是ClassNotFoundException),说明jar不存在,那实例化下一个,通过不停的尝试,最终如果没有引入日志框架,那使用JDK Logging(这个肯定会有的),当然这种方式也和Common-logging存在类似问题,不过不用到跨ClassLoader还是很好用的。
对于JDK Logging,我也做了一些适配,使之可以与Slf4j的日志级别做对应,这样就将各个日志框架差异化降到最小。另一方面,如果你看过我的这篇日志,那你一定了解了我的类名自动识别功能,这样大家在复制类名的时候,就不用修改日志的那一行代码了,在所有类中,日志的初始化只有这一句:
Log log = LogFactory.get();
是不是简洁简洁又简洁?实现方式也很简单:
/**
* @return 获得调用者的日志
*/
public static Log get() {
return getLog(new Exception().getStackTrace()[1].getClassName());
}
通过堆栈引用获得当前类名。
 
作为一个强迫症患者,日志接口我也会定义的非常处女座:
/**
* 日志统一接口
*
* @author Looly
*
*/
public interface Log extends TraceLog, DebugLog, InfoLog, WarnLog, ErrorLog
这样就实现了单一使用,各个日志框架灵活引用的作用了。


分享阅读原文:http://www.xiaoleilu.com/some-thing-about-java-log/


收起阅读 »

IOS崩溃命令行工具atosl安装记录

IOS
Centos安装1、安装依赖包libdwarf、binutils-devel、lasso、tbb yum -y install libdwarf-devel libdwarf-tools binutils-devel lasso libdwarf lasso-...
继续阅读 »

Centos安装

1、安装依赖包libdwarf、binutils-devel、lasso、tbb


yum -y install libdwarf-devel libdwarf-tools binutils-devel lasso libdwarf lasso-python libdwarf-tools libdwarf-static tbb

2、创建libdwarf.h软连接


ln -s /usr/include/libdwarf/libdwarf.h /usr/include/libdwarf.h

ln -s /usr/include/libdwarf/dwarf.h /usr/include/dwarf.h

3、获取atosl源码


cd /usr/local/ && git clone https://github.com/facebook/atosl.git

4、安装atosl


cd atosl  #进入源码目录
echo "LDFLAGS += -L/usr/bin" > ./config.mk.local #添加objdump环境目录
make #编译安装

5、测试命令


默认安装完成后,命令是在你源码包路径下
Example:/usr/local/atosl是我源码存储目录,那安装完成后命令路径为/usr/local/atosl/atosl
所以需要做个软连接让环境变量中可以查到:
# ln -s /usr/local/atosl/atosl /usr/bin/atosl

命令结果如下:

Ubuntu安装

1、安装libdwarf-dev、 dwarfdump、binutils-dev 、libiberty-dev软件包


$ sudo apt-get install libdwarf-dev dwarfdump binutils-dev libiberty-dev

2、从github克隆下载atosl源码


$ git clone https://github.com/facebook/atosl.git

3、进入源码目录安装


$ cd atosl

Create a local config config.mk.local which contains a flag with the location of your binutil apps. (in Ubuntu by default that's /usr/bin). If you're not sure, you can find out by executing cat /var/lib/dpkg/info/binutils.list | less and copy the path of the file objdump. E.g. if the entry is /usr/bin/objdump, your path is /usr/bin.

So in the end, your config.mk.local should look like this:

$ echo "LDFLAGS += -L/usr/bin" > ./config.mk.local
$ make

4、测试命令

参考:



https://github.com/facebook/hhvm/issues/536
https://github.com/facebook/hhvm/wiki/Building-and-installing-HHVM-on-CentOS-6.3
http://stackoverflow.com/questions/15070680/ios-symbolication-server-side


收起阅读 »

编程语言之争—PHP VS RUBY VS PYTHON

正如世界上的语言有多种多样,编程语言同样如此,有些更受欢迎,有些简单易用。随着编 程语言的种类越来越多,它们之间的竞争也日益激烈。而且往往简单的、运行速度快的编程语言并非就是最好的选择,因为不同的程序员对编程语言的选择很有讲究,而且能讲出一大堆道理...
继续阅读 »
difference3.png

正如世界上的语言有多种多样,编程语言同样如此,有些更受欢迎,有些简单易用。随着编 程语言的种类越来越多,它们之间的竞争也日益激烈。而且往往简单的、运行速度快的编程语言并非就是最好的选择,因为不同的程序员对编程语言的选择很有讲究,而且能讲出一大堆道理来解释为什么喜欢某种编程语言 ,不过他们的给出的理由一般都带有太多个人的经历和情感因素。

下面的图表站在客观的立 场,从各个角度对PHP、Ruby、Python三种当前比较流行的语言的优势和劣势进行了对比:Ruby编写的代码精确、强大、表达性好,可用性最高;Python语法简单,最适合初学者学习,也是讨论最为热门的语言;PHP在三者中的流行程度最高;代码效率方面,代码行数PHP表现最好,运行时间上Python最短......,就如下图所示:
phpvpythonvruby.jpg

更过精彩分析,可以到Youtube观看视频:https://www.youtube.com/watch?v=VBm5m1-Eonw​  收起阅读 »

Python模拟P2P大文件传输

一、需求及应用场景 考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者s...
继续阅读 »


一、需求及应用场景


考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能做到一个点往下分发这个文件,这个时候下发的速度就会比较的慢,基于以上原因,我写了一个基于bt协议传输文件的小工具,实际测试,传输到10个机房,70多台机器传输一个240M的这个内核文件,到所有的机器,源采用限速2m/s的上传速度,测试的结果大概只要140s,就可以全部传输完毕,这个效率是非常之高,如果不限速的情况下速度会更快,下面把这个程序开源出来。


二、代码


#!/usr/bin/env python
import libtorrent as lt
import sys
import os
import time
from optparse import OptionParser
import socket
import struct
import fcntl
def get_interface_ip(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s',
ifname[:15]))[20:24])
def ip2long(ip):
return reduce(lambda a,b:(a<<8)+b,[int(i) for i in ip.split('.')])
def get_wan_ip_address():
interfaces = set(['eth0', 'eth1', 'eth2', 'eth3', 'em1', 'em2', 'em3', 'em4'])
ip = ''
for i in interfaces:
try:
ip = get_interface_ip(i)
if (ip2long(ip) < ip2long('10.0.0.0') or ip2long(ip) > ip2long('10.255.255.255')) \
and (ip2long(ip) < ip2long('172.16.0.0') or ip2long(ip) > ip2long('172.33.255.255')) \
and (ip2long(ip) < ip2long('192.168.0.0') or ip2long(ip) > ip2long('192.168.255.255')):
return ip
except:
pass
return ip
def make_torrent(path, save):
fs = lt.file_storage()
lt.add_files(fs, path)
if fs.num_files() == 0:
print 'no files added'
sys.exit(1)
input = os.path.abspath(path)
basename = os.path.basename(path)
t = lt.create_torrent(fs, 0, 4 [i] 1024 [/i] 1024)
t.add_tracker("http://10.0.1.5:8760/announce")
t.set_creator('libtorrent %s' % lt.version)
lt.set_piece_hashes(t, os.path.split(input)[0], lambda x: sys.stderr.write('.'))
sys.stderr.write('\n')
save = os.path.dirname(input)
save = "%s/%s.torrent" % (save, basename)
f=open(save, "wb")
f.write(lt.bencode(t.generate()))
f.close()
print "the bt torrent file is store at %s" % save
def dl_status(handle):
while not (handle.is_seed()):
s = handle.status()
state_str = ['queued', 'checking', 'downloading metadata', \
'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
print '\ractive_time: %d, %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d, seeds: %d) %s' % \
(s.active_time, s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \
s.num_peers, s.num_seeds, state_str[s.state]),
sys.stdout.flush()
time.sleep(1)
def seed_status(handle, seedtime=100):
seedtime = int(seedtime)
if seedtime < 100:
seedtime = 100
while seedtime > 0:
seedtime -= 1
s = handle.status()
state_str = ['queued', 'checking', 'downloading metadata', \
'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
print '\rseed_time: %d, %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d, seeds: %d) %s' % \
(s.active_time, s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \
s.num_peers, s.num_seeds, state_str[s.state]),
sys.stdout.flush()
time.sleep(1)
def remove_torrents(torrent, session):
session.remove_torrent(torrent)
def read_alerts(session):
alert = session.pop_alert()
while alert:
#print alert, alert.message()
alert = session.pop_alert()
def download(torrent, path, upload_rate_limit=0, seedtime=100):
try:
session = lt.session()
session.set_alert_queue_size_limit(1024 * 1024)
sts = lt.session_settings()
sts.ssl_listen = False
sts.user_agent = "Thunder deploy system"
sts.tracker_completion_timeout = 5
sts.tracker_receive_timeout = 5
sts.stop_tracker_timeout = 5
sts.active_downloads = -1
sts.active_seeds = -1
sts.active_limit = -1
sts.auto_scrape_min_interval = 5
sts.udp_tracker_token_expiry = 120
sts.min_announce_interval = 1
sts.inactivity_timeout = 60
sts.connection_speed = 10
sts.allow_multiple_connections_per_ip = True
sts.max_out_request_queue = 128
sts.request_queue_size = 3
sts.use_read_cache = False
session.set_settings(sts)
session.set_alert_mask(lt.alert.category_t.tracker_notification | lt.alert.category_t.status_notification)
session.set_alert_mask(lt.alert.category_t.status_notification)
ipaddr = get_wan_ip_address()
#print ipaddr
if ipaddr == "":
session.listen_on(6881, 6881)
else:
session.listen_on(6881, 6881, ipaddr)
limit = int(upload_rate_limit)
if limit>=100:
session.set_upload_rate_limit(limit*1024)
session.set_local_upload_rate_limit(limit*1024)
print session.upload_rate_limit()
torrent_info = lt.torrent_info(torrent)
add_params = {
'save_path': path,
'storage_mode': lt.storage_mode_t.storage_mode_sparse,
'paused': False,
'auto_managed': True,
'ti': torrent_info,
}
handle = session.add_torrent(add_params)
read_alerts(session)
st = time.time()
dl_status(handle)
et = time.time() - st
print '\nall file download in %.2f\nstart to seeding\n' % et
sys.stdout.write('\n')
handle.super_seeding()
seed_status(handle, seedtime)
remove_torrents(handle, session)
assert len(session.get_torrents()) == 0
finally:
print 'download finished'
if __name__ == '__main__':
usage = "usage: %prog [options] \n \
%prog -d -f -s \n \
or \n \
%prog -m -p -s \n"
parser = OptionParser(usage=usage)
parser.add_option("-d", "--download", dest="download",
help="start to download file", action="store_false", default=True)
parser.add_option("-f", "--file", dest="file",
help="torrent file")
parser.add_option("-u", "--upload", dest="upload",
help="set upload rate limit, default is not limit", default=0)
parser.add_option("-t", "--time", dest="time",
help="set seed time, default is 100s", default=100)
parser.add_option("-p", "--path", dest="path",
help="to make torrent with this path")
parser.add_option("-m", "--make", dest="make",
help="make torrent", action="store_false", default=True)
parser.add_option("-s", "--save", dest="save",
help="file save path, default is store to ./", default="./")
(options, args) = parser.parse_args()
#download(sys.argv[1])
if len(sys.argv) != 6 and len(sys.argv) != 4 and len(sys.argv) != 8 and len(sys.argv) != 10:
parser.print_help()
sys.exit()
if options.download == False and options.file !="":
download(options.file, options.save, options.upload, options.time)
elif options.make == False and options.path != "":
make_torrent(options.path, options.save)


三、使用


1、环境准备
需要在所有的os上面安装一个libtorrent的库,下载地址:http://code.google.com/p/libtorrent/downloads/list (国内需使用代理访问)

记得编译的时候带上./configure –enable-python-binding,然后mak,make install,进入binding目录,make,make install就可以运行这个小的工具。当然大规模部署不可能采用每一台都去编译安装的方式,只要把编译出来的libtorrent.so libtorrent-rasterbar.so.7的文件跟bt.py这个文件放到同一个目录,另外写一个shell脚本。
lib=`dirname $0`
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$lib
python bt.py -d -f <种子文件> -s <文件保存路径> -t <做种时间> -u <限制上传速度>

2、使用方法
在源服务器上生成种子文件:
python bt.py -m -p <要发布的文件或者文件夹> -s <种子保存地址>

在源服务器上发布文件:
python bt.py -d -f <种子文件> -s <文件保存路径> -t <做种时间> -u <限制上传速度>
其中做种时间默认设置是100s,上传速度默认不限制,限制速度的单位是kb。
 
只要有一台机器完成了,就自动作为种子,在下载的过程中也会上传,任何一台机器都可以作为源服务器,当然了这里面还有中心的tracker服务器,脚本当中,我搭建了一个tracker源服务器,放到10.0.1.5端口是8760上面,当然大家也可以采用opentracker这个软件自己搭建一个tracker服务器,修改其中的源代码对应部分,另外考虑到发布都是私有文件,代码当作已经禁止了dht,如果还想更安全,就自己搭建一个私有的tracker server,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!

目前基本做到可以使用,后续考虑更简单一点,采用磁力链接的方式,这样就可以做到不用每台都要拷贝一个种子文件,采用一个单独的命令行就可以发布整个文件。

在使用实用中进行大文件传输时,可以再结合ansible、saltstack等自动化运维工具需要在多台主机之间传大文件时,可以通过该文件加快传输速度,增加网络利用率。 收起阅读 »