在类里面定义的函数就是方法,类方法需要@ classmethod 修饰并且有个隐藏参数 cls,实例方法必须有个参数 self, 静态方法必须有 @staticmethod修饰,类和实例都可以访问静态方法,实
例可以访问实例方法也可以访问类方法,类可以访问类方法也可以访问实例方法,访问实例方法必须要带参数 self, 可以理解为类其实也是一个实例,类访问实例方法不带参数会报错的.类本
身可以访问函数,实例却不行.
机器学习中最小二乘法可以理解为就是通过最小化误差的平方和来寻找最佳的匹配函数。一般常用于曲线的拟合。
关于曲线的拟合,就是求出最佳的k,b的值来找出好的曲线实现好的分类效果。
一般情况下拟合的曲线为k*x+b一次函数,不过如果需要拟合的函数不是一次函数,就比较麻烦了。python的科学计算包scipy的里面提供了一个函数,可以求出任意的想要拟合的函数的参数。那就是scipy.optimize包里面的leastsq函数。函数原型是
leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=0.0, factor=100, diag=None, warning=True)
一般我们只要指定前三个参数就可以了:
func 是我们自己定义的一个计算误差的函数,
x0 是计算的初始参数值
args 是指定func的其他参数
一个简单的应用实例为:
import numpy as np import scipy as sp import matplotlib.pyplot as plt from scipy.optimize import leastsq ##样本数据(Xi,Yi),需要转换成数组(列表)形式 Xi=np.array([160,165,158,172,159,176,160,162,171]) Yi=np.array([58,63,57,65,62,66,58,59,62]) ##需要拟合的函数func :指定函数的形状 k= 0.42116973935 b= -8.28830260655 def func(p,x): k,b=p return k*x+b ##偏差函数:x,y都是列表:这里的x,y更上面的Xi,Yi中是一一对应的 def error(p,x,y): return func(p,x)-y #k,b的初始值,可以任意设定,经过几次试验,发现p0的值会影响cost的值:Para[1] p0=[1,20] #把error函数中除了p0以外的参数打包到args中(使用要求) Para=leastsq(error,p0,args=(Xi,Yi)) #读取结果 k,b=Para[0] print("k=",k,"b=",b) #画样本点 plt.figure(figsize=(8,6)) ##指定图像比例: 8:6 plt.scatter(Xi,Yi,color="green",label="样本数据",linewidth=2) #画拟合直线 x=np.linspace(150,190,100) ##在150-190直接画100个连续点 y=k*x+b ##函数式 plt.plot(x,y,color="red",label="拟合直线",linewidth=2) plt.legend() #绘制图例 plt.show()
在类里面定义的函数就是方法,类方法需要@ classmethod 修饰并且有个隐藏参数 cls,实例方法必须有个参数 self, 静态方法必须有 @staticmethod修饰,类和实例都可以访问静态方法,实
例可以访问实例方法也可以访问类方法,类可以访问类方法也可以访问实例方法,访问实例方法必须要带参数 self, 可以理解为类其实也是一个实例,类访问实例方法不带参数会报错的.类本
身可以访问函数,实例却不行.
转载于:https://www.cnblogs.com/jinyanjun/p/9636882.html
定义类及方法
class ParameterFactory(object): ..... def fullLinkTag(self, fromDate, toDate, status, cate='全部', op=''): ....... .......
在main文件中创建其实例
factory = ParameterFactory(cookie)
新建一个字典,根据业务需要传入中文名称,找到对应的函数名
funcdict = { "全链路状态" : factory.fullLinkTag, "搜索":factory.searchTag, "付费广告":factory.payAdvertising, "内容运营":factory.contentOperation, #"天猫营销平台":factory., "销售渠道":factory.salesChannel, #"线下触点":factory., #"istore小程序":factory., "店铺商品圈人":factory.shopGoods, "属性圈人":factory.attributeTag, "会员":factory.membership, "现有人群": factory.currentCrowdMarketing, }
以下是业务代码举例,包含调用的函数中文名及该函数需要的参数列表
call_setting = {'fun_name': '全链路状态', 'parameters': {'fromDate': 'T1加1', 'op': '交', 'status': '认知', 'toDate': 'T1加1'}}
动态函数调用成功!!!
- 关键可以通过在参数dict前面 添加 ** 两个星号**的形式实现
funcdict[call_setting['fun_name']](**parameters)
转载于:https://www.cnblogs.com/yeni/p/10484837.html
文章目录
一、类及其实例化
1、定义类
类要先声明后使用;不能声明两个名字相同的类,类是具有唯一标识符的实体;在类中声明的任何成员不能使用extern、auto、register关键字进行修饰;类中声明的变量属于该类,在某些情况下,变量也可以被该类的不同实例所共享;类中有数据成员和成员函数,不有在类声明中对数据成员使用表达式进行初始化。
⑴ 声明类
声明类以class开始,其后跟类名,类所声明的内容用花括号括起来,右括号后的分号作为类声明结束的标志。类成员具有访问权限,通过它前面的关键字来定义,关键字private后的成员叫私有成员、public后的成员叫公有成员、protected后的成员叫受保护的成员,访问权限用于控制对象的成员在程序中的可访问性。如果没有使用关键字,则所有成员默认声明为private权限。
class Point{//类名Point private://声明为私有访问权限 int x,y;//私有的数据成员 public://声明为公有的访问权限 void setXY(int a,int b); void move(int a,int b); void display(); int getX(); int getY(); };//声明以分号为结尾
⑵ 定义成员函数
#include <iostream> using namespace std; class Point{//类名Point private://声明为私有访问权限 int x,y;//私有的数据成员 public://声明为公有的访问权限 Point(){};//没有参数的构造函数 Point(int a,int b){//两个有参的构造函数 x = a; y = b; } void setXY(int a,int b);//函数声明 void display(); inline int getX();//声明为内联函数 int getY(){//在类体中定义函数,如果不包含循环或switch语句则默认为内联函数 return y; } };//声明以分号为结尾 //在类体外定义函数 void Point :: setXY(int a,int b){ x = a; y = b; } void Point :: display(){ cout << x << "," << y; } inline int Point :: getX(){//类体外定义内联函数 return x; }
一般在类体中给出简单成员函数的定义,在类中定义的函数如果不包含循环或switch语句会被系统默认当作内联函数来处理,函数体内容较多的函数则在类外定义,系统并不会把它们默认为内联函数,如果想把它们指定为内联函数,则应该使用inline进行显示声明。如果在类体外定义内联函数,需要把函数声明和函数定义放在同个源文件中才能编译成功。
在类体中直接定义函数时,不需要在函数名前加上类名,只有在类体外定义时才需要。其中,“::”是作用域运算符,它用于表明其后的成员函数是属于这个特定的类 。
⑶ 数据成员的赋值
不能在类体内给数据成员赋值,数据成员的具体值是用来描述对象属性的,只有产生了一个具体的对象,这些数据值才有意义。如果产生对象时就使对象的数据成员具有指定值,则称为对象的初始化。注意,初始化和赋初值是两个不同的概念,初始化是使用与Point同名的构造函数来实现的,赋初值是在有了对象A之后,对象A调用自己的数据成员或成员函数实现赋值操作。
int main(){ //构造函数初始化 Point a(10,20); //对象赋值 Point b; b.setXY(10,20); return 0; }
2、使用类的对象
只有产生类的对象,才能使用这些数据和成员函数。类不仅可以声明为对象,还可以声明为对象的引用和对象的指针。
//定义print函数的重载,分类使用类指针和类对象作为参数 void print(Point *a){//类指针作为参数重载print函数 a -> display(); } void print(Point &b){//类引用作为参数重载print函数 b.display(); } int main(){ //构造函数初始化 Point a(10,20); //对象赋值 Point b; b.setXY(10,20); Point *p1 = &a;//声明对象a的对象指针 Point &p2 = b;//声明对象b的对象引用 print(p1);//10,20 print(p2);//10,20 return 0; }
总结:
① 类的成员函数可以直接使用类的私有成员;
② 类外的函数不能直接使用类的私有成员;
③ 类外的函数只能通过类的对象使用该类的公有成员函数;
④ 对象的成员函数代码都是一样的,对象的区别只是属性的取值;
⑤ 在程序运行时,通过为对象分配内存来创建对象,为了节省内存,在创建对象时,只分配用于保存数据的内存,代码为每个对象共享,类中定义的代码被放在计算机内的一个公共区中供该类的所有对象共享;
⑥ 对象和引用在访问对象的成员时,使用运算符“.”,而指针则使用“->”运算符。
3、数据封装
面向对象程序设计是通过为数据和代码建立分块的内存区域,以便提供对程序进行模块化的程序设计方法,这些模块可以被用作样板,在需要时再建立副本。而对象是计算机内存中的一块区域,通过将内存分块,每个对象在功能上保持相对独立。这些内存块中不但存储数据,也存储代码,只有对象中的代码才可以访问存储于这个对象中的数据,这将保护它自己不受未知外部事件的影响,从而使自己的数据和功能不会遭到破坏。
在面向对象的程序中,只有向对象发送消息才能引用对象的行为,所以面向对象是消息处理机制,对象之间只能通过成员函数相互调用来实现相互通信。这样,对象之间相互作用的方式是受控制的,一个对象外部的代码就没有机会通过直接修改对象的内存区域妨碍对象发挥其功能。
面向对象就是将世界看成是一组彼此相关并能相互通信的实体即对象组成的,程序中的对象映射现实世界中的对象。
C++对其对象的数据成员和成员函数的访问是通过访问控制权限来限制的,一般情况下将数据成员说明为私有的,以便隐藏数据,将部分成员函数说明为公有的,用于提供外界和这个类的对象相互作用的接口,从而使得其他函数也可以访问和处理该类的对象。
二、构造函数
1、默认构造函数
没有定义构造函数,却可以使用类直接产生对象,原因是当没有为一个类定义任何构造函数的情况下,C++编译器总要自动建立一个不带参数的构造函数。默认的构造函数函数名与类名相同,函数体是空的,没有参数,也没有返回值,如果它有返回值,编译器就必须知道如何处理返回值,这样会大大增加编译器的工作,降低了效率。如果我们在程序中定义了自己的构造函数,系统就不再提供默认的构造函数。如果我们需要使用到无参的构造函数,则需要在显式的声明并定义一个无参的构造函数。
2、定义构造函数
#include <iostream> using namespace std; class Point{ private: int x,y; public: Point();//声明一个无参的构造函数 Point(int,int);//声明一个有两个参数的构造函数 }; Point :: Point(){//定义无参的构造函数 cout << "默认初始化对象" << endl; } Point :: Point(int a,int b):x(a),y(b){//定义两个参数的构造函数,x(a)相当于x = a,它跟下面的声明方式是等价的 cout << "初始化对象,属性x:" << a << ",属性y:" << b <<endl; } /*Point :: Point(int a,int b){ x = a; y = b; }*/ int main(){ Point a;//使用无参构造函数产生对象 Point b(10,20);//使用有参构造函数产生对象 Point c[2];//使用无参构造函数产生对象数组 Point d[2]={Point(15,25),Point(20,30)};//使用有参构造函数产生对象数组 /** * 初始化对象,属性x:10,属性y:20 * 默认初始化对象 * 默认初始化对象 * 初始化对象,属性x:15,属性y:25 * 初始化对象,属性x:15,属性y:25 */ }
3、构造函数和运算符new
运算符new用于建立生存期可控的对象,new返回这个对象的指针。当使用new建立一个动态的对象时,new将首先分配保证类的一个对象所需要的内存,然后自动调用构造函数来初始化这块内存,再返回这个动态对象的地址。
使用new建立的动态对象只能使用delete删除,以便释放所占空间。
Point *p1 = new Point(); Point *p2 = new Point(5,8); delete p1; delete p2; /** * 默认初始化对象 * 初始化对象,属性x:5,属性y:8 */
4、构造函数的默认参数
class Point1{ private: int x,y; public: Point1(int=0,int=0);//声明一个默认参数的构造函数,使用默认参数的构造函数就不能再声明无参的构造函数 }; Point1 :: Point1(int a,int b):x(a),y(b){//定义两个参数的构造函数 cout << "初始化对象,属性x:" << a << ",属性y:" << b <<endl; } int main(){ Point1 a; Point1 b(10,25); }
5、复制构造函数
引用在类中可以用在复制构造函数中,编译器建立一个默认复制构造函数,然后采用拷贝式的方法使用已有的对象来建立新对象。复制构造函数必须使用对象的引用为形式参数,为了安全起见,建议使用const限定符。
class Point2{ private: int x,y; public: Point2(); Point2(const Point2&);//声明带const限定符的复制构造函数 }; Point2 :: Point2():x(12),y(20){ cout << "初始化对象,属性x:" << x << ",属性y:" << y <<endl; } Point2 :: Point2(const Point2 &p){ x = p.x;//一个类中定义的成员函数可以访问该类任何对象的私有成员 y = p.y; cout << "初始化对象,属性x:" << x << ",属性y:" << y <<endl; }; int main(){ Point2 a; Point2 b(a); /** * 初始化对象,属性x:12,属性y:20 * 初始化对象,属性x:12,属性y:20 */ }
三、析构函数
在对象消失时,应使用析构函数释放由构造函数分配的内存。构造函数、复制构造函数和析构函数是构造型成员函数的基本成员。
1、定义析构函数
析构函数的函数名称与类名一样,为了与构造函数进行区分,在析构函数的前面加一个“~”号。在定义析构函数时,不能指定任何返回类型,也不能指定任何参数,但是可以显式的声明参数为void,即A::~A(void),一个类只能定义一个析构函数。
void example3(); class Point3{ private: int x,y; public: Point3(int,int);//声明两个参数的构造函数 ~Point3();//声明析构函数 }; Point3 :: Point3(int a,int b):x(a),y(b){//定义两个参数的构造函数 cout << "Initializing" << endl; } Point3 :: ~Point3(){ cout << "Destructor is active" << endl; } int main(){ example3(); return 0; } void example3(){ Point3 a(10,20);//通过构造函数实例化一个对象 cout << "Exiting main function" << endl; /** * Initializing //创建对象时调用构造函数 * Exiting main function //在程序结束之前调用析构函数 * Destructor is active //程序自动调用构造函数 */ }
当对象的生命周期结束时,程序为这个对象自动调用析构函数,然后回收这个对象占用的内存。全局对象和静态对象的析构函数在程序运行结束之前调用。类的对象数组的每个元素调用一次析构函数。全局对象的析构函数在程序结束之前被调用。
如果在定义类时没有定义析构函数,C++编译器也要为它产生一个函数体为空的默认析构函数。
2、析构函数和运算符delete
运算符delete与析构函数一起工作,当使用运算符delete删除一个动态对象时,它首先为这个动态对象调用析构函数,然后再释放这个动态对象占用的内存,这与使用new建立动态对象的过程刚好相反。
void example4(); class Point3{ private: int x,y; public: Point3(int=0,int=0);//声明两个参数的构造函数 ~Point3();//声明析构函数 }; Point3 :: Point3(int a,int b):x(a),y(b){//定义两个参数的构造函数 cout << "Initializing" << a << "," << b << endl; } Point3 :: ~Point3(){ cout << "Destructor is active" << endl; } int main(){ example4(); return 0; } void example4(){ Point3 *p = new Point3[2];//创建对象数组 delete [] p;//动态删除对象 /** * Initializing0,0 * Initializing0,0 * Destructor is active * Destructor is active */ }
当使用delete释放动态对象数组时,必须告诉它这个动态对象数组有几个元素对象,C++使用“[]”来实现 。然后,delete将为动态数组的每个对象调用一次析构函数,并释放内存。
当程序先后创建几个对象时,系统将按照先创建后析构的原则进行析构对象,当使用delete调用析构函数时,则按delete的顺序析构。
四、this指针
在定义Point类的对象a之后,当执行语句“a.getX()”时,计算是怎么知道获取哪个对象的值呢?其实成员函数getX()有一个隐藏参数,名为this指针,当源程序被编译后,getX()的实际形式如下:
int Point :: getX((Point*)this){ return this -> x; }
五、一个类的对象作为另一个类的成员
void example9(); class Desk{ private: int num;//数量 public: void setNum(int a){ num = a; } int getNum(){ return num; } }; class Bed{ private: int num;//数量 public: void setNum(int a){ num = a; } int getNum(){ return num; } }; class House{ private: Desk d; Bed b; public: void setHouse(Desk &d,Bed &b){ this -> d = d; this -> b = b; } int getTotal(){ return d.getNum() + b.getNum(); } }; int main(){ example9(); return 0; } void example9(){ Bed b; b.setNum(2); Desk d; d.setNum(5); House h; h.setHouse(d,b); cout << "屋子里一共有" << h.getTotal() << "件家具!"; /** * 屋子里一共有7件家具! */ }