Checking for hyperthreading I want to just write a simple function to check if my linux box has hyperthreading enabled. I want to know if there's a simpler way to produce the cpuinfo dict (would be great if I could use a dict comprehension somehow) or generally a better way to check this information:

def is_hyperthreading_enabled():
    cpuinfo = dict(map(str.strip, line.split(':'))
                   for line in open('/proc/cpuinfo')
                   if ':' in line)

    return cpuinfo['siblings'] != cpuinfo['cpu cores']
First off, you should always close a file in Python.
There are two ways to do that.


The old style way:

file_handler = open('/proc/cpuinfo')
// Your code here
file_handler.close()
The 'new' way with with.

with open('/proc/cpuinfo') as file_handler:
    // Your code here


The second is more recommended as then it's both clear when the file is open, and you don't forget to close it.



While /proc/cpuinfo is unlikely to have more than one : per line, it could happen. As it seems model name can be whatever the model is called. If a vendor were to put a : in their name, your code won't work. with the exception:

ValueError: dictionary update sequence element #1 has length 3; 2 is required


To avoid this as an issue, you can use the optional second argument to str.split(':', 1).



If you want to use a dictionary comprehension at all cost. Then it's the same as your above code, but it will have a dictionary comprehension surrounding it.

with open('/proc/cpuinfo') as file_handler:
    cpuinfo = {
        key: value
        for key, value in (
            map(str.strip, line.split(':', 1))
            for line in file_handler
            if ':' in line
        )
    }


This is in my opinion worse than your above code, as it's common knowledge that dict([['key', 'value']]) can be used to make a dict, which was added in 2.2. Where dictionary comprehensions were added in 2.7.
And your original code is a lot less verbose.



You could however use a functional approach to this. Which has the drawback of needing to define line twice, and is more verbose than the original code.

with open('/proc/cpuinfo') as file_handler:
    cpuinfo = dict(map(
        lambda line: map(str.strip, line.split(':', 1)),
        filter(lambda line: ':' in line, file_handler)
    ))




Overall I would recommend using your original code, but with with and line.split(':', 1)) added.

Just to note, ':' in line returns false every time the CPU core changes.
For example from my /proc/info. (note I removed the flags)

processor   : 0
vendor_id   : GenuineIntel
cpu family  : 6
model       : 42
model name  : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz
stepping    : 7
microcode   : 0x28
cpu MHz     : 1728.761
cache size  : 6144 KB
physical id : 0
siblings    : 4
core id     : 0
cpu cores   : 4
apicid      : 0
initial apicid  : 0
fpu     : yes
fpu_exception   : yes
cpuid level : 13
wp      : yes
bugs        :
bogomips    : 6800.31
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

processor   : 1
vendor_id   : GenuineIntel
cpu family  : 6
model       : 42
model name  : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz
stepping    : 7
microcode   : 0x28
cpu MHz     : 1686.609
cache size  : 6144 KB
physical id : 0
siblings    : 4
core id     : 1
cpu cores   : 4
apicid      : 2
initial apicid  : 2
fpu     : yes
fpu_exception   : yes
cpuid level : 13
wp      : yes
bugs        :
bogomips    : 6800.31
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:


This also shows that the information can change. E.g. cpu MHz:1728.761 and cpu MHz:1686.609. So you may not want to overwrite some of this information. Also if you have more than one CPU (say you are using a sever) then you could return false on one CPU and true on another, but as the last core overwrites all the previous data it's somewhat up to chance to know.

Due to this I would recommend that you change your function to make cpuinfo a list of dicts.

Finally as far as I know unless you read the entire file and split on \n\n then there is no way to make it a comprehension.
And so I would recommend:

def is_hyperthreading_enabled():
    with open('/proc/cpuinfo') as file_handler:
        cpuinfo = []
        temp_dict = {}
        for line in file_handler:
            try:
                key, value = map(str.strip, line.split(':', 1))
            except ValueError:
                cpuinfo.append(temp_dict)
                temp_dict = {}
            else:
                temp_dict[key] = value

    return any(map(lambda core: core['siblings'] != core['cpu cores'], cpuinfo))


Note, the above works as I make the assumption that the file always ends with an empty line. Otherwise you would be missing one of the cores. This assumption seems to be true, as I tested if /proc/cpuinfo ends with an empty line on all a single; quad-core, dual-core and single core, CPU.
If you think this is too small a test case, you can add the following after the for loop.

if temp_dict:
    cpuinfo.append(temp_dict)


So if you only care about one core, your way is best. If you want to test if any CPU can, then you would want to use the above. And if you want to know if all of them can then you should change any to all in the above.