python面向对象,类,以及连接数据库

## 面向对象

### 1.面向对象三大特性: 封装,继承,多态

### 1.1.封装

1.在类中对数据的赋值、内部调用对外部用户是透明的

2.这使类变成了一个胶囊或容器,里面包含着类的数据和方法

3.作用

  1)防止数据被随意修改

   2)使外部程序不需要关注对象内部的构造,只需要通过对外提供的接口进行直接访问


## 2.继承

### 2.1.单继承

在程序中,继承描述的是多个类之间的所属关系。

如果一个类A里面的属性和方法可以复用,则可以通过继承的方式,传递到类B里。

那么类A就是基类,也叫做父类;类B就是派生类,也叫做子类。


### 2.2.多继承

**子类从多个父类派生,而子类又没有自己的构造函数时,**

**(1)按顺序继承,哪个父类在最前面且它又有自己的构造函数,就继承它的构造函数;**

**(2)如果最前面第一个父类没有构造函数,则继承第2个的构造函数,第2个没有的话,再往后找,以此类推。**


### 2.3.子类重写父类的同名属性和方法

#####   如果子类和父类的方法名和属性名相同,则默认使用子类的  叫 子类重写父类的同名方法和属性


### 2.4.子类调用父类方法

#####  无论何时何地,self都表示是子类的对象。在调用父类方法时,通过传递self参数,来控制方法和属性的访问修改。


### 1.3. 多态(接口重用)

   1.多态是面向对象的重要特性,简单点说:“一个接口,多种实现”

    2. 指一个基类中派生出了不同的子类,且每个子类在继承同样的方法名的同时又对父类的方法做了不同的实现

    3. 这就是同一种事物表现出的多种形态

    4. 比如黄种人继承了人talk这个功能,但是他说的是中文,而美国人的talk是英文,但是他们是同样的talk

***\*作用:\****简单的讲就是允许父类调用子类的方法


### 2.静态方法、类方法、属性方法  魔法方法

### 1.静态方法

1. 作用:静态方法可以更好的组织代码,防止代码变大后变得比较混乱。 

2. 特性: 静态方法只是名义上归类管理,实际上在静态方法里访问不了类或则实例中的任何属性

3. 静态方法使用场景:

    1)我们要写一个只在类中运行而不在实例中运行的方法.

    2)经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法.

    3)比如更改环境变量或者修改其他类的属性等能用到静态方法.

    4)这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.

4. 调用方式: 既可以被类直接调用,也可以通过实例调用

class aaa():

    def__init__(self,name):

       self.name = name

   @staticmethod        #返回函数的静态方法

    def eee():

       print("心如花木,向阳而生")

a = aaa

a.eee()                  #方法1:使用实例调用

aaa.eee()                #方法2:使用类直接调用

返回结果:

心如花木,向阳而生

心如花木,向阳而生


### 2.类方法

1. 作用:无需实例化直接被类调用 

2. 特性: 类方法只能访问类变量,不能访问实例变量

3. 类方法使用场景: 当我们还未创建实例,但是需要调用类中的方法

4. 调用方式: 既可以被类直接调用,也可以通过实例调用

class aaa():

    name = '类变量'      #在这里如果不定义类变量仅定义实例变量依然报错

    def__init__(self,name):

       self.name = name    #实例变量

    @classmethod   #是用来指定一个类的方法为类方法

    defeat(self,food):

       print("%s is eating %s"%(self.name,food))

aaa.eat('baozi')          #方法1:使用类直接调用

d = aaa

d.eat("包子")            #方法2:使用实例d调用

返回结果

类变量is eating baozi

类变量 is eating 包子


### 3. 属性方法

作用:属性方法把一个方法变成一个属性,隐藏了实现细节,调用时不必加括号直接d.eat即可调用self.eat()方法

class aaa():

    def__init__(self, name):

       self.name = name

   @property             #@property是python的一种装饰器,是用来修饰方法的。

    defeat(self):

       print(" %s在跳舞" % self.name)

d = aaa("1111111")

d.eat                     #不加()

# 调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了,

# 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了

返回结果

1111111 在跳舞


### 4. 魔法方法

### 1._ _ _init_ _ _ 方法

 在Python中定义类经常会用到__init__函数(方法),首先需要理解的是,两个下划线开头的函数是声明该属性为私有,不能在类的外部被使用或访问。而__init__函数(方法)支持带参数类的初始化,也可为声明该类的属性(类中的变量)。__init__函数(方法)的第一个参数必须为self,后续参数为自己定义。


### 2. __ _str_ _ _方法

__str__方法是用来显示信息的,通常是用来返回一个字符串,作为这个实例对象的描述信息,它只有一个参数,需要return一个数据,当你在类的外部打印实例对象的时候则会打印这个数据,在使用print(对象)或者str(对象)的时候会触发此方法。


### 3._ __new_ _ _方法

大家刚才看到了这个__init__方法的效果,肯定都会认为这个方法是类中第一个执行的方法,其实并不然,我们的类最开始调用的是__new__方法,它的第一参数是它的类对象,其他的参数则是传递给__init__方法的,,_new__方法可以调用其他的类的方法或者返回别的实例来作为当前类的实例,所以如果__new__方法没有返回实例,那么__init__方法就不会被调用,所以__new__方法决定了__init__方法是否使用,也可以说实例就是__new__方法创建的。__new__方法的主要用途是当你继承了一些不可更改的属性的时候,给你提供一个途径去修改它。


### 4._ _call _ _方法

__call__方法可以是类的实例对象能像调用函数那样使用对象。它的作用是简化了对象下方法的使用,模糊了对象和函数调用时的区别。


### __5. _ _ dir _ ___方法

熟悉python的人都知道dir()方法可以让我们查看当前环境下有些什么样的方法和属性可以使用,通过dir(object)可以获得一个对象拥有的方法和属性,同样的道理,如果我们自己在类中定义了这个__dir__方法,我们就可以指定一些别人能够被调用的方法,你的协同开发者就可以通过调用dir()方法查看到并使用。


### 1. PyMySQL介绍

PyMySQL

是在Python3.x版本中用于连接MySQL服务器的一个库


### 2. PyMysql

使用流程

![20190807115104-pymysql

流程.jpeg](https://raw.githubusercontent.com/bookandmusic/images/master/gitnote/20190807115104-pymysql%E6%B5%81%E7%A8%8B.jpeg)

- pymysql

使用步骤:==核心类 Connect链接用  和Cursor读写用==

1.与数据库服务器建立链接

2.获取游标对象 (用于发送和接收数据)

3.用游标执行sql语句

4.使用fetch方法来获取执行的结果

5.关闭链接  先关游标再关链接

==

连接数据库注意事项==:

有一个MySQL数据库,并且已经启动。

有可以连接数据库的用户名和密码。

有一个有权限操作的database。


### 3.引入模块

在py文件中引入pymysql模块

```python

from pymysql import *


### 4. Connection对象

用于建立与数据库的连接

创建对象:调用connect()方法

```python

conn=connect(参数列表)

参数host:连接的mysql主机,如果本机是'localhost'

参数port:连接的mysql主机的端口,默认是3306

参数database:数据库的名称

参数user:连接的用户名

参数password:连接的密码

参数charset:通信采用的编码方式,推荐使用utf8


####对象的方法

- close()

关闭连接

- commit()

提交

- cursor()

返回Cursor对象,用于执行sql语句并获得结果


### 5. Cursor对象

用于执行sql语句,使用频度最高的语句为select、insert、update、delete

获取Cursor对象:调用Connection对象的cursor()方法

```python

cs1=conn.cursor()


####对象的方法

- close()关闭

- execute(operation [, parameters ])

执行语句,返回受影响的行数,主要用于执行insert、update、delete语句,也可以执行create、alter、drop等语句

- fetchone()执行查询语句时,获取查询结果集的第一个行数据,返回一个元组

- fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回


####对象的属性

- rowcount只读属性,表示最近一次execute()执行后受影响的行数

- connection获得当前连接对象


### 6. ==单例模式==实现增删改查

####准备数据

创建 "京东" 数据库sql

create database jing_dong charset=utf8;

使用 "京东" 数据库sql

use jing_dong;

创建一个商品goods数据表sql

create table goods(

    id int unsigned primary keyauto_increment not null,

    name varchar(150) not null,

    cate_name varchar(40) not null,

    brand_name varchar(40) notnull,

    price decimal(10,3) not null default0,

    is_show bit not null default 1,

    is_saleoff bit not null default0

);


插入数据

```sql

insert into goods values(0,'r510vc 15.6

英寸笔记本','笔记本','华硕','3399',default,default);

insert into goods values(0,'y400n 14.0

英寸笔记本电脑','笔记本','联想','4999',default,default);

insert into goods values(0,'g150th 15.6

英寸游戏本','游戏本','雷神','8499',default,default);

insert into goods values(0,'x550cc 15.6

英寸笔记本','笔记本','华硕','2799',default,default);

insert into goods values(0,'x240

超极本','超级本','联想','4880',default,default);

insert into goods values(0,'u330p 13.3

英寸超极本','超级本','联想','4299',default,default);

insert into goods values(0,'svp13226scb

触控超极本','超级本','索尼','7999',default,default);

insert into goods values(0,'ipad mini 7.9

英寸平板电脑','平板电脑','苹果','1998',default,default);

insert into goods values(0,'ipad air 9.7

英寸平板电脑','平板电脑','苹果','3388',default,default);

insert into goods values(0,'ipad mini

配备 retina 显示屏','平板电脑','苹果','2788',default,default);

insert into goods values(0,'ideacentre c340 20

英寸一体电脑','台式机','联想','3499',default,default);

insert into goods values(0,'vostro 3800-r1206

台式电脑','台式机','戴尔','2899',default,default);

insert into goods values(0,'imac me086ch/a 21.5

英寸一体电脑','台式机','苹果','9188',default,default);

insert into goods values(0,'at7-7414lp

台式电脑 linux )','台式机','宏碁','3699',default,default);

insert into goods values(0,'z220sff f4f06pa

工作站','服务器/工作站','惠普','4288',default,default);

insert into goods values(0,'poweredge ii

服务器','服务器/工作站','戴尔','5388',default,default);

insert into goods values(0,'mac pro

专业级台式电脑','服务器/工作站','苹果','28888',default,default);

insert into goods values(0,'hmz-t3w

头戴显示设备','笔记本配件','索尼','6999',default,default);

insert into goods values(0,'

商务双肩背包','笔记本配件','索尼','99',default,default);

insert into goods values(0,'x3250 m4

机架式服务器','服务器/工作站','ibm','6888',default,default);

insert into goods values(0,'

商务双肩背包','笔记本配件','索尼','99',default,default);


#### pymysql交互

```python

import pymysql

class PyMysql(object):

    __isinstance = None

    def __new__(cls, *args,**kwargs):

        if cls.__isinstance isNone:

            cls.__isinstance =object.__new__(cls)

        return cls.__isinstance

    def __init__(self, database,host="localhost", port=3306, user="root",password="mysql", charset="utf8"):


连接数据库

        :param database:

数据库名

        :param host:

主机IP,默认本机

        :param port:

主机端口,默认3306

        :param user:

主机账户,默认root

        :param password:

主机密码,默认mysql

        :param charset:

数据库编码,默认utf8

        try:

            self.db =pymysql.connect(host=host, port=port, user=user, password=password,database=database,

                                     charset=charset)

            self.cs =self.db.cursor()

        except Exception as e:

            print("

数据库连接发生异常,详细信息为:", e)

            exit()

    def query(self, sql):


查询数据

        :param sql:

查询的sql语句

        :return: None

        try:

            count =self.cs.execute(sql)

        except Exception as e:

            print("查询失败,详细信息为:", e)

            return

        #查询一行数据

        # result =self.cs.fetchall()

        #查询多行数据

        result = self.cs.fetchall()

        if count != 0:

            print("

共查到%d条数据:" % count)

            for i in result:

                print(i)

        else:

            print("没有查到有效的数据")

    def change_data(self, sql):


修改数据: 增、删、改

        :param sql:

        :return:

        #执行sql语句,并返回受影响的行数

        try:

            count = self.cs.execute(sql)

            self.db.commit()

        except Exception as e:

            print("修改数据失败,详细信息为:", e)

        else:

            #提交之前的操作,如果之前已经之执行过多次的execute,那么就都进行提交

            print("%d条数据被修改成功" % count)

    def __del__(self):

        self.db.close()

        self.cs.close()

db = PyMysql("jing_dong")

db.query("select * from goods;")


### 7. sql注入

#### 1. SQL注入

SQL

注入是非常常见的一种网络攻击方式,主要是通过参数来让 mysql 执行 sql 语句时进行预期之外的操作。

即:因为传入的参数改变SQL的语义,变成了其他命令,从而操作了数据库。

产生原因:SQL语句使用了动态拼接的方式。

例如,下面这段代码通过获取商品id为1的详细信息:

```python

from pymysql import *

#创建Connection连接

conn = connect(host='localhost', port=3306, user='root', password='mysql',database='jing_dong', charset='utf8')

#获得Cursor对象

cs1 = conn.cursor()

#利用字符串拼接,容易产生sql注入

qid = '1'

sql = 'select * from goods where id=' + qid +';'

# print(sql)

count = cs1.execute(sql)

result = cs1.fetchall()

for i in result:

    print(i)

但是,如果传入参数是:

```python

qid = "1 or 1=1"

你会发现,用户能够获取所有商品信息,因为原本 sql 语句的判断条件被 or 短路成为了永远正确的语句。这里仅仅是举一个例子,事实上,sql 注入的方式还有很多种,这里不深入介绍了。总之,只要是通过用户输入数据来拼接 sql 语句,就必须在第一时间考虑如何避免 SQL 注入问题。那么,如何防止 SQL 注入呢?


#### 2.预防 SQL 注入 – pymysql 参数化语句

pymysql的 execute 支持参数化 sql,通过占位符 %s 配合参数就可以实现 sql 注入问题的避免。

```python

import pymysql

#创建Connection连接

conn=connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')

#获得Cursor对象

cs1 = conn.cursor()

# sql语句的参数化,可以有效防止sql注入

sql = 'select * from goods where id=%s'

qid = '1'

count = cursor.execute(sql, qid)

result = cursor.fetchone()

print(result)

这样参数化的方式,让 mysql 通过预处理的方式避免了sql 注入的存在。

需要注意的是,不要因为参数是其他类型而换掉 %s,pymysql的占位符并不是 python 的通用占位符。

同时,也不要因为参数是 string 就在 %s 两边加引号,mysql 会自动去处理。

你可能感兴趣的:(python面向对象,类,以及连接数据库)