如何解决我们应该避免使用C ++中的重复代码以使其“ Pythonic”吗?如何?
| 我处于Python的幼虫阶段,而处于C ++的预蛋阶段,但是我正在努力做到最好,尤其是遵循“不要重复自己”的原则。 我有一个要打开的多通道原始文件格式,带有一个主要的ascii标头,其字段可表示为字符串和整数(始终编码为用空格填充的字符)。第二部分是N个标头,其中N是主标头的字段,并且这些标头中的每个标头本身都有许多文本和数字字段(编码为ascii),这些字段涉及实际的16位多通道流的长度和大小。组成文件的其余部分。 到目前为止,我在C ++中有以下工作代码:#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
using namespace std;
struct Header {
string version;
string patinfo;
string recinfo;
string start_date;
string start_time;
int header_bytes;
string reserved;
int nrecs;
double rec_duration;
int nchannels;
};
struct Channel {
string label;
string transducertype;
string phys_dim;
int pmin;
int pmax;
int dmin;
int dmax;
string prefiltering;
int n_samples;
string reserved;
};
int main()
{
ifstream edf(\"/home/helton/Dropbox/01MIOTEC/06APNÉIA/Samples/Osas2002plusQRS.rec\",ios::binary);
// prepare to read file header
Header header;
char buffer[80];
// reads header fields into the struct \'header\'
edf.read(buffer,8);
header.version = string(buffer,8);
edf.read(buffer,80);
header.patinfo = string(buffer,80);
edf.read(buffer,80);
header.recinfo = string(buffer,8);
header.start_date = string(buffer,8);
header.start_time = string(buffer,8);
stringstream(buffer) >> header.header_bytes;
edf.read(buffer,44);
header.reserved = string(buffer,44);
edf.read(buffer,8);
stringstream(buffer) >> header.nrecs;
edf.read(buffer,8);
stringstream(buffer) >> header.rec_duration;
edf.read(buffer,4);
stringstream(buffer) >> header.nchannels;
/*
cout << \"\'\" << header.version << \"\'\" << endl;
cout << \"\'\" << header.patinfo << \"\'\" << endl;
cout << \"\'\" << header.recinfo << \"\'\" << endl;
cout << \"\'\" << header.start_date << \"\'\" << endl;
cout << \"\'\" << header.start_time << \"\'\" << endl;
cout << \"\'\" << header.header_bytes << \"\'\" << endl;
cout << \"\'\" << header.reserved << \"\'\" << endl;
cout << \"\'\" << header.nrecs << \"\'\" << endl;
cout << \"\'\" << header.rec_duration << \"\'\" << endl;
cout << \"\'\" << header.nchannels << \"\'\" << endl;
*/
// prepare to read channel headers
int ns = header.nchannels; // ns tells how much channels I have
char title[16]; // 16 is the specified length of the \"label\" field of each channel
for (int n = 0; n < ns; n++)
{
edf >> title;
cout << title << endl; // and this successfully echoes the label of each channel
}
return 0;
};
我已经要说的一些话:
我之所以选择使用struct是因为格式规范是非常硬编码的。
我没有遍历主标头字段,因为在我看来,要读取的字节和类型的数量相当随意。
现在,我已经成功获取了每个通道的标签,实际上我将为每个通道的字段创建结构,这些结构本身可能必须存储在地图中。
我的(希望很简单)的问题是:
\“我是否应该担心偷工减料,以使这类代码更加“ Pythonic”(更抽象,更少重复),或者这不是C ++的工作方式吗?”
许多Python传播者(就像我自己一样,因为我喜欢它)强调了它的易用性以及所有这些。因此,我会怀疑我是在做愚蠢的事情还是只是在做正确的事情,但是由于C ++的本质,我不会这么想“自动”。
谢谢阅读
海尔顿
解决方法
我会说没有Pythonic C ++代码之类的东西。 DRY原理在两种语言中都适用,但是使用Python特定的构造,大多数被认为是Python语言的最简单,最甜蜜的方式就是“ Pythonic”。惯用的C ++完全不同。
例如,有时将
lambda
视为不是Python风格的,而是保留给不存在其他解决方案的情况,而只是将其添加到C ++标准中。 C ++没有关键字参数,这是非常Pythonic的。 C ++程序员在不需要时不喜欢构造map
,而Python程序员可能会在很多问题上抛出dict
,而恰恰是它们使意图比有效的选择更清晰。
如果要保存键入,请使用我之前发布的功能,然后:
header.version = read_field(edf,8);
header.patinfo = read_field(edf,80);
那应该节省您很多行。但是,与那几行相比,更为重要的是,您已经实现了少量的模块化:如何读取字段以及要读取的字段现在已成为程序的独立部分。
,您是正确的:按照书面要求,该代码是重复性的(并且没有错误检查)。阅读的每个字段实际上都需要您采取三到五个步骤,具体取决于要读取的数据类型:
从信息流中读取字段
确保读取成功
解析数据(如有必要)
确保解析成功(如有必要)
将数据复制到目标位置
您可以将所有这三个函数包装到一个函数中,以使代码减少重复。例如,考虑以下功能模板:
template <typename TStream,typename TResult>
void ReadFixedWidthFieldFromStream(TStream& str,TResult& result,unsigned sz)
{
std::vector<char> data(sz);
if (!str.read(&data[0],sz))
throw std::runtime_error(\"Failed to read from stream\");
std::stringstream ss(&data[0]);
if (!(ss >> result))
throw std::runtime_error(\"Failed to parse data from stream\");
}
// Overload for std::string:
template <typename TStream>
void ReadFixedWidthFieldFromStream(TStream& str,std::string& result,sz))
throw std::runtime_error(\"Failed to read from stream\");
result = std::string(&data[0],sz);
}
现在,您的代码可以更加简洁:
ReadFixedWidthFieldFromStream(edf,header.version,8);
ReadFixedWidthFieldFromStream(edf,header.patinfo,80);
ReadFixedWidthFieldFromStream(edf,header.recinfo,80);
// etc.
,此代码简单,简单且易于理解。如果它可以正常工作,请不要浪费时间进行更改。我敢肯定,有很多写得不好,复杂且难以理解(并且可能不正确)的代码应该首先修复:)
,Python的Zen并未明确提及DRY。
>>> import this
The Zen of Python,by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren\'t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity,refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you\'re Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain,it\'s a bad idea.
If the implementation is easy to explain,it may be a good idea.
Namespaces are one honking great idea -- let\'s do more of those!
,要直接从字符串中读取文件,请参阅此问题,其余的是错误的。但我个人认为这是一种更好/更清洁的方法。
如果知道结构的大小不使用字符串,请使用原始C类型(并确保结构已打包)。请参阅以下链接:http://msdn.microsoft.com/zh-cn/library/2e70t5y1(v=vs.80).aspx和http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc /Type-Attributes.html
我将以这种方式进行操作(例如,不确定每个字符串的大小,但您会明白的):
struct Header {
char version[8];
char patinfo[80];
char recinfo[80];
char start_date[8];
char start_time[8];
int header_bytes;
char reserved[44];
int nrecs;
double rec_duration;
int nchannels;
};
一旦有了打包结构,就可以直接从文件中读取它:
struct Header h;
edf.read(&h,sizeof(struct Header));
对我来说,这是最干净的方法,但是请记住,您必须打包好结构,以确保内存中的结构与文件中保存的结构具有相同的大小-这在这段时间内很难看到测试。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。