类,封装

一,面向对象

面向过程:
优点:复杂的过程流程化,简单化
缺点:可扩展性差
举例:linux中shell编译安装,这种固定的流程,面向过程方式堆积命令即可


面向对象:对象是特征与技能的合体
优点:可扩展性强
缺点:编程复杂难度高,容易出现过度设计




二,类

1,类的定义


在程序中:一定先有类再有对象
对象可以访问到类中共有的数据与功能,所以类中的内容仍然是属于对象的;
类只不过是一种节省空间、减少代码冗余的机制,面向对象编程最终的核心仍然是去使用对象。



class Student:
    beauty='mzz'
    def learning(self):
        print('mzz like to study')
    print('----->running')

# ----->running会在"类"定义阶段执行

# 查看类的内存空间
print(Student.__dict__)
# {'__module__': '__main__', 'beauty': 'mzz', 'learning': <function Student.learning at 0x102c43e50>, '__dict__': <attribute '__dict__' of 'Student' objects>, '__weakref__': <attribute '__weakref__' of 'Student' objects>, '__doc__': None}




print(Student.beauty)    # 数据类型(变量)
# mzz
print(Student.learning)     # 函数属性
# <function Student.learning at 0x103063e50>
# 类调用的learning是一个函数,所以要按照函数的调用方式,即要加上self这个参数

Student.learning('mzz')
# ----->running
# mzz like to study








# 增加
Student.counry="China"
print(Student.counry)
# China


# 修改
Student.beauty="Egg"
print(Student.beauty)
# Egg


# 删除
del Student.counry
#print(Student.counry) # 会报错,已经删除

# 查看类的内存空间验证,没有country
print(Student.__dict__)

2,类的实例化过程

# 调用类的过程又称实例化
#1)得到一个返回值,即对象,该对象是一个空对象
#2) Student.__init__,把类当作第一个参数传进去
class Student:
    beauty='mzz'

    def __init__(self,name,age,sex):  # 在调用时自动触发
        self.Name=name
        self.Age=age
        self.Sex=sex

    def learning(self):
        print('mzz like to study')


s1=Student('mz',13,'female')
print(s1.__dict__)
# {'Name': 'mz', 'Age': 13, 'Sex': 'female'}

print(s1.Sex)
# female


s2=Student('egon',22,'male')
print(s2.Name)
# egon


3,属性查找与绑定方法

#1, 查找一个对象的属性,先找自己的__dict__,再找类的__dict__
class Student:
    school='Asia'

    def __init__(self,name,age,sex):  # 在调用时自动触发
        self.Name=name
        self.Age=age
        self.Sex=sex

    def learning(self):
        print('%s like to study' %self.Name)

s1=Student('mz',13,'female')
s2=Student('egon',22,'male')





#2, 类的数据属性是所有对象共享,所有对象都指向同一个内存地址
print(Student.school,id(s1.school))
# Asia 4303951152
print(Student.school,id(s2.school))
# Asia 4303951152



Student.school='India'
print(Student.school,id(s1.school))
# India 4383185008
print(Student.school,id(s2.school))
# India 4383185008









#3, 类中定义的函数是绑定给对象使用,类也可以使用(用起来会很复杂)
# 不同对象就是不同绑定方法
# 绑定给谁,就应该给谁调用

print(Student.learning)
# <function Student.learning at 0x10029f790>
print(s1.learning)
# <bound method Student.learning of <__main__.Student object at 0x10025dfa0>>
print(s2.learning)
# <bound method Student.learning of <__main__.Student object at 0x1002962b0>>


s1.learning()
# mz like to study
s2.learning()
# egon like to study






# 接上验证,函数属性的绑定方法
class Student:
    school='Asia'

    def __init__(self,name,age,sex):  # 在调用时自动触发
        self.Name=name
        self.Age=age
        self.Sex=sex

    def learning(self,x,y):
        print('%s like to study' %self.Name)
        print(x,y)


s1=Student('mz',13,'female')
s2=Student('egon',22,'male')

s1.learning(1,2)
# mz like to study
# 1 2


s2.learning(1,2)
# egon like to study
# 1 2


#类也可以使用(用起来会很复杂)
Student.learning(s1,1,2)
# mz like to study
# 1 2



类的函数属性调用默认必须要有一个参数

示例

# 示例:任何一个老师都可以看到老师的个数
class Teacher:
    school='Asia'
    count=0

    def __init__(self,name,sex,age,level,salary):
        self.name=name
        self.age=age
        self.level=level
        self.salary=salary
        Teacher.count+=1

    def teach(self):
        print('%s is teaching' %self.name)


t1=Teacher('小艾','male',20,1,3000)
t2=Teacher('小林','male',21,2,4000)
t3=Teacher('小狗','female',23,3,5000)


# 查看Teacher数量
print(t1.count)
print(t2.count)
print(t3.count)
# 3   都是3

4,类和对象

a1=list([1,2,3,4])
a2=list([1,2,3,4])
print(id(a1))
# 4343027392

print(id(a2))
# 4343027456

a1.append('a')
a2.append('b')

print(a1)
# [1, 2, 3, 4, 'a']

print(a2)
# [1, 2, 3, 4, 'b']

python中,一切皆对象,类型本质都是类。
数据类型都是一个个类创造的对象

-- 游戏中生命值攻击力示例

class Dog:
    camp='A' #所有类里面的(xiaohua)都属于A组
    def __init__(self,name,life_value=200,attack_value=10):
    # 初始生命值200,初始攻击力10
        self.name=name
        # 赋值,前面的name可以任意起名
        self.life_value=life_value
        self.attack_value=attack_value
    def attack(self,enemy):   # 攻击技能
        enemy.life_value-=self.attack_value
        # 敌人的生命力=敌人的生命力减去自己的攻击力

class Cat:
    camp='B'
    def __init__(self,name,life_value=100,attack_value=80):
        self.name=name
        self.life_value=life_value
        self.attack_value=attack_value
    def attack(self,enemy):
        enemy.life_value-=self.attack_value

xiaohua=Dog('xiaohua')
mimi=Cat('mimi')


print(xiaohua.life_value)
# 200

mimi.attack(xiaohua)
print(xiaohua.life_value)
# 120

5,代码级别看面向对象

# 伪代码示例

#1、在没有学习类这个概念时,数据与功能是分离的
def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name):
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

#每次调用都需要重复传入一堆参数
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')



#2、我们能想到的解决方法是,把这些变量都定义成全局变量
HOST=‘127.0.0.1’
PORT=3306
DB=‘db1’
CHARSET=‘utf8’

def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
exc2(HOST,PORT,DB,CHARSET,'存储过程的名字')





#3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用,然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合到一起的解决方法,这就是我们说的类了

class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
    def exc1(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.execute(sql)
        return res


    def exc2(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.call_proc(sql)
        return res


三,封装

1,隐藏属性

# 正常情况下,x可以通过调用Foo正常访问
class Foo:
    x=1

    def __init__(self,name,age):
        self.name=name
        self.age=age

print(Foo.x)
# 1

abc=Foo('dog',3)
print(abc.age)
# 3





# 隐藏属性,在需要隐藏属性的前面加上__(两个下划线)
# 隐藏属性是在调用阶段生成,所以在类内部是可以直接访问双下滑线开头的属性的
class Foo:
    __x=1

    def __init__(self,name,age):
        self.name=name
        self.age=age


#print(Foo.x)  会报错

obj=Foo('mzz',18)
print(obj.name,obj.age)
# mzz 18



class Foo:
    __x=1

    def __init__(self,name,age):
        self._name=name
        self._age=age

print(Foo.__dict__)
# {'__module__': '__main__', '_Foo__x': 1, '__init__': <function Foo.__init__ at 0x10304f790>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}

# 根据属性的变形,通过以下方式可以得到隐藏的属性的值
print(Foo._Foo__x)
# 1


2,为什么使用隐藏属性




class People:
    def __init__(self,name):
        self.__name=name



#People.get_name('mmm')   # 会报错

obj=People('muzz')
#print(obj.set_name())   # 会报错


class People:
    def __init__(self,name):
        self.__name=name

    def get_name(self):
        # 类似于开个接口,可以赋予其他的东西
        print('谁是小可爱')
        print(self.__name)

obj=People('muzz')
obj.get_name()
# 谁是小可爱
# muzz


# 类的创造者,可以严格控制使用者对属性的操作
class People:
    def __init__(self,name):
        self.__name=name

    def get_name(self):
        # 类似于开个接口,可以赋予其他的东西
        print('不给看')

obj=People('muzz')
obj.get_name()
# 不给看



# 如果更改名字,如下
class People:
    def __init__(self,name):
        self.__name=name

    def get_name(self):
        print(self.__name)

    def set_name(self,val):
        self.__name=val

obj=People('muzz')
obj.set_name('egon')
obj.get_name()
# egon





# 增加条件
class People:
    def __init__(self,name):
        self.__name=name

    def get_name(self):
        print(self.__name)

    def set_name(self,val):
        if type(val) is not str:
            print('必须字符串类型')
            return
        self.__name=val

obj=People('muzz')
obj.set_name(12235)
obj.get_name()
# 必须字符串类型
# muzz


3,property装饰器

1)用法一
"""
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
  体质指数(BMI)=体重(kg)÷身高^2(m)
  EX:70kg÷(1.75×1.75)=22.86
"""


# 例1:传值给People,得到ami的值需要obj.ami(),即调用函数的方式
class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height

    def ami(self):
        print(self.weight / (self.height **2))

obj=People('mzz',55,1.70)
print(obj.ami())
# 19.031141868512112
# None

obj.ami()
# 19.031141868512112






# 例2:加上@property 可以正常以obj.ami方式调用
class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.weight=weight
        self.height=height

    @property
    def ami(self):
        print(self.weight / (self.height **2))

obj=People('mz',55,1.70)
obj.ami
# 19.031141868512112


2)用法2
# property用法2
class People:
    def __init__(self, name):
        self.__name = name

    def get_name(self): # obj1.name
        return self.__name

    def set_name(self, val): # obj1.name='EGON'
        if type(val) is not str:
            print('必须传入str类型')
            return
        self.__name = val

    def del_name(self): # del obj1.name
        del self.__name

    name=property(get_name,set_name,del_name)

obj=People('eggg')
print(obj.name)

obj.set_name('EGGG')
print(obj.name)
#EGGG

obj.del_name()
print(obj.name) # 会报错

3) 用法3 (建议)
# property用法3
class People:
    def __init__(self, name):
        self.__name = name

    @property
    def name(self): # obj1.name
        return self.__name

    @name.setter
    def name(self, val): # obj1.name='EGON'
        if type(val) is not str:
            print('必须传入str类型')
            return
        self.__name = val

    @name.deleter
    def name(self): # del obj1.name
        print('不让删除')
obj=People('mz')
print(obj.name)
# mz

obj.name=12
# 必须传入str类型

obj.name='xiaohua'
print(obj.name)
# xiaohua

del obj.name
# 不让删除




注意def name的name要统一
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容