面向对象进阶

类命名空间与对象,实例的命名空间

创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性

类属性的种类:

  • 静态属性就是直接在类中定义的变量
  • 动态属性就是定义在类中的方法

类的属性的构成:

  类属性的数据属性

    类的数据属性是共享给所有的对象的

>>>id(egg.role)
4341594072
>>>id(Person.role)
4341594072

  类属性的动态属性

    类的动态属性是绑定到所有的对象的

>>>egg.attack
<bound method Person.attack of <__main__.Person object at 0x101285860>>
>>>Person.attack
<function Person.attack at 0x10127abf8> 

创建一个对象/实例就会创建一个对象/实例的名称空间,存放对象/实例的名字,称为对象/实例的属性

在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常

查看类中的所有内容:
    类名.__dict__方法
class Course:
    language = 'Chinese'  
    def __init__(self,teacher,name,period,price):
        self.teacher = teacher
        self.name = name
        self.period = period
        self.price = price

python = Course('egon','python','6 months',20000)
print(Course.__dict__)
查看结果:
{'__module__': '__main__', 'language': 'Chinese', '__init__': <function Course.__init__ at 0x0000024E5DB9A8C8>, '__dict__': <attribute '__dict__' of 'Course' objects>, '__weakref__': <attribute '__weakref__' of 'Course' objects>, '__doc__': None}


在类中可以定义俩种属性:
    1 静态属性
    2 动态属性:在类中自定义的方法(函数)

class Person:
    language = 'Chinese'  #静态属性
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

    def walk(self):  #类的动态属性
        return '人都有走路的功能'

person = Person('张三','')
print(person.name)
print(person.sex)
print(person.walk())


静态属性的修改:
    不可以使用类名.__dict__方法来修改
    修改方式:
        类名.静态属性名='修改后的值‘    

class Course:
    language = 'Chinese'  #静态属性
    def __init__(self,teacher,name,period,price):
        self.teacher = teacher
        self.name = name
        self.period = period
        self.price = price

python = Course('egon','python','6 months',20000)
print(Course.language)  #修改之前的值   Chinese
Course.language = 'English'   #静态属性修改之后形成一个新的值之前的值无效
print(Course.language)   #修改之后的值  English

类中静态属性的调用
    类中的静态属性只可以被类名和对象名调用
class Course:
    language = 'Chinese'  #静态属性
    def __init__(self,teacher,name,period,price):
        self.teacher = teacher
        self.name = name
        self.period = period
        self.price = price

python = Course('egon','python','6 months',20000)
print(Course.language)  #使用类名调用静态属性
print(python.language)  #使用对象名调用静态属性


在类中只有变量名和函数名 只要是定义在类中的名字都可以通过类名和对象名来调用

class Person:
    language = 'Chinese'  #类中的变量(属性)名
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex
    @classmethod    #类名调用方法的时候使用语法糖可以不用传参数
    def walk(self):  #类中的函数(方法)名
        return '在走路'

person = Person('张三','')
#对象名调用属性和方法
print(person.language)
print(person.walk())
#类名调用属性和方法
print(Person.language)
#print(Person.walk(Person))#类名调用自己类中的方法需要把类自己作为参数传入到方法中
print(Person.walk())       #或者使用语法糖可以不用传参数






















    
详解及总结

从内存的角度详解类和对象的命名空间

以上图为例:
当你创建一个类的时候 在内存中已经开辟了一个名为Course空间
在Course这个类的空间中有language,init和func三个名字,当使用类名去调用的时候是直接使用Course自己的空间中的值

每实例化一次,就会开辟一个新的空间和Course的命名空间无关
当实例化后python调用类的时候会创建一个标识(类对象指针)指向类(Course)通过这个标识找到对象自己的类(类和对象之间只是单向关联即对象关联类):对象可以使用类中的名字,类不能使用对象中的名字

在对象(self)中的名字(属性) 它们都存放在对象的空间中,每当对象调用属性的时候会先在自己的空间中找如果没有再用类的空间中的属性名字

对象和对象之间是兄弟关系,它们之间香菇独立互不影响,都可以使用类中的名字

如果类中的属性名改变的话 对象调用类中的名字也会改变

当在对象的空间中有和类空间中相同的变量名时对象以自己空间的变量名为主,对象空间中没有相同的变量名的时候用类空间中的变量名;如果对象还想用类中的变量只有使用del将对象自己空间中和类相同的变量名删除(defl 对象名.变量名)后才能使用
图解

 面向对象的组合用法

软件重用的倆个重要方式:继承   组合

组合定义:

在一个类中以另一个类的对象作为数据属性 称为类的组合,组合表示的是一种什么有什么的关系

class Weapon:
    def prick(self, obj):  # 这是该装备的主动技能,扎死对方
        obj.life_value -= 500  # 假设攻击力是500

class Person:  # 定义一个人类
    role = 'person'  # 人的角色属性都是人

    def __init__(self, name):
        self.name = name  # 每一个角色都有自己的昵称;
        self.weapon = Weapon()  # 给角色绑定一个武器;
        
egg = Person('egon')
egg.weapon.prick() 
#egg组合了一个武器的对象,可以直接egg.weapon来使用组合类中的所有方法
初识组合示例

组合应用示例:

圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。
这个时候,我们就首先实现一个圆形类,计算一个圆的周长和面积。然后在"环形类"中组合圆形的实例作为自己的属性来用
应用场景及分析
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()) #计算环形的面积
实现代码
组合进阶示例:
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教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)
''' 
运行结果: 
1 27 
python 28000 4 months 
'''
代码实现

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

小结

定义一个人类

class Person:  # 定义一个人类
    role = 'person'  # 人的角色属性都是人

    def __init__(self, name, aggressivity, life_value, money):
        self.name = name  # 每一个角色都有自己的昵称;
        self.aggressivity = aggressivity  # 每一个角色都有自己的攻击力;
        self.life_value = life_value  # 每一个角色都有自己的生命值;
        self.money = money

    def attack(self,dog):
        # 人可以攻击狗,这里的狗也是一个对象。
        # 人攻击狗,那么狗的生命值就会根据人的攻击力而下降
        dog.life_value -= self.aggressivity

定义一个狗类

class Dog:  # 定义一个狗类
    role = 'dog'  # 狗的角色属性都是狗

    def __init__(self, name, breed, aggressivity, life_value):
        self.name = name  # 每一只狗都有自己的昵称;
        self.breed = breed  # 每一只狗都有自己的品种;
        self.aggressivity = aggressivity  # 每一只狗都有自己的攻击力;
        self.life_value = life_value  # 每一只狗都有自己的生命值;

    def bite(self,people):
        # 狗可以咬人,这里的狗也是一个对象。
        # 狗咬人,那么人的生命值就会根据狗的攻击力而下降
        people.life_value -= self.aggressivity

创建一个新的兵器类

class Weapon:
    def __init__(self,name, price, aggrev, life_value):
        self.name = name
        self.price = price
        self.aggrev = aggrev
        self.life_value = life_value

    def update(self, obj):  #obj就是要带这个装备的人
        obj.money -= self.price  # 用这个武器的人花钱买所以对应的钱要减少
        obj.aggressivity += self.aggrev  # 带上这个装备可以让人增加攻击
        obj.life_value += self.life_value  # 带上这个装备可以让人增加生命值

    def prick(self, obj):  # 这是该装备的主动技能,扎死对方
        obj.life_value -= 500  # 假设攻击力是500

测试交互

lance = Weapon('长矛',200,6,100)
egg = Person('egon',10,1000,600)  #创造了一个实实在在的人egg
ha2 = Dog('二愣子','哈士奇',10,1000)  #创造了一只实实在在的狗ha2

#egg独自力战"二愣子"深感吃力,决定穷毕生积蓄买一把武器
if egg.money > lance.price: #如果egg的钱比装备的价格多,可以买一把长矛
    lance.update(egg) #egg花钱买了一个长矛防身,且自身属性得到了提高
    egg.weapon = lance #egg装备上了长矛

print(egg.money,egg.life_value,egg.aggressivity)

print(ha2.life_value)
egg.attack(ha2)   #egg打了ha2一下
print(ha2.life_value)
egg.weapon.prick(ha2) #发动武器技能
print(ha2.life_value) #ha2不敌狡猾的人类用武器取胜,血槽空了一半
原文地址:https://www.cnblogs.com/bypp/p/7544257.html