Python新式类-统一types和class

这篇文章翻译自 Python官方的非正式文档 https://www.python.org/download/releases/2.2.3/descrintro/

引言

Python2.2引入类型和类的统一(type/class unification)的第一个阶段。这是我们试图引入一系列措施,以消除内置类型和用户定义类之间的区别。也许其中最严重的限制就是内置类型不能作为基类被继承。

新式类的引入是Python最大的改变之一,当然也会引入一些向后兼容性的问题。 这些改变在都在一系列的Python PEP文档中详细描述。 PEPs不是面向初学者的文档,PEPs描述的type/class unification的方式有时候令人难以理解,而且PEPs目前尚不完善。本篇文章的主要目标就是向广大的基础的Python程序员解释type/class unification中最关键的部分。

Continue Reading...

Python中的__slots__的用途

限制类属性的扩展

我们知道Python中,我们很容易为一个类的实例增加属性或者方法。
比如

class Student(object):
    pass

s = Student()
s.name = "lightky"
print(s.name)  #为实例s增加了属性name

def set_id(self, id):
    self.id = id

from types import MethodType

s.set_id = MethodType(set_id, s)
s.set_id(201300000001)
print(s.id)   # 为s增加了set_id方法,从而可以输出id属性

Continue Reading...

龙书练习题-第二章

2.2 语法定义

练习2.2.1

考虑下面的上下文无关文法
$$S\rightarrow SS+ | S S * |a$$

  1. 试说明如何使用该文法生成串aa+a*.
  2. 试为这个串构造语法分析树
  3. 该文法生成的语言是什么。请证明你的答案

答案

  1. $[ S\rightarrow SS* \rightarrow SS+S* \rightarrow aS+S* \rightarrow aa+S* \rightarrow aa+a* $[
  2. 语法树如下

语法树

  1. L是一个包含乘法和加法的运算表达式的后序表达

练习2.2.2

下面的各个文法生成什么语言?证明你的答案

  1. $[ S \rightarrow 0S1|01 $[
  2. $[ S \rightarrow +SS|-SS|a $[
  3. $[ S \rightarrow S(S)S| \epsilon $[
  4. $[ S \rightarrow aSbS|bSaS| \epsilon $[
  5. $[ S \rightarrow a | S+S | SS | S* | (S) $[

练习2.2.4

为下面的各个语言构建无二义性的上下文无关文法。证明你的文法都是正确的。

  1. 用后缀方式表示的算术表达式
  2. 由逗号分隔开的左结合的标识符列表
  3. 由逗号分隔开的右结合的标识符列表
  4. 由整数、标识符、四个二目运算符+-*/构成的算术表达式
  5. 在4的运算符中增加单目+和单目-构成的袁术表达式

答案


  1. $$ exp \rightarrow exp exp - $$
    $$\space\space | exp \space exp + $$
    $$\space\space | exp \space exp * $$
    $$\space\space | exp \space exp / $$
    $$ | num $$

mac os使用homebrew来管理后台服务

在linux下我们经常通过 service 或者 /etc/init.d/来管理我们的后台服务软件,并使用包管理器安装这些软件。 在mac下有homebrew这个好用的工具来安装软件,但是一直没有找到好的管理这些软件的方法,知道我发现了homebrew的一个services插件。

安装方法:

通过下面的命令行可以安装services插件

brew tap gapple/services
安装好之后就可以非常方便的使用,例如

$ brew services start mysql
==> Successfully started mysql (label: homebrew.mxcl.mysql)
Alt text

C++ 坑笔记

返回值优化

以前我们可能会认为C++的复制构造函数会在函数返回时调用,但是现代的编译器对返回值有优化。
wiki上有详细的原文

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};

C f() {
  return C();
}

int main() {
  std::cout << "Hello World!\n";
  C obj = f();
  return 0;
}

宏函数可能引发的错误

#define DO_MAX(a,b) f((a) > (b)? (a):(b))
int a = 5, b = 0;
DO_MAX(++a, b);      //a被累加二次
DO_MAX(++a, b+10);   //a被累加一次

可以采用inline模板,照样可以达到宏一样的性能。而且没有这种宏替换带来的缺点,而且有类型检查。

template<typename T>
inline void DO_MAX(const T& x, const T& b) {
    f(a > b ? a : b);
}

对于单纯的常量,最好使用const或者enums,替换#define
对于宏函数,最好改用inline

const 尽可能的使用const

  • const修饰常量
  • const修饰指针本身
  • const修饰成员函数
    表示该成员不会改变类的成员,如果需要改变的某个变量的话,使用mutable修饰成员
    const修饰成员函数时仅仅只是测试该函数执行过程中有没有进行修改或者赋值。如果故意把某个变量的引用返回出去,也可能会被外部修改。
    在const和non-const的成员函数中避免重复,如果需要,通过const_cast进行转换。
  • const修饰函数形参

对象初始化

C++11之前对象初始化不具有线程安全特性
C++的初始化成员次序非常固定,基类早于子类的初始化。析构时,正好相反

C++中对定义于不同编译单元内的全局静态对象的初始化顺序不确定。但是都是在main函数之前。 编译单元其实就是单个cpp文件。 最常见而且容易被忽略的情况是 non local static的模板类成员。模板类在被使用时编译才具体化。
C++中的local static对象一定会在第一次使用时定义。

A * getInstance() {
   static A * m;
   if (m == nullptr) {
      Lock();
      m = new A();
      UnLock();
   }
   return A;
}  //这段代码在c++11之前 线程不安全

void test() {
   cout << "before a";
   static A a();           //假设a构造是输出 I am created.
   cout << "after a";     
} // 这段代码的输出结果是, 先before,再I am created,再after

C++的默默编写的函数

  • 构造函数
  • 析构函数
  • 复制构造函数
  • 赋值重载

若不想使用编译器自动生成的函数,就要明确拒绝

C++11中 使用 delete 可以删除默认的函数
之前的版本,可以显式声明,并且设置为private。不需要实现。

多态基类的析构函数声明为virtual

否则对指向子类的基类指针使用delete时候,会产生内存泄露。