使用Gitlab的内置nginx去服务其他静态内容

有时候,我们使用gitlab官方提供的deb去安装时,gitlab使用了内嵌的nginx服务,使用
chef去管理nginx的配置文件,所以如果我们在gitlab的服务器上想要使用其他的nginx服务
就很不方便,gitlab官方提供了方案是:

  • 停用内嵌的nginx,而使用外部的nginx,然后在外部的nginx安装文件里装入gitlab的配置

但是如果我们不想再安装外部的nginx,而直接使用内嵌的nginx,可以使用如下方案:

这个方法很好用,当然我们也可以直接修改:

  • 在原来的nginx配置文件(/opt/gitlab/embedded/cookbooks/gitlab/recipes/nginx.rb)中加入自定义的内容

Python GC and Destructure

先看一个示例:

In [1]:

class Foo:
def __init__(self, x):
print "Foo: Hi"
self.x = x
def __del__(self):
print "Foo: bye"

class Bar:
def __init__(self):
print "Bar: Hi"
self.foo = Foo(self) # x = this instance

def __del__(self):
print "Bar: Bye"

bar = Bar()
# del bar # This doesn't work either.
Bar: Hi
Foo: Hi
In [2]:

import sys
In [3]:

sys.getrefcount(bar)
Out[3]:
3

这里的destructor在对象被销毁的时候并没有被调用,原因就是:

  • Cyle Reference
  • CPython的实现在对象的GC是基于简单的reference count

即使我们使用del bar这样的操作,也不会触发destructor,原始是:

  • 当前的对象的reference count是3
  • del只会让reference count减1

根据文档:

“del x” doesn’t directly call x.__del__() — the former decrements the reference count for x by one, and the latter is only called when x’s reference count reaches zero. Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects

也就是说x.__del__del x不是同义的,并且根据文档,如果在cycle reference的对象
中使用__del__将会造成内存泄露:

Circular references which are garbage are detected when the option cycle detector is enabled (it’s on by default), but can only be cleaned up if there are no Python-level __del__() methods involved.

A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects). By default, this list contains only objects with __del__() methods.26.1Objects that have __del__() methods and are part of a reference cycle cause the entire reference cycle to be uncollectable, including objects not necessarily in the cycle but reachable only from it. Python doesn’t collect such cycles automatically because, in general, it isn’t possible for Python to guess a safe order in which to run the __del__() methods. […] It’s generally better to avoid the issue by not creating cycles containing objects with __del__() methods

程序退出时,destructor会被调用吗?

答案是不确定。

One final thing to ponder: if we have a __del__ method, should the interpreter guarantee that it is called when the program exits? (Like C++, which guarantees that destructors of global variables are called.) The only way to guarantee this is to go running around all modules and delete all their variables. But this means that __del__ method cannot trust that any global variables it might want to use still exist, since there is no way to know in what order variables are to be deleted.

Exception in __del__

def __del__(self):
raise Exception("Oopsy")
print "Bar: Bye"

Exception exceptions.Exception: Exception('Oopsy',) in > ignored
Bar: Hi
Foo: Hi
Foo: bye

会被忽略,只是编译器会有warning。

修正后的版本:

import weakref

class Foo:
def __init__(self, x):
print "Foo: Hi"
self.x = weakref.ref(x)
def __del__(self):
print "Foo: bye"

class Bar:
def __init__(self):
print "Bar: Hi"
self.foo = Foo(self) # x = this instance

def __del__(self):
print "Bar: Bye"

参考:

[1] http://mindtrove.info/python-weak-references/

随机权重分布的Python实现

原文:http://www.electricmonk.nl/log/2009/12/23/weighted-random-distribution/

Randomly selecting elements from a set of items is easy. Just generate a random number between 0 and the length of the set minus one, and use that as an index in the set (if it is an array) to get a random entry. The chance that an entry is picked is the same for each entry in the set. This is called even distribution or uniform distribution.

But what if we do not want each entry to appear as much as every other? Suppose we’re creating a question-answer game, and we want the questions the user got wrong previously to appear more often than the question he or she got right? This is called a Weighted Random Distribution, or sometimes Weighted Random Choice, and there are multiple methods of implementing such as random picker.

This article explains these various methods of implementing Weighted Random Distribution along with their pros and cons. We use Python as our language of choice, because it has an easy to read syntax, and provides many useful tools which would take many more lines of code in most other languages. Along the way all Python “tricks” will be explained.

分为几种实现:

Expanding

#!/usr/bin/python

import random

weights = {
        'A': 2,
        'B': 4,
        'C': 3,
        'D': 1
}

dist = []
for x in weights.keys():
        dist += weights[x] * x

results = {}
for i in range(100000):
        wRndChoice = random.choice(dist)
        results[wRndChoice] = results.get(wRndChoice, 0) + 1

print results

In-Place(Unsorted)

#!/usr/bin/python

import random

weights = {
        'A': 2,
        'B': 4,
        'C': 3,
        'D': 1
}

wTotal = sum(weights.values())

results = {}
for i in range(100000):
        wRndNr = random.randint(0, wTotal - 1)
        s = 0
        for w in weights.items():
                s += w[1]
                if s > wRndNr:
                        break;
        results[w[0]] = results.get(w[0], 0) + 1

print results

In-Place(Sorted)

results = {}
for i in range(100000):
        wRndNr = random.randint(0, wTotal - 1)
        s = wTotal
        for i in xrange(len(sWeights) - 1, -1, -1):
                wRndChoice = sWeights[i]
                s -= wRndChoice[1]
                if s <= wRndNr:
                        break
        results[wRndChoice[0]] = results.get(wRndChoice[0], 0) + 1
print results

Pre-calculation

wTotal = 0
sWeights = []
for w in weights.items():
    wTotal += w[1]
    sWeights.append( (wTotal, w[0]) )
    results = {}
for i in range(100000):
    wRndNr = random.randint(0, wTotal - 1)
    wRndChoice = sWeights[bisect.bisect(sWeights, (wRndNr, None))]

    results[wRndChoice[1]] = results.get(wRndChoice[1], 0) + 1

Python Innard: Introduction

翻译:《Python的内核揭秘(一):入门》

一个朋友曾经对我说:“你懂的,对某些人来说,C语言就是一堆扩展自汇编的宏”。这句话
是在数年前(好吧,是在llvm之前)说的,但是这话也让我语塞。Kernighan和Richie真的
可以在看到C语言的代码的时候可以立即解析为汇编代码?或者Tim Berners-Lee在浏览网页
的时候跟你我看到的内容都不同?或者Keanu Reeves在看一个新出炉的乱七八糟的汤的时候,
看到的究竟跟别人有啥差别?或者,严肃的说,他有看到什么玄机吗?好吧,无论如何,我
们回到程序,Guido van Rossum看到的Python跟别人不同吗?

这篇文章是我在研究Python的内核的时候写的一系列文章的开头,我之所以写这些文章是因
为我觉得能够解释清楚一个东西是深刻理解一个东西的最好的方法,我在这里很愿意把我在
读Python代码时的心得写在这里去尝试解释Python中到底发生了什么。在这个系列文章里,
我主要讨论的是CPython、py3k、bytecode以及其他(unladen swallow、Jython、Cython)
Python相关或者类似的代码。当我在这里说Python的时候,主要说的是CPython,运行的平台
是posix OS,比如linux。如果你想知道Python是怎么工作的,你应该读我的文章;如果你想
为CPython贡献代码,你也应该读我的文章。如果有发现任何错误的地方,你可以在后面写下
你的意见。

我在这里会写下所有关于我在读Python源代码时的心得,但是偶尔也会参考一个资料,比如
这个或者另个或者一些邮件列表其他。我把所有的资料都放在一起,希望你可以
通过订阅方便阅读。在读我的文章之前,我假设你已经知道一些C语言知识、操作系统理论、
一些汇编、或者一些Unix的爱好。如果没有这些知识也没有关系,但是我不保证你可以顺利
地理解。另外,如果你还没有那些为Python开发所需要的工具链,你可以参考这里

首先,我们从一些假设你已经知道的知识开始,但是我认为他们从我理解的角度是重要的。
Python使用虚拟机(VM)去执行代码,你必须要对虚拟机有一个比较好的认识,你可以把
Python的虚拟机当作是JVM,而不是Virtualbox。我发现从字面意义上理解虚拟机会更容易
懂,它一个用软件打造的机器。CPU是一个电子仪器,用来接受输入(比如data、machine
code),有一个状态(register),然后根据状态+输入数据可以得到输出的结果到RAM或者
Bus。Python的虚拟机也是这样一个机器,使用软件打造,接受机器码输入,有一个状态。这
个虚拟机存在于宿主的一个进程中。

让我们从一个具体的代码来对Python虚拟机有一个大概的理解,当你做$python -c 'print ("Hello, world!")'的时候,Python的二进制代码被执行了,标准的C代码库被初始化,然
后主程序开始执行(可以参考源代码./Modules/python.c ./Modules/main.c: Py_Main)。
在一些常见的初始化(输入参数解析、环境变量解析等)之后,./Python/pythonrun.c: Py_Initialize被调用。这个
函数是用来build和assemble,然后去运行虚拟机的,它创立了两个重要的数据结构:
interpreter statethread state。同时也创建了sys模块和builtins模块。我们在后
面会深入的解释这些概念。

当这些都完成之后,Python接下来的行动是基于它要如何执行代码:

  • -coption,用来执行一个字符串
  • -moption,用来执行模块
  • 执行一个python文件
  • 运行REPL loop,交互模式

对于我们的示例,我们将会执行一个字符串。为了执行这个字符串,./Python/pythonrun.c: PyRun_SimpleStringFlags将会被调用。这个函数创建了__main__命名空间,这个命名空
间将会被用来执行我们的字符串。比如你运行$ python -c 'a=1; print(a)',a将会被存
储在这个命名空间里。在命名空间被创建后,字符串就会在这里被执行,或者也可以理解为
评估(evaluate)或者解析(interpreter)。但是,首先你必须把字符串转换为机器可以
执行的东西。

Read More

Meta Class in Python

About Meta Class

由于class在Python中是first class对象,所谓的“first class”是指class跟Python中的其
他对象是同样级别的,比如:

  • class可以在运行时动态创建
  • class可以作为函数的参数名被传入
  • class可以重新赋值
  • class可以作为被return,作为返回的值

我们通常意义上理解的class是对象的模具或者原型,是对对象的抽象;我们可以通过初始化
class生成基于该class的对象,在python中,我们叫这个原型为type(类型)。对于类型的
理解,由于Python中一切都是对象,所以type本身也是对象,对于type的划分一般可以分为:

  • 在标准库中存在的type
  • 用户自定义的type

我们只关注用户自定义的type,Python在标准库中提供了一个原型type,然后所有的新型的
Python的class都是基于type创建的,我们可以使用下面的代码证明:

class C(object):
pass

type(C)
# type

值得注意的是,我们这里的class在定义的时候,传入了一个object,这个表明该class继承
了object类,object不是type,object同样由type生成的。这个C类这里继承object主要是
为了继承object里那些特殊的方法:

'__class__', '__delattr__', '__doc__', '__format__', '__getattribute__',
'__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'

所有的Python中的class对象都是type生成的。如果不想使用type,那可以选择我们这里说
的Meta Class,大部分Meta Class继承于type。

Read More

Non-capturing and Named Groups

渊源:

Perl 5 针对标准的“正则表达式”提供了几个额外的feature,Python在re模块中实现了大部
分,但是对于MetaCharacter的选择上,Perl为了突出当前的pattern使用了扩展的正则表达
式,而选择使用?作为一个标志,原因是?作为一个“重复次数(repeat times)”的限定
符的前面没有任何东西,这就意味着“Repeat Nothing”,这在标准的正则表达式是会出错的。
如果使用其他的单字符的MetaCharacter比如&,则会被那些标准的正则表达式识别为正常
的字符,而不是MetaCharacter控制字符。

Read More