工程基础
1. Python 装饰器
装饰器本身也是一个函数, 其参数是被装饰的类或者函数,关键字是@
这里给出一个通用的装饰器模板,对照着代码就很容易理解:
Python:
# 装饰器函数,本身也是个函数,其参数是被装饰的类或者函数(func) def decorator(func): # 装饰器所做的操作 def wrapper(*args, **kwargs): return func() return wrapper # 使用@ 关键字调用装饰器,修饰 function 函数 @decorator def function(): print("hello, decorator")
然后依据该模板,给出一个统计函数运行时间的装饰器函数例子:
Python:
import time # 定义一个装饰器,统计函数的运行时间 def run_time(func): def wrapper(*args, **kwargs): start = time.time() r = func(*args, **kwargs) # 这里就是待装饰的函数 print time.time() - start return r return wrapper # 调用装饰器 @run_time def test(n): print("特里斯丹") for i in range(n): print(i) return n
我们自己写代码的时候可能很少会写装饰器,这是因为装饰器不是必须的,就像上面打印函数运行时间的代码,我们完全可以在每个函数里记录和打印。
但是装饰器只需要写一次,就可以在很多函数上使用,这也是其优点所在:将实现特定的功能代码封装成装饰器,提高代码复用率,增强代码可读性,代码结构更加清晰
延伸考点
2. 本题旨在考察候选人对 python 的掌握程度,有没有系统地学习过 python 编程。
类似的概念还有Python 生成器、with 作用域等。
3. 说说你用到过的装饰器:
@torch.no_grad()
@functools.lru_cache(maxsize=128, typed=False)
2. Python 生成器
生成器是跟列表推导式对应的概念,举个简单的例子:
Python:
lst = [i for i in range(10)] # 列表推导式 gen = (i for i in range(10)) # 生成器表达 # 注意,上面两行的区别只有[] 和 () # 实际演示一下 In [1]: gen = (i for i in range(10)) In [2]: gen Out[2]: <generator object <genexpr> at 0x7fb0c0f0e048> In [3]: lst = [i for i in range(10)] In [4]: lst Out[4]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] In [5]: next(gen) # 访问生成器的每一个元素,使用 next Out[5]: 0 In [6]: next(gen) Out[6]: 1 In [7]: next(gen) Out[7]: 2 In [8]: for x in gen: ...: print(x) ...: 3 4 5 6 7 8 9
列表推导与生成器表达式都可以用于初始化元组、数组或其他类型的序列。
但列表推导需要先建立一个完整的列表,存储所有的元素,然后再把这个列表传递到某个构造函数。
而生成器表达式会逐个产出元素(使用next()方法),用一个生成一个,而不是全部生成之后再返回,从而减少内存损耗。
关于生成器,还有另一个用法,即生成器函数,关键字是yield,简单来说可以把return 换成yield,就会从普通函数变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
Python:
In [20]: def gen_print(n): ...: yield n ...: n += 1 ...: ...: yield n ...: n += 1 ...: In [21]: gen_fun = gen_print(10) In [22]: gen_fun Out[22]: <generator object gen_print at 0x7fb0d0272480> # 在每次调用next()的时候执行,遇到yield语句返回, # 再次执行时从上次返回的yield语句处继续执行。 In [23]: next(gen_fun) Out[23]: 10 In [24]: next(gen_fun) Out[24]: 11 In [25]:
延伸考点
本题旨在考察候选人对 python 的掌握程度,有没有系统地学习过 python 编程。
类似的概念还有Python 装饰器、with 作用域等。
3. 请你介绍const的用法
const是常量限定符,用来限定特定变量,以通知编译器该变量是不可修改的。使用const,可以避免在函数中对某些不应修改的变量造成可能的改动。
举几个例子,说明const的大致用法
C++:
const int a=10; //等价的书写方式: int const a=10; const int* a = & [1] //非常量数据的常量指针 指针常量 int const *a = & [2] //非常量数据的常量指针 a is a pointer to the constant char variable int* const a = & [3] //常量数据的非常量指针指针常量 常量指针 a is a constant pointer to the (non-constant) char variable const int* const a = & [4] //常量数据的常量指针
C++:
const int* a = & [1] //非常量数据的常量指针 指针常量 int const *a = & [2] //非常量数据的常量指针 a is a pointer to the constant char variable int* const a = & [3] //常量数据的非常量指针指针常量 常量指针 a is a constant pointer to the (non-constant) char variable const int* const a = & [4] //常量数据的常量指针
说明:
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;
如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。
因此,[1]和[2]的情况相同,都是指针所指向的内容为常量,这种情况下不允许对内容进行更改操作,如不能a = 3 ;
[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;
[4]为指针本身和指向的内容均为常量。
延伸考点
本题考察C++的基础知识,如果面试开发岗,就得认真准备了(“背八股”,可以在牛客网搜到很多面经)
类似的概念还有 static 关键字、#define 等
4. 请你说一下内联函数和虚函数
内联函数:
概念:C++内联函数通常与类一起使用,如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。对内联函数进行任何修改,都需要重新执行编译,因为编译器需要重新更换一个所有的代码,否则就会继续使用旧的函数。如果想把一个函数定义为内联函数,则需要在函数名前面放置关键字inline,在调用函数之前对函数进行定义。
内联函数仅仅是对编译器的内联建议,编译器是否觉得采取你的建议取决于函数是否符合内联的有利条件。如何函数体非常大,那么编译器将忽略函数的内联声明,而将内联函数作为普通函数处理。在类内定义的函数都是内联函数,即使没有使用inline关键字。
代码示例:
Plain Text:
#include <iostream> using namespace std; inline int Max(int x, int y) { return (x > y)? x : y; } // 程序的主函数 int main( ) { cout << "Max (20,10): " << Max(20,10) << endl; cout << "Max (0,200): " << Max(0,200) << endl; cout << "Max (100,1010): " << Max(100,1010) << endl; return 0; }
优点:
- 通过避免函数调用所带来的开销来提高程序的运行效率;
- 当函数调用发生时,节省了变量弹栈、压栈的开销;
- 避免了一个函数执行完返回原现场的开销;
- 通过将函数声明为内联,可以把函数定义放在头文件内。
缺点:
- 因为代码的扩展,内联函数增大了可执行程序的体积;
- C++内联函数的展开是在编译阶段,意味着如果内联函数发生了改动,那么要重新编译代码;
- 内联机制在嵌入式系统场景下并不受欢迎,嵌入式系统的存储约束可能不允许体积很大的可执行程序。
虚函数:
概念:
C++中,基类将类型相关的函数与派生类不做改变直接继承的函数区别对待。对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数(virtual function),方法为在函数返回类型前加上virtual关键字。C++11标准之后允许派生类显式的注明将使用哪个成员函数改写基类的虚函数,方法是在该函数的形参列表之后增加一个override关键字。
虚函数是用于C++的多态机制的实现,通过指向派生类对象的基类指针或者引用,来访问派生类中同名覆盖基类中的函数(声明为虚函数之后,能够在运行期识别出对象的动态类型,也就是基类指针或引用所绑定的究竟是基类对象,还是派生类对象)。
纯虚函数:虚函数的声明最后加上”=0”,即为纯虚函数,和虚函数在派生类各自实现自定义版本不同,纯虚函数只提供接口,不会被改写实现,具有纯虚函数的类称之为抽象类,无法被实例化。
虚函数代码示例:
Plain Text:
#include<iostream> using namespace std; class A { public: void print() { cout<<"This is A"<<endl; } }; class B : public A { public: void print() { cout<<"This is B"<<endl; } }; int main() // 该段程序output为“This is A”、“This is B”。 { A a; B b; a.print(); b.print(); return 0; } 纯虚函数代码示例: class Shape { protected: int width, height; public: Shape( int a=0, int b=0) { width = a; height = b; } // pure virtual function virtual int area() = 0; };
5. 怎么把csv文件导入java中,怎么处理数据,存储成什么格式?
概念:
csv是逗号分隔文件(comma separated values),是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件。在csv文件中,数据“栏”以逗号分隔,可允许程序通过读取文件为数据重新创建正确的栏结构,并在每次遇到逗号时开始新的一栏。
csv导入/导出java接口代码:
TypeScript:
package com.parami.utils; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.List; public class CSVUtils { /** * 导出 * @param file csv文件(路径+文件名),csv文件不存在会自动创建 * @param dataList 数据 * @return */ public static boolean exportCsv(File file, List<String> dataList){ boolean isSucess=false; FileOutputStream out=null; OutputStreamWriter osw=null; BufferedWriter bw=null; try { out = new FileOutputStream(file); osw = new OutputStreamWriter(out); bw =new BufferedWriter(osw); if(dataList!=null && !dataList.isEmpty()){ for(String data : dataList){ bw.append(data).append("\r"); } } isSucess=true; } catch (Exception e) { isSucess=false; }finally{ if(bw!=null){ try { bw.close(); bw=null; } catch (IOException e) { e.printStackTrace(); } } if(osw!=null){ try { osw.close(); osw=null; } catch (IOException e) { e.printStackTrace(); } } if(out!=null){ try { out.close(); out=null; } catch (IOException e) { e.printStackTrace(); } } } return isSucess; } /** * 导入 * @param file csv文件(路径+文件) * @return */ public static List<String> importCsv(File file){ List<String> dataList=new ArrayList<String>(); BufferedReader br=null; try { br = new BufferedReader(new FileReader(file)); String line = ""; while ((line = br.readLine()) != null) { dataList.add(line); } }catch (Exception e) { }finally{ if(br!=null){ try { br.close(); br=null; } catch (IOException e) { e.printStackTrace(); } } } return dataList; } }
csv文件导入导出单测代码:
TypeScript:
package junit.test; import java.io.File; import java.util.ArrayList; import java.util.List; import org.junit.Test; import com.parami.utils.CSVUtils; public class CsvTest { /** * CSV导出 * @throws Exception */ public void exportCsv() { List<String> dataList=new ArrayList<String>(); dataList.add("1,张三,男"); dataList.add("2,李四,男"); dataList.add("3,小红,女"); boolean isSuccess=CSVUtils.exportCsv(new File("D:/test/lidian.csv"), dataList); System.out.println(isSuccess); } /** * CSV导出 * @throws Exception */ public void importCsv() { List<String> dataList=CSVUtils.importCsv(new File("D:/test/lidian.csv")); if(dataList!=null && !dataList.isEmpty()){ for(String data : dataList){ System.out.println(data); } } } }
6. 使用pandas(Python)读取csv和excel文件内容
Pandas读取excel文件:
(1)首先创建一个excel文件,命名为test.xls
(2)安装pandas库(pandas是基本numpy的软件库)
pip install pandas
为了读取excel电子表格中的数据,我们还需要使用xlrd库:
pip install xlrd
(3)读取excel文件
Plain Text:
import pandas as pd file = “test.xls” data = pd.read_excel(file) print(data)
首先引入pandas模块,初始化一个变量file用于存储excel文件名,示例中并没有给出确切的文件路径,那么将文件放置于项目代码文件同级目录即可。
调用pandas的read_excel方法,将“text.xls”中的内容读取到变量data,最后在终端将data变量的内容打印出来。
(4)写入excel文件
这里需要用到xlwt:pip install xlwt
Plain Text:
import pandas as pd file = “text.xls” data = pd.read_excel(file) data.to_excel(“new.xls”, sheet_name = “Student”)
Pandas读取csv文件
(1)在读取的时候,默认会将第一行记录当成列名,如果没有列名,可以指定header = None
Plain Text:
import pandas as pd df = pd.read_csv(“test.csv”) #csv文件与py文件在同一级目录下 print(df.head(3)) #读取前三行
(2)在读取后自定义标题
Plain Text:
import pandas as pd df=pd.read_csv('test.csv') #hotelreviews50_1.csv文件与.py文件在同一级目录下 #在读数之后自定义标题 columns_name=['mysql_id','A','B','C','D','E','F','G','H'] df.columns=columns_name print(df.head(3)) #读取前3行
(3)使用pandas读取csv文件的指定列
Plain Text:
import pandas as pd df=pd.read_csv('test.csv',header=None,usecols=[0,1,2,3]) columns_name=['mysql_id','A','B','C'] df.columns=columns_name