python_面向对象进阶(7)

第1章 面向对象特性—继承(补充)
1.1 接口类、抽象类介绍 
1.2 接口类
1.3 接口类应用过程
1.3.1 第一版:完成多种支付方式接口
1.3.2 第二版: 归一化设计,统一支付方式
1.3.3 第三版:野生程序员的乱搞
1.3.4 第四版:制定规范,统一方法名
1.3.5 第五版本:强制性制定规定
1.4 抽象类
1.4.1 解释:
1.4.2 为什么要有抽象类
1.4.3 抽象类实际应用理论
1.4.4 抽象类的使用方法
1.5 接口类和抽象类的区别
1.6 继承注意问题
第2章 面幸对象特征—多态
2.1 鸭子类
2.2 多态实例
第3章 面向对象特征—封装
3.1 封装定义
3.2 广益封装
3.3 狭义封装
3.3.1 特点
3.3.2 1)私有静态字段(静态变量)
3.3.3 私有字段外部调用方法
3.3.4 私有字段内部访问方式
3.3.5 2)私有普通变量(私有对象属性)
3.3.6 3)私有方法
3.3.7 4)私有成员实际应用
第4章 面向对象进阶
4.1 面向对象整体结构及成员
4.1.1 字段:
4.1.2 方法:
4.1.3 属性
4.2 @peroperty
4.2.1 将方法变为属性
4.2.2 私有属性的外部显示
4.2.3 @age.setter修改私有属性
4.2.4 自动触发的三要素
4.2.5 peroperty匹配的三种方法
4.3 类方法:
4.3.1 @classmethod
4.3.2 静态方法直接引用@staticmethod
4.4 *****getattr()反射
4.4.1 在类中
4.4.2 在对象中
4.4.3 在模块中
4.4.4 在当前模块中
4.4.5 通过字符串去到 类名 中取值
4.4.6 hasattr/ getattr/ setattr/ delattr
4.5 *****hasattr()
4.6 其他方法
4.6.1 isinstance()
4.6.2 issubclass()
4.7 __len__
4.8 __hash__
4.9 __str__
4.10 __repr__
4.11 ***__call__
4.12 __eq__
4.13 __del__
4.14 ****__new__
4.15 __item__

 

 

第1章 面向对象特性—继承(补充)

1.1 接口类、抽象类介绍

解释:接口类和抽象类是一种规范,写代码时的规范

1.2 接口类

继承有两种用途:

l  继承基类的方法,并且做出自己的改变或者扩展(代码重用) 

l  声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能

实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。

继承的第二种含义非常重要。它又叫“接口继承”。

接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。

1.3 接口类应用过程

1.3.1 第一版:完成多种支付方式接口

class QQpay:

    def pay(self,money):

        print('您已经通过qq支付了%s元' %money)

 

class Alipay:

    def pay(self,money):

        print('您已经通过支付宝支付了%s元' %money)

 

a = QQpay()

b = Alipay()

 

a.pay(100)

b.pay(200)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

您已经通过qq支付了100元

您已经通过支付宝支付了200元

缺点:

       若果十个支付方式.py()支付方式不统一,写了十次太麻烦

1.3.2 第二版: 归一化设计,统一支付方式

class QQpay:

    def pay(self,money):

        print('您已经通过qq支付了%s元' %money)

 

class Alipay:

    def pay(self,money):

        print('您已经通过支付宝支付了%s元' %money)

 

def pay(obj,money):

    obj.pay(money)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

您已经通过qq支付了100元

您已经通过支付宝支付了200元

缺点:确实统一了支付方式,但是新增接口时并无任何提示,及相关接口的保护

1.3.3 第三版:野生程序员的乱搞

class QQpay:

    def pay(self,money):

        print('您已经通过qq支付了%s元' %money)

 

class Alipay:

    def pay(self,money):

        print('您已经通过支付宝支付了%s元' %money)

 

class Wechatpay:

    def fukuan(self,money):

        print('您已经通过微信支付了%s元' %money)

 

def pay(obj,money):

    obj.fukuan(money) ###野生程序员更改了支付方式的代码

 

c = Wechatpay()

pay(c,200)

 

a = QQpay()   ###原接口已经被改变,不能使用

pay(a,100)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

您已经通过微信支付了200元

Traceback (most recent call last):

  File "D:/python/untitled2/python_7/lession2.py", line 61, in <module>

    pay(a,100)

  File "D:/python/untitled2/python_7/lession2.py", line 55, in pay

    obj.fukuan(money)

 

1.3.4 第四版:制定规范,统一方法名

class Payrole:

   

    def pay(self):pass

 

class QQpay(Payrole):

    def pay(self,money):

        print('您已经通过qq支付了%s元' %money)

 

class Alipay(Payrole):

    def pay(self,money):

        print('您已经通过支付宝支付了%s元' %money)

 

class Wechatpay(Payrole):

    def pay(self,money):

        print('您已经通过微信支付了%s元' %money)

 

def pay(obj,money):

    obj.pay(money)

缺点:归一化了付款接口,但是谁来都可以随意改动

1.3.5 第五版本:强制性制定规定

解释:from abc import ABCMeta,abstractclassmethod #从abc文件中引用两个模块

如果不用pay方法就会报错:

例:

from abc import ABCMeta,abstractmethod

class Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类

    @abstractmethod

    def pay(self):pass  # 抽象方法

 

class Alipay(Payment):

    def pay(self,money):

        print('使用支付宝支付了%s元'%money)

 

class QQpay(Payment):

    def pay(self,money):

        print('使用qq支付了%s元'%money)

 

class Wechatpay(Payment):

    def pay(self,money):

        print('使用微信支付了%s元'%money)

    def recharge(self):pass

 

 

def pay(obj,money):

    obj.pay(money)

 

 

a = Wechatpay()

b = QQpay()

c = Alipay()

 

pay(a,100)

pay(b,200)

pay(c,201)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

使用微信支付了100元

使用qq支付了200元

使用支付宝支付了201元

1.4 抽象类

1.4.1 解释:

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

1.4.2 为什么要有抽象类

    如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

1.4.3 抽象类实际应用理论

  比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子……..你永远无法吃到一个叫做水果的东西。

    从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

   从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案

1.4.4 抽象类的使用方法

l  组合

面向对象的组合用法,软件重用的重要方式除了继承之外还有另外一种方式,即:组合

组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合

例1):攻击类

class Person:

 

    def __init__(self,nickname,sex,hp,ad):

        self.nickname = nickname

        self.sex = sex

        self.hp = hp

        self.ad = ad

 

    def attack(self,p1):

        p1.hp -= self.ad

        print('%s攻击了%s,%s还剩%s血量'%(self.nickname,p1.nickname,p1.nickname,p1.hp))

 

    def weapon_attack(self,wea):

        # 武器类的对象封装到人的对象中当做一个属性.就叫做组合.

        self.weapon = wea

 

class Weapon:

 

    def __init__(self,name,att):

        self.name = name

        self.att = att

 

    def Aux_attack(self,p,p1):

        p1.hp -= self.att

        print('%s利用%s打了%s%s滴血,%s还剩%s滴血' %(p.nickname,self.name,p1.nickname,self.att,p1.nickname,p1.hp))

 

 

# alex = Person('alex','男',100,20)

# barry = Person('太白','男',200,50)

# axe = Weapon('斧子',30)

# barry.weapon_attack(axe)

# barry.weapon.Aux_attack(barry,alex)

 

# axe.Aux_attack(alex)

# alex.attack(barry)

# alex.attack(barry)

 

例2):计算类

圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。

这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用

from math import pi

 

class Circle:

    '''

    定义了一个圆形类;

    提供计算面积(area)和周长(perimeter)的方法

    '''

    def __init__(self,radius):

        self.radius = radius

 

    def area(self):

         return pi * self.radius * self.radius

 

    def perimeter(self):

        return 2 * pi *self.radius

 

 

circle =  Circle(10) #实例化一个圆

area1 = circle.area() #计算圆面积

per1 = circle.perimeter() #计算圆周长

print(area1,per1) #打印圆面积和周长

 

class Ring:

    '''

    定义了一个圆环类

    提供圆环的面积和周长的方法

    '''

    def __init__(self,radius_outside,radius_inside):

        self.outsid_circle = Circle(radius_outside)

        self.inside_circle = Circle(radius_inside)

 

    def area(self):

        return self.outsid_circle.area() - self.inside_circle.area()

 

    def perimeter(self):

        return  self.outsid_circle.perimeter() + self.inside_circle.perimeter()

 

 

ring = Ring(10,5) #实例化一个环形

print(ring.perimeter()) #计算环形的周长

print(ring.area()) #计算环形的面积

 

例3)

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程

class BirthDate:

    def __init__(self,year,month,day):

        self.year=year

        self.month=month

        self.day=day

 

class Couse:

    def __init__(self,name,price,period):

        self.name=name

        self.price=price

        self.period=period

 

class Teacher:

    def __init__(self,name,gender,birth,course):

        self.name=name

        self.gender=gender

        self.birth=birth

        self.course=course

    def teach(self):

        print('teaching')

p1=Teacher('egon','male',

            BirthDate('1995','1','27'),

            Couse('python','28000','4 months')

           )

 

print(p1.birth.year,p1.birth.month,p1.birth.day)

 

print(p1.course.name,p1.course.price,p1.course.period)

'''

运行结果:

27

python 28000 4 months

'''

当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

1.5 接口类和抽象类的区别

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念。

1.6 继承注意问题

l  多继承问题

在继承抽象类的过程中,我们应该尽量避免多继承;

而在继承接口的时候,我们反而鼓励你来多继承接口

l  接口隔离原则

使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

l  方法的实现

在抽象类中,我们可以对一些抽象方法做出基础实现;

而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现

 

第2章 面幸对象特征—多态

2.1 鸭子类

Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”

2.2 多态实例

python对于一些相似的功能不用强制规定直接约定俗成,默认支持多态,自带多态

class F1:

    pass

class S1(F1):

    def show(self):

        print 'S1.show'

class S2(F1):

    def show(self):

        print 'S2.show'

# 由于在Java或C#中定义函数参数时,必须指定参数的类型

# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类

# 而实际传入的参数是:S1对象和S2对象

def Func(F1 obj):

    """Func函数需要接收一个F1类型或者F1子类的类型"""

    print obj.show()

s1_obj = S1()

Func(s1_obj) # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show

s2_obj = S2()

Func(s2_obj) # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show

Python伪代码实现Java或C#的多态

Python伪代码实现java C#多态

第3章 面向对象特征—封装

3.1 封装定义

       封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

所以,在使用面向对象的封装特性时,需要:

l  将内容封装到某处

l  从某处调用被封装的内容

3.2 广益封装

class Pesrson:

    country = 'China'

    def __init__(self,name,age):

        self.name = name

        self.age = age

 

    def func(self):

        print(self.name)

#创建了两个对象

p1 = Pesrson('wang',100)

p2 = Pesrson('li',200)

p1.func()#封装到对象中的属性是一种封装

 

3.3 狭义封装

定义:也称私有性封装

3.3.1 特点

只要类执行,将类的内容加载到内存时,发现“__变量名” ,自动将其转化成"_类名__变量名",所以找不到。

私有静态字段,类的内部都可以访问,父类以及类的外部都不能访问

3.3.2 1)私有静态字段(静态变量)

实例:私有静态变量调用结果

class Pesrson:

    country = 'China' #共有静态字段/变量

    __name == 'lili'##私有静态字段/变量

    def __init__(self,name,age):

        self.name = name

        self.age = age

 

    def func(self):

        print(self.name)

 

print(Pesrson.__name)

p1 = Pesrson('wang',100)

p2 = Pesrson('li',200)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

Traceback (most recent call last):

  File "D:/python/untitled2/python_7/lession2.py", line 79, in <module>

    class Pesrson:

  File "D:/python/untitled2/python_7/lession2.py", line 81, in Pesrson

    __name == 'lili'##私有静态字段/变量

NameError: name '_Pesrson__name' is not defined

在类的外部谁都不能调用

3.3.3 私有字段外部调用方法

class Pesrson:

    country = 'China' #共有静态字段/变量

    __name = 'lili'##私有静态字段/变量

    def __init__(self,name,age):

        self.name = name

        self.age = age

 

    def func(self):

        print(self.name)

 

 

p1 = Pesrson('wang',100)

p2 = Pesrson('li',200)

print(Pesrson.__dict__['_Pesrson__name'])

print(p1._Pesrson__name)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

lili

lili

注意:虽然可以访问但工作中没有这样访问的

 

3.3.4 私有字段内部访问方式

解释:对于私有字段,在子类派生类也不可访问父类的私有静态字段,只能在本类使用

class Person:

    country = 'China' #共有静态字段/变量

    __name = 'lili'##私有静态字段/变量

    __age = 23

    def __init__(self,name,age):

        self.name = name

        self.age = age

 

    def func(self):

        return self.__name

 

p1 = Person('liu',19)

print(p1.func())

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

lili

 

3.3.5 2)私有普通变量(私有对象属性)

class Person:

    def __init__(self,name,age):

        self.name = name #公有普通字段

        self.__age = age #私有普通字段

 

p1 = Person('wang',18)

print(p1.name)

print(p1.__age)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

Traceback (most recent call last):

  File "D:/python/untitled2/python_7/lession2.py", line 112, in <module>

    print(p1.__age)

wang

AttributeError: 'Person' object has no attribute '__age'

3.3.6 3)私有方法

class Person:

    def __init__(self,name,age):

        self.name = name #公有普通字段

        self.__age = age #私有普通字段

 

    def __func(self):#私有方法

        print(666)

 

p1 = Person('wang',18)

print(p1.name)

p1.__func()

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

Traceback (most recent call last):

  File "D:/python/untitled2/python_7/lession2.py", line 116, in <module>

    p1.__func()

AttributeError: 'Person' object has no attribute '__func'

wang

 

3.3.7 4)私有成员实际应用

对只想让类内部使用的成员,要设置成私有成员

例1):密码加密方法

class Person:

    def __init__(self,username,password):

        self.username = username

        self.__password = self.__encryption(password)

 

    def __encryption(self,pwd):

        '''

        加密处理

        :param pwd:

        :return:

        '''

        return '%s xyz123' % pwd

p1 = Person('wang','123')

print(p1._Person__password)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

123 xyz123

 

例2):

类的执行顺序:有先找__init__

 

class A:

    def __init__(self):

        self.func()

    def func(self):

        print('in A')

class B(A):

    def func(self):

        print('in B')

b = B()

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

in B

执行逻辑:

b è B(A) è A() è __init__ èfunc() è B.func() è print('in B')

 

例3)

class A:

    def __init__(self):

        self.__func()

    def __func(self):

        print('in A')

class B(A):

    def __func(self):

        print('in B')

b = B()

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

in A

执行逻辑:

b è B(A) è A() è __init__ èself.__func() == self._A__func() è A.func() è print('in A')

第4章 面向对象进阶

4.1 面向对象整体结构及成员

4.1.1 字段:

普通字段和静态字段

4.1.2 方法:

普通方法和属性

       1)普通:一般是由对象调用的 init

class A:

    name = 'lili'

    def __init__(self,name,age):

        self.name = name

        self.age = age

    def func(self):

        print(666)

p1 = A('li',19)

print(p1.name)

print(p1.age)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

li

19

 

4.1.3 属性

例一

BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)

成人的BMI数值:

过轻:低于18.5

正常:18.5-23.9

过重:24-27

肥胖:28-32

非常肥胖, 高于32

  体质指数(BMI)=体重(kg)÷身高^2(m)

  EX:70kg÷(1.75×1.75)=22.86

 

class People:

    def __init__(self,name,weight,height):

        self.name = name

        self.__weight = weight

        self.__height = height

    def bmi(self):

        return self.__weight /self.__height **2

p1 = People('wang',75,1.78)

print(p1.bmi())

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

23.671253629592222

4.2 @peroperty

4.2.1 将方法变为属性

解释:property 将你的 ‘一些方法伪装为属性,虽然在代码是哪个没有提高,让其看起来合乎情理’

例:

class People1:

    def __init__(self,name,weight,height):

        self.name = name

        self.__weight = weight

        self.__height = height

    @property

    def bmi(self):

        return self.__weight /self.__height **2

p2 = People1('wang',75,1.78)

print(p2.bmi)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

23.671253629592222

4.2.2 私有属性的外部显示

class People1:

    def __init__(self,name,weight,height,age):

        self.name = name

        self.__weight = weight

        self.__height = height

        self.__age = age

 

    def age(self):

        return self.__age

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

<class 'float'>

<bound method People1.age of <__main__.People1 object at 0x00000000021D8B00>>

 

加@property 后

class People1:

    def __init__(self,name,weight,height,age):

        self.name = name

        self.__weight = weight

        self.__height = height

        self.__age = age

 

    @property

    def age(self):

        return self.__age

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

<class 'float'>

16

 

4.2.3 @age.setter修改私有属性

class People1:

    def __init__(self,name,weight,height,age):

        self.name = name

        self.__weight = weight

        self.__height = height

        self.__age = age

 

    @property

    def age(self):

        return self.__age

 

    @age.setter

    def age(self,new_age):

        if type(new_age) == int:

            self.__age = new_age

        else:

            return '请输入一个整数'

 

p1 = People1('lili',45,1.6,23)

print(p1.age)

p1.age = 22

print(p1.age)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

23

22

 

4.2.4 自动触发的三要素

m  方法名相同

m  对方法赋值

m  调用方法setter

 

 

4.2.5 peroperty匹配的三种方法

l  getattr(object, name, default=None)

l  setattr(x, y, v) 设置增加或修改

l  delattr(x, y)

 

class People1:

    def __init__(self,name,weight,height,age):

        self.name = name

        self.__weight = weight

        self.__height = height

        self.__age = age

 

    @property

    def age(self):

        return self.__age

 

    @age.setter

    def age(self,new_age):

        if type(new_age) == int:

            self.__age = new_age

        else:

            return '请输入一个整数'

 

    @age.deleter

    def age(self):

        print(666)

 

p1 = People1('lili',45,1.6,23)

print(p1.age) #触发@property 方法

p1.age = '1234' #触发@aage.setter 装饰器方法

del p1.age #触发 @age.deleter装饰的方法

print(p1.age)

 

一个属性只能对应一个值

class People:

    def __init__(self,name,age,sex):

        self.name = name

        self.__age = age

        self.__sex = sex

 

    def age(self):

        return  self.__age

 

p1 = People('wang','25','男')

print(p1.name)

print(p1.age)

输出

C:\python3\python.exe D:/python/untitled2/lianxi/lianxi.py

wang

<bound method People.age of <__main__.People object at 0x00000000021F8940>>

输出年龄

class People:

    def __init__(self,name,age,sex):

        self.name = name

        self.__age = age

        self.__sex = sex

    @property

    def age(self):

        return  self.__age

 

 

p1 = People('wang','25','男')

print(p1.name)

print(p1.age)

 

练习:水果折扣价格

class Goods:

    def __init__(self,name,origin_price,discount):

        self.name  = name

        self.__origin_price = origin_price

        self.__discount = discount

    @property

    def price(self):

        return self.__origin_price*self.__discount

 

    @price.setter

    def price(self,new_price):

        self.__origin_price = new_price

 

obj1 = Goods('apple',5,0.8)

print(obj1.price)

obj1.price = 8

print(obj1.price)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

4.0

6.4

 

4.3 类方法:

一般用类名直接调用

有些情况对于类内部的方法,无需对象直接调用,而用类名直接调用即可

例1:(对象调用)

class Goods:

    __discount = 0.8

 

    def __init__(self,name,origin_price):

        self.name = name

        self.__origin_price = origin_price

 

    @property

    def price(self):

        return self.__origin_price * Goods.__discount

 

    def discount(self,new_discount):

        Goods.__discount = new_discount

 

 

p1 = Goods('apple',5)

print(p1.price)

p1.discount(0.85)

print(p1.price)

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

4.0

4.25

 

4.3.1 @classmethod

例2 (类名调用)

cls 默认接受类名本身

class Goods:

    __discount = 0.8

 

    def __init__(self,name,origin_price):

        self.name = name

        self.__origin_price = origin_price

 

    @property

    def price(self):

        return self.__origin_price * Goods.__discount

 

    @classmethod

    def discount(cls,new_discount):

        Goods.__discount = new_discount

 

p1 = Goods('apple',5)

Goods.discount(0.85)

print(p1.price)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

4.25

4.3.2 静态方法直接引用@staticmethod

不用类cls或者对象self 传值,直接调用即可

class A:

    def __init__(self):

        pass

 

    @staticmethod

    def login(username,password):

        print(username,password)

 

A.login('wang',134)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

wang 134

4.4 *****getattr()反射

概念:python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

4.4.1 在类中

解释:通过字符串去到 类名  中获取值。

特殊:在python中,一切皆对象,凡是通过  什么.什么 ,通过 反射都能取到。

要求:输入字段即可获取字段

class A:

    role = 'Teacher'

    def func(self):

        print(666)

       

eval exec用法注意:写死的时候可以用

普通方法:

class A:

    role = 'Teacher'

    def func(self):

        print(666)

msg = input('>>')

print(A.__dict__[msg])

输出:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

>>role

Teacher

 

升级后:反射

class A:

    role = 'Teacher'

    def func(self):

        print(666)

# msg = input('>>')

# print(A.__dict__[msg])

print(getattr(A,'role'))

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

Teacher

完整形式:

class A:

    role = 'Teacher'

    def func(self):

        print(666)

msg = input('>>')

 

print(getattr(A,msg))

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

>>role

Teacher

4.4.2 在对象中

class Foo:

    f = '类的静态变量'

    def __init__(self,name,age):

        self.name=name

        self.age=age

 

    def say_hi(self):

        print('hi,%s'%self.name)

 

obj=Foo('egon',73)

 

#检测是否含有某属性

print(hasattr(obj,'name'))

print(hasattr(obj,'say_hi'))

 

#获取属性

n=getattr(obj,'name')

print(n)

func=getattr(obj,'say_hi')

func()

 

print(getattr(obj,'aaaaaaaa','不存在啊')) #报错

 

#设置属性

setattr(obj,'sb',True)

setattr(obj,'show_name',lambda self:self.name+'sb')

print(obj.__dict__)

print(obj.show_name(obj))

 

#删除属性

delattr(obj,'age')

delattr(obj,'show_name')

delattr(obj,'show_name111')#不存在,则报错

 

print(obj.__dict__)

 

对实例化对象的示例

 

4.4.3 在模块中

#一个模块中的代码

def test():

    print('from the test')

"""

程序目录:

    module_test.py

    index.py

 

当前文件:

    index.py

"""

# 另一个模块中的代码

import module_test as obj

 

#obj.test()

 

print(hasattr(obj,'test'))

 

getattr(obj,'test')()

 

4.4.4 在当前模块中

import sys

 

 

def s1():

    print 's1'

 

def s2():

    print 's2'

 

this_module = sys.modules[__name__]

 

hasattr(this_module, 's1')

getattr(this_module, 's2')

 

4.4.5 通过字符串去到 类名 中取值

class A:

    role = 'Teacher'

    def func(self):

        print(666)

msg = input('>>')

 

getattr(A,msg)(111)

输出

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

>>func

666

4.4.6 hasattr/ getattr/ setattr/ delattr

解释:通过字符串到类中判断是否存

l  hasattr(object,name)

l  getattr(object, name, default=None)

l  setattr()

l  delattr() 删除

 

应用实例:

class BlackMedium:

    feature='Ugly'

    def __init__(self,name,addr):

        self.name=name

        self.addr=addr

 

    def sell_house(self):

        print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)

    def rent_house(self):

        print('%s 黑中介租房子啦,傻逼才租呢' %self.name)

 

b1=BlackMedium('万成置地','回龙观天露园')

 

#检测是否含有某属性

print(hasattr(b1,'name'))

print(hasattr(b1,'sell_house'))

 

#获取属性

n=getattr(b1,'name')

print(n)

func=getattr(b1,'rent_house')

func()

 

# getattr(b1,'aaaaaaaa') #报错

print(getattr(b1,'aaaaaaaa','不存在啊'))

 

#设置属性

setattr(b1,'sb',True)

setattr(b1,'show_name',lambda self:self.name+'sb')

print(b1.__dict__)

print(b1.show_name(b1))

 

#删除属性

delattr(b1,'addr')

delattr(b1,'show_name')

delattr(b1,'show_name111')#不存在,则报错

 

print(b1.__dict__)

4.4.7 *****hasattr()

通过字符串操作对象进行判断,先判断有没有值,再用getattra取值

class A:

    role = 'Teacher'

    def __init__(self,name,age):

        self.name = name

        self.age = age

a1 = A('wang',18)

 

print(hasattr(a1,'name'))

print(hasattr(a1,'alex'))

输出

C:\python3\python.exe D:/python/untitled2/lianxi/练习2.py

True

False

结合getatter用法

 

class A:

    role = 'Teacher'

    def __init__(self,name,age):

        self.name = name

        self.age = age

a1 = A('wang',18)

 

print(hasattr(a1,'name'))

print(hasattr(a1,'alex'))

print(getattr(a1,'name'))

                                                    

4.5 其他方法

4.6 ****__new__

解释:创建对象的根源

源码解释:

  def __new__(cls, *more): # known special case of object.__new__

        """ Create and return a new object.  See help(type) for accurate signature. """

        pass

案例分析

class A:

    def __init__(self):

        self.x = 1

        print('in init function')

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

        print('in new function')

        return object.__new__(A, *args, **kwargs)

 

a = A()

print(a.x)

设计模式:单例模式(一个类只能实例化一个对象)

class A:

    __instance = None

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

        if cls.__instance is None:

            obj = object.__new__(cls)

            cls.__instance = obj

        return cls.__instance

 

4.7 ***__call__

解释:对象加()自动执行__call__方法

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

 

    def __init__(self):

        pass

   

    def __call__(self, *args, **kwargs):

 

        print('__call__')

 

 

obj = Foo() # 执行 __init__

obj()       # 执行 __call__

4.8 isinstance()

对象属不属于这个类是不是输入这个类的派生类

class A: pass

class B(A): pass

 

abj = B()

print(isinstance(abj,B)) #true

print(isinstance(abj,A)) #true

 

4.9 issubclass()

第一类是第二个类的后代就是true

class A: pass

class B(A): pass

 

abj = B()

print(issubclass(B,A)) #true

4.10 __len__

解释:len方法能不能用,归结于对象中有没有__len__方法

class A:

    def __init__(self):

        self.a = 1

        self.b = 2

 

    def __len__(self):

        return len(self.__dict__)

a = A()

print(len(a)

4.11 __hash__

解释:能不能hash 看对象中有没有__hash__

class A:

    def __init__(self):

        self.a = 1

        self.b = 2

 

    def __hash__(self):

        return hash(str(self.a)+str(self.b))

a = A()

print(hash(a))

4.12 __str__

类中如果有__str__方法,打印或者str() 即可执行str

class A:

    def __init__(self):

        pass

    def __str__(self):

        return '太白'

a = A()

print(a)

print('%s' % a)

4.13 __repr__

解释:如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回

class A:

    def __init__(self):

        pass

    def __repr__(self):

        return 'lili'

a = A()

print(repr(a))

print('%r'%a)

 

4.14 __eq__

class A:

    def __init__(self):

        self.a = 1

        self.b = 2

 

    def __eq__(self,obj):

        if  self.a == obj.a and self.b == obj.b:

            return True

a = A()

b = A()

print(a == b)

4.15 __del__

析构方法:自动执行

析构方法,当对象在内存中被释放时,自动触发执行。

注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class A:

    def __init__(self):

        self.a =1

        self.b =2

    def __del__(self):

        print(222)

        return 666

obj1 = A()

解释:

C:\python3\python.exe D:/python/untitled2/python_7/lession2.py

222

4.16 __item__

class Foo:

    def __init__(self,name):

        self.name=name

 

    def __getitem__(self, item):

        print(self.__dict__[item])

 

    def __setitem__(self, key, value):

        self.__dict__[key]=value

    def __delitem__(self, key):

        print('del obj[key]时,我执行')

        self.__dict__.pop(key)

    def __delattr__(self, item):

        print('del obj.key时,我执行')

        self.__dict__.pop(item)

 

f1=Foo('sb')

print(f1.__dict__)

f1['age']=18

print(f1.__dict__)

f1['age1']=19

print(f1.__dict__)

del f1.age1

print(f1.__dict__)

del f1['age']

print(f1.__dict__)

f1['name']='alex'

print(f1.__dict__)

输出

C:\python3\python.exe D:/python/untitled2/lianxi/练习2.py

{'name': 'sb'}

{'name': 'sb', 'age': 18}

{'name': 'sb', 'age': 18, 'age1': 19}

del obj.key时,我执行

{'name': 'sb', 'age': 18}

del obj[key]时,我执行

{'name': 'sb'}

{'name': 'alex'}

 

posted @ 2018-06-26 15:59  王晓冬  阅读(172)  评论(0编辑  收藏  举报