Common Python and C++11 usage comparison

My Gist

  • Python
    1
    2
    3
    
    a = 1
    b = 0.0
    c = 'xxx'
  • C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    int a = 1;
    auto a = 1;
    double b = 0.0;
    auto b = 0.0;
    const char c[] = "xxx"; // C string (char array)
    const char* c = "xxx";  // C string (pointer)
    std::string c = "xxx";
    std::string c("xxx");
    std::string c{"xxx"};
  • Python

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    global_var1 = 1
    def func(arg):
        local_var = 2
        global global_var2
        global_var2 = 'xxx' # global
    if arg:
        local_var2 = 0.5 # scope: function
        ...
        # if arg evaluates to True,
        # local_var2 is still accessible here.
        return False

  • C++

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    int global_var1 = 1; // global
    static std::string global_var2; // global in the current file
    bool func(bool arg){
    int local_var = 2;
    global_var2 = "xxx";
    if(arg){
    double local_var2 = 0.5; // scope: if block
    ....}
    // local_var2 is undefined here}
    

  • Python

    1
    2
    3
    4
    5
    6
    7
    8
    
    s1 = {"key1" : 100}
    s2 = s1 # reference the same object
    s2["key2"] = 200
    print(s1["key1"])
    # {"key1":100, "key2": 200}
    s2 = {} # s1 is NOT changed, s1 and s2
    
    # reference different objects now

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    std::unordered_map<std::string, int> s1 = {"key1" : 100};
    std::unordered_map<std::string, int> s2 = s1; // copy the whole object
    std::unordered_map<std::string, int>& s2 = s1; // reference the same object
    s2 = std::unordered_map<std::string, int>(); // s1 is changed, s1 and s2 still reference the same object
    // C++ 11
    auto s2 = s1;  // copy the whole object (slow)
    auto& s2 = s1; // reference the same object
    // Now s2 is a reference to s1
    auto s3 = s2;  // copy the whole s1 object. s3 is NOT a reference
    const auto& s3 = s2; // reference the same s1 object
    

  • Python

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    if a == 1 and b == 2:
        pass
    elif c == 3 or d == 4:
        pass
    else:
        pass
    if a == 1:
    ...
    elif a == 2:
    ...
    elif a == 3:
    ...
    else:
    ...

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    if (a == 1 && b == 2){}
    else if(c == 3 || d == 4){}
    else {}
    switch(a){
    case 1:
        ...
        break;    // without break, will run case 2 as well
    case 2: { // create a new scope if we need to define new variables
        int a = 100;
        break;}
    default:  // it's good practice to always add this
    ...};

  • Python

    1
    2
    3
    4
    5
    
    # Import: File: app/bidders/ai_util.py
    import app.bidders.ai_util
    # Namespace: defined by directory structure
    # Fully qualified names:
    app.bidders.ai_util.func("xxx")

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    // Import: Files: app/bidders/ai_util.hpp & ai_util.cpp
    #include "app/bidders/ai_utils.hpp"
    // Namespace: not related to directory structure
    namespace app {
        namespace bidder {
            namespace ai_util {
                void func(const char* str);
            }
        }
    }
    // Fully qualified names:
    app::bidders::ai_util::func("xxx");

  • Python

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    for i in range(100):
        pass
    while cond:
    ...
    a = [0, 1, 100]
    for item in a:
        pass
    b = {"key": 0.5, "key2", 1.0}
    for key, val in b.iteritems():
        pass

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    for(int i = 0; i < 100; ++i){...}
    while(cond){}
    std::vector<int> a = {0, 1, 100};
    for(auto& item: a){ // without &, this will copy each item
    }
    std::unordered_map<std::string, double> b = {{"key", 0.5}, {"key2",
    1.0}};
    for(auto& item: b){ // without &, this will copy each item
    auto& key = item.first;
    auto& val = item.second;}

  • Python

    1
    2
    3
    
    def func(arg1, arg2):
        ....
        return ret1, ret2, ret3

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    void func(const Arg1& arg1, const Arg2& arg2,
    Ret1& ret1, Ret2& ret2, Ret3& ret3
    ){...
    ret1 = ....;
    ret2 = ....;
    ret3 = ....;}
    No multiple return values
    Need to specify the type of the return value
    Every variable needs to have type declaration
    Declaration before use is required
    Add const to the references that are not changed by the method
    Declare in *.hpp, implement in *.cpp (for public functions)

  • Python

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    # Python version: only one *.py file:
    class PythonClass(ParentClass):
        def __init__(self): # constructor, pass instance as self
            ParentClass.__init__(self) # python2
            self.attrib = 1111
            Self.attrib2 = 'xxx'
        def some_method(self, arg1, arg2):
            return arg1 * arg2 + self.attrib
        def _some_private_method(self): # kind of private func
            pass

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    // --------- Declaration: cpp_class.hpp ---------
    class CppClass: public ParentClass {
    public:
    CppClass(): ParentClass(), attrib(5566),
    attrib2("xxx"){}
    virtual ~CppClass(): {
    // destructor: free allocated resources here}
    double someMethod(double arg1, double arg2);
    private:
    void somePrivateMethod(){}
    int attrib;
    std::string attrib2;};
    // --------- Implementation: cpp_class.cpp ---------
    #include "cpp_class.hpp"
    double CppClass::someMethod(double arg1, double arg2){
    return arg1 * arg2 + attrib;}

  • Python

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    class Raccoon:
        def get_name(self):
            return "raccoon"
    class Zebra(Raccoon):
        def get_name(self):
            return "zebra_" + Raccoon.get_name()
    def func(maybe_racoon):
        print(maybe_racoon.get_name())
    obj = Zebra()
    func(obj)
    
    # pintout: zebra_raccoon

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    class Raccoon {
    public:
    std::string getName() const {
    return "raccoon";}};
    class Zebra: public Raccoon {
    public:
    std::string getName() const {
    return "zebra" + Raccoon::getName();}};
    void func(const Raccoon& maybeRaccoon){
    std::cout << maybeRaccoon.getName() << std::endl;}
    Zebra obj;
    func(obj);
    // pintout: raccoon
    

  • C++

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    class Raccoon {
    public:
    virtual std::string getName() const {
    return "raccoon";}};
    class Zebra: public Raccoon {
    public:
    std::string getName() override const {
    return "zebra" + Raccoon::getName();}};
    void func(const Raccoon& maybeRaccoon){
    std::cout << maybeRaccoon.getName() << std::endl;}
    Zebra obj;
    func(obj);
    // pintout: zebra_raccoon
    

  • Python
    1
    2
    3
    4
    5
    
    obj = ObjClass()
    obj.method(arg)
    obj.attribute = 100
    obj2 = obj # reference the same object
    # Manual delete is not needed
  • C++
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    ObjClass* obj = nullptr; // prefer nullptr over NULL
    ObjClass* obj = new ObjClass(); // allocate on heap
    obj->method(arg);
    obj->attribuge = 100;
    auto obj2 = obj;   // point to the same object
    auto obj2 = *obj;  // copy!
    auto& obj2 = *obj; // reference the same object
    delete obj;        // when not used, manual delete is required
    ObjectClass localObj(); // allocate on local stack
    localObj.method(arg);
    // Raw pointer is not recommended. Use smart pointers
    #include <memory>
    std::shared_ptr<ObjClass> obj;
    auto obj = std::make_shared<ObjClass>();
    obj->method(arg);
    obj->attribute = 100; // manual delete is not needed
    auto obj2 = obj;      // point to the same object (no * or &)
    
  • int:
    • int, long, unsigned int, unsigned long (size is architecture dependent)
    • std::int64_t, std::uint64_t, std::int16_t, … (#include , well-defined sizes)
  • bool:bool
  • float: double (64-bit), float(32-bit, bad performance & not recommended)
  • str, bytes: std::string (#include )
  • containers:
    • list: std::vector<> (#include )
    • dict: std::unordered_map<> (#include <unordered_map>)
    • set: std::unordered_set<> (#include <unordered_set>)
  • None:
    • For float, can use NAN (#include ) and use std::isnan(number) to check if it’s NAN
    • For string, just use empty string and use str.empty() to check if it’s empty
  • Python
    1
    2
    3
    4
    5
    6
    7
    
    s = "this is a string"
    s2 = s # s2 and s reference the same object
    len(s)
    t = "prefix_" + s + "_suffix"
    t = "prefix1" + "prefix2" + s
    s = "has\0zero"
    # len(s): 8
  • C++
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    #include <string>
    std::string s = "this is a string";
    auto s2 = s; // copy s to s2 (new object)
    auto& s2 = s; // s2 is a reference only
    s.length();
    auto t = "prefix_" + s + "_suffix"; // works but slower
    std::string t = "prefix_"; t += s; t += "_suffix"; // good
    auto t = "prefix1" + "prefix2" + s; // does not work
    std::string s = "has\0zero"; // incorrect
    s.length(): 3
    std::string s("has\0zero", 8); // correct
    Alternative (C++ 14):
    using namespace std::string_literals;
    auto z = "has\0zero"s; // add "s" suffix, z is std::string
    auto z = "has\0zero"; // z is char* pointer
    
  • Python
    1
    2
    3
    4
    5
    6
    7
    8
    
    t = "test str"
    if t.find("sub_str") == -1:
        print("not found")
    u = t[1:2] # get sub string
    u = t[2:]  # get sub string til end
    if not t:
        print("empty str")
    v = t.lower()
  • C++
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    #include <string>
    std::string t = "test str";
    if (t.find("sub_str") == std::string::npos)
    std::cout << "not found\n";
    if(t.empty())
    std::cout << "empty str\n";
    auto u = t.substr(1, 2);
    auto u = t.substr(1);
    #include <algorithm>
    #include <cctype>
    std::transform(t.begin(), t.end(), t.begin(), std::tolower);
    // This does not work in unicode
    
  • Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    a = [1, 2, 3]
    b = ["str1", "str2", "str3"]
    c = ["xxx", {}, 100, 0.5] # cannot be done in C++
    a.append(100)
    a.insert(2, 10)
    del a[1], a[0:2]
    tmp = a[0:2]
    tmp = a[2]
    tmp2 = b[1] # reference the element
  • C++
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    #include <vector>
    std::vector<int> a = {1, 2, 3};
    std::vector<std::string> b = {"str1", "str2", "str3"};
    std::vector<????> c // cannot be done in C++
    a.push_back(100);
    a.insert(a.begin() + 2, 10);
    a.erase(a.begin() + 1);
    a.erase(a.begin(), a.begin() + 2);
    std::vector<int> tmp{a.begin(), a.begin() + 2};
    auto tmp = a[2];
    auto tmp2 = b[1]; // copy the element!
    auto& tmp2 = b[1]; // reference the element
    
    s
  • Python
    1
    2
    3
    4
    5
    6
    7
    8
    
    a = set()
    a = {"1", "2", "3"}
    b = [1, 2, 3]
    c = set(b)
    a.add("x")
    a.remove("2")
    if "4" in a:
        pass
  • C++
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    #include <unordered_set>
    std::unordered_set<std::string> a;
    std::unordered_set<std::string> a = {"1", "2", "3"};
    std::vector<int> b = {1, 2, 3};
    std::unordered_set<int> c(b.begin(), b.end());
    a.insert("x");
    a.erase("2");
    if (a.find("4") != a.end()){
    ...}
  • Python
    1
    2
    3
    4
    5
    6
    
    d = {"a": 1, "b": 2}
    nested = {
    "a": {"a1": 0.5},
    "b": {"b1": 0.3, "b2": 0.4},}
    free = {"a": 100, "b": "xxx", 50: None} # cannot do this in C++
    d = defaultdict(lambda: "null"); # cannot easily do this in C++ 
  • C++
    1
    2
    3
    4
    5
    6
    7
    
    #include <unordered_map>
    std::unordered_map<std::string, int> d = {
    {"a", 1}, {"b", 2}};
    std::unordered_map<std::string,
    std::unordered_map<std::string, int>> nested = {
    {"a": {{"a1", 0.5}}},
    {"b": {{"b1", 0.3}, {"b2", 0.4}},};
  • Python
    1
    2
    3
    4
    5
    6
    7
    
    d["new_key"] = 100
    d["no such key"] # raise KeyError
    del d["key"]; gc.collect()
    if "key" in d:
        e = d["key"]
    for key, val in d.iteritems():
        pass
  • C++
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    d["new_key"] = 100;
    d["no such key"] // create a new item for it
    d.erase("key");
    auto iter = d.find("key");
    if(iter != d.end()){
     // without &, this will do copy
    auto& e = iter->second;}
     // C++ 11 ranged for loop syntax
    for(auto& item: d){ // without &, this will do copy
    auto& key = item.first;
    auto& val = item.second;
    ...}

Related Content