我是Python新手,在完成了一些介绍性的练习之后,我编写了一个用于处理一些硬件的类定义,特别是一个信号恢复模型7230锁定放大器。为了从一开始就学习好习惯,我试着编写“好代码”,这些代码都有适当的文档记录,遵循良好的实践等等。
""" Module for interfacing with Signal Recovery 7230 lock-in amplifier.
A substantial ammount is currently not implmented. It will not work with
a lockin which is configured for double demodulation. If you get a lot
of timeouts, that might be why.
It is also currently missing any way to configure the lockin. Use the
web interface. It does read and expose the status bytes, but at the moment
there is no checking of their content.
@author: Jack Barraclough
"""
import pyvisa
class WrongInstrumentError(Exception):
"""The wrong instrument is connected
A connection was successfuly established, and the instrument responded
to a request to identify itself, but the ID recieved was wrong.
Probably the instrument at the given VISA identifier is not the one
you wanted.
"""
pass
class Instrument:
"""Represents a Signal Recovery Model 7230 lock-in amplifier
Note that several instances can be created representing the same
instrument. Be careful.
Instance variables:
pyvisa -- a pyvisa object for the connection, avoid using.
status_byte -- status byte after the last read operation.
overload_byte -- overload byte after the last read operation.
Methods:
read, write -- Read and write strings to/from the instrument.
get_X, get_Y, get_R, get_T -- get measurements from the instrument.
get_noise -- get the estimated measurement noise
"""
def __init__(self,visaName):
""" Connects to the lockin amplifier
Connects to the lockin, and checks that the lockin is present and
correct. An error will be raised if the lockin is not there, or
if it fails to identify itself as a model 7230
Arguments:
visaName -- A Visa Resource ID, like 'TCPIP0::10.0.0.2::50000::SOCKET'
"""
rm = pyvisa.ResourceManager()
self.pyvisa = rm.open_resource(visaName)
self.pyvisa.read_termination='\00'
self.write('ID') # uses this not '*IDN?'
resp = self.read()
if resp != '7230':
raise WrongInstrumentError(
'Wrote "ID" Expected "7230" got "{}"'.format(resp))
def write(self,string):
"""Write string to the instrument."""
self.pyvisa.write(string)
def read(self):
"""Read string from the instrument. Also sets status bytes"""
# replies seem to be: response LF NUL then two status bytes
resp = self.pyvisa.read().strip()
status = self.pyvisa.visalib.read(self.pyvisa.session,2)[0]
self.status_byte = status[0]
self.overload_byte = status[1]
return resp
def get_X(self):
"""Get X value from the instrument, returns a float"""
self.write('X.')
return float(self.read())
def get_Y(self):
"""Get Y value from the instrument, returns a float"""
self.write('Y.')
return float(self.read())
def get_R(self):
"""Get R value from the instrument, returns a float"""
self.write('MAG.')
return float(self.read())
def get_T(self):
"""Get theta value from the instrument, returns a float"""
self.write('PHA.')
return float(self.read())
def get_noise(self):
"""Get Y noise from the instrument, in v/sqrtHz, returns a float"""
self.write('NHZ.')
return float(self.read())我对一般的反馈感兴趣,但也有一些具体的问题:
rm.close()方法。我没说出来,是不是漏了什么东西?垃圾收集器会处理它吗?把它留给垃圾收集器是不好的形式吗?我该用毁灭器把它弄清楚吗?发布于 2015-03-15 23:31:32
到目前为止,您的代码看起来相当不错--结构良好,有用的文档字符串,做得很好!你提到了例外,你用的那一次对我来说很好。
每个风格指南,例如,visaName应该是visa_name。此外,与注释pyvisa -- a pyvisa object for the connection, avoid using.不同,传统的做法是将不应该在外部使用的属性名称加上单独的下划线:_pyvisa。
与其在docstring中包含@author,不如使用Python的一个特殊模块属性:
__author__ = 'Jack Barraclough'get方法不是非常Pythonic的。相反,我建议您使用属性,例如:
@property
def R(self):
"""Get R value from the instrument, returns a float"""
self.write('MAG.')
return float(self.read())现在,您可以键入简单的instrument.get_R(),而不是instrument.R。
更进一步说,还有很多重复--每个调用self.write的人都会从self.read返回值。你可以完全考虑到这一点:
class Instrument:
PROPERTIES = {'R': 'MAG.', ...}
def __getattr__(self, attr):
if attr in self.PROPERTIES:
return self._get(self.PROPERTIES[attr])
msg = "{!r} object has no attribute {!r}"
raise AttributeError(msg.format(self.__class__.__name__, attr))
def __setattr__(self, attr, val):
if attr in self.PROPERTIES:
raise AttributeError("can't set attribute")
return super().__setattr__(attr)
def _get(self, value):
self.write(value)
return float(self.read())我承认我对pyvisa不太了解,但是确保资源被释放的一个选择是让您的类成为上下文管理器类型。这样,用户就可以做到。
with Instrument(whatever) as inst:
...并确保所有的事情都在__exit__上处理过。
发布于 2015-03-16 19:05:48
我也不知道pyvisa,但我有相当类似的脚本接口仪器与VXI。在这种情况下,对话是通过tcp套接字完成的,而不是关闭它可能会导致脚本下一次运行时出现问题。但是,pyvisa可能会帮你处理这些事情。在我的例子中,我使用了上下文管理器。
根据仪器的不同,您可能需要使__setattr__变得更加复杂,因为您可能不仅在阅读,而且还在改变仪器中的一些设置。您可能需要一些列表,比如ReadOnly_PROPERTIES和ReadWrite_PROPERTIES。
@jonrsharpe --我以前从未见过那种一次性定义一组属性的方法。好主意!
https://codereview.stackexchange.com/questions/84087
复制相似问题