Python面向对象 | 类属性

property

property是一个装饰器函数,可以将一个方法伪装成属性,调用的时候可以不用加()。@property被装饰的方法,是不能传参数的,因为它伪装成属性了。

装饰器的使用:在要装饰的函数、方法、类上面一行加上 @装饰器名字

装饰器的分类:

  •   装饰函数
  •   装饰方法:property
  •   装饰类

例一: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

查看我的BMI

class Person(object):
    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

p = Person(‘xiao‘,65,1.75)
print(p.bmi)                                        # 21.224489795918366
print(Person.__dict__)                   
print(p.__dict__)                      # 在对象里面,并没有被当成属性

‘‘‘
执行输出:
21.224489795918366
{‘__module__‘: ‘__main__‘, ‘__init__‘: <function Person.__init__ at 0x000002221B1EC048>, ‘bmi‘: <property object at 0x000002221B1E8C78>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘Person‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘Person‘ objects>, ‘__doc__‘: None}

{‘name‘: ‘xiao‘, ‘_Person__weight‘: 65, ‘_Person__height‘: 1.75}
‘‘‘

被property装饰的bmi仍然是一个方法,存在Person.__dict__。对象的.__dict__中不会存储这个属性.

下面的代码,也可以实现上面的效果

class Person(object):
    def __init__(self,name,weight,height):
        self.name = name
        self.__weight = weight
        self.__height = height
        #self.bmi = self.__weight / self.__height **2
        #self.bmi = cal_BMI()  

# 但是计算的逻辑,不能放到init里面。初始化,不要做计算

举例:

class Person(object):
    def __init__(self,name,weight,height):
        self.name = name
        self.__weight = weight
        self.__height = height
        self.bmi = self.__weight / self.__height **2

p = Person(‘xiao‘,65,1.75)
print(p.bmi)
p._Person__weight = 70                                  # 1周之后,增加体重
print(p.bmi)

‘‘‘
执行输出:
21.224489795918366
21.224489795918366
‘‘‘

执行结果是一样的,体重增加了,但是bmi指数没有变动。因为__init__初始化之后,就不会再变动了。

在__init__里面,属性名不能和方法名重复

class Person(object):
    def __init__(self,name,weight,height,bmi):
        self.name = name
        self.__weight = weight
        self.__height = height
        self.bmi = bmi

    def bmi(self):
        return self.__weight / self.__height **2

a = Person(‘xiao‘,65,1.75)
print(a.bmi())                      # TypeError: __init__() missing 1 required positional argument: ‘bmi‘

那么bmi是否可以修改呢?

class Person(object):
    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

p = Person(‘xiao‘,65,1.75)
p.bmi = 2    # AttributeError: can‘t set attribute

但是它的name属性是可以改变的。

class Person:
    def __init__(self,name):
        self.name = name

p = Person(‘Tony‘)
print(p.name)           # Tony
p.name = ‘John‘
p.name = 123

那么上面这2个例子,和直接定义name属性有什么区别?

class Person:
    def __init__(self,name):
        self.__name = name  # 私有的属性

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

    def set_name(self,new_name):
        if type(new_name) is str:
            self.__name = new_name

        else:    # 通过if判断,就可以保护属性的类型,必须是字符串
            print(‘您提供的姓名数据类型不合法‘)

p = Person(‘Tony‘)
print(p.name)
p.set_name(‘John‘)
print(p.name)
p.set_name(123)

‘‘‘
执行输出:
Tony
John
您提供的姓名数据类型不合法
‘‘‘            

@property可以将python定义的函数“当做”属性访问,有时候setter/deleter也是需要的。

  • 只有@property表示只读。
  • 同时有@property和@x.setter表示可读可写。
  • 同时有@property和@x.setter和@x.deleter表示可读可写可删除。

 

新式类中具有三种访问方式,分别将三个方法定义为对同一个属性:获取、修改、删除

class Foo:
    @property
    def AAA(self):
        print(‘get的时候运行我啊‘)

    @AAA.setter
    def AAA(self,value):
        print(‘set的时候运行我啊‘)

    @AAA.deleter
    def AAA(self):
        print(‘delete的时候运行我啊‘)

#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA=‘aaa‘
del f1.AAA

‘‘‘
执行输出:
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
‘‘‘

或者:

class Foo:
    def get_AAA(self):
        print(‘get的时候运行我啊‘)

    def set_AAA(self,value):
        print(‘set的时候运行我啊‘)

    def delete_AAA(self):
        print(‘delete的时候运行我啊‘)
    AAA=property(get_AAA,set_AAA,delete_AAA)        # 内置property三个参数与get,set,delete一一对应

f1=Foo()
f1.AAA
f1.AAA=‘aaa‘
del f1.AAA

‘‘‘
执行输出:
get的时候运行我啊
set的时候运行我啊
delete的时候运行我啊
‘‘‘

商品实例

class Goods(object):

    def __init__(self):
        self.original_price = 100           # 原价
        self.discount = 0.8                 # 折扣

    @property
    def price(self):                        # 计算折后价格
        new_price = self.original_price * self.discount
        return new_price

    @price.setter
    def price(self, value):
        self.original_price = value

    @price.deleter
    def price(self, value):
        del self.original_price

obj = Goods()
print(obj.price)    # 获取商品价格 80.0

obj.price = 200     # 修改商品原价
print(obj.price)    # 获取商品价格 160.0

# del obj.price     # 删除商品原价 TypeError: price() missing 1 required positional argument: ‘value‘
class Person:
    def __init__(self,name):
        self.__name = name      # 私有的属性

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

    @name.setter
    def name(self,new_name):
        print(‘---‘,new_name)

p = Person(‘Tony‘)
p.name = ‘John‘                 # 修改name属性

‘‘‘
执行输出:
--- John
‘‘‘

上面的代码,3个name必须是相同的。三位一体。@name.settet有且并只有一个参数

class Person:
    def __init__(self,name):
        self.__name = name  # 私有的属性

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

    @name.setter
    def name(self,new_name):
        print(‘---‘,new_name)

p = Person(‘Tony‘)
print(p.name)

p.name = ‘John‘     # 修改name属性
print(p.name)

‘‘‘
执行输出:
Tony
--- John
Tony
‘‘‘

从结果上来看,并没有改变Tony的值那么如何改变呢?看下面的代码

class Person:
    def __init__(self,name):
        self.__name = name                  # 私有的属性

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

    @name.setter
    def name(self,new_name):
        self.__name = new_name              # 更改__name属性

p = Person(‘Tony‘)
print(p.name)

p.name = ‘John‘     # 修改name属性
print(p.name)

‘‘‘
执行输出:
Tony
John
‘‘‘

但是这样,不能保证修改的数据类型是固定的

class Person:
    def __init__(self,name):
        self.__name = name  # 私有的属性

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

    @name.setter
    def name(self,new_name):
        if type(new_name) is str:
            self.__name = new_name

        else:
            print(‘您提供的姓名数据类型不合法‘)

p = Person(‘Tony‘)
print(p.name)

p.name = ‘John‘     # 修改name属性
print(p.name)

p.name = 123        # 不合法
print(p.name)

‘‘‘
执行输出:
Tony
John
您提供的姓名数据类型不合法
John
‘‘‘

非法类型,不允许修改,这样就可以保护属性的类型

方法伪装成的属性删除操作

class Person:
    def __init__(self,name):
        self.__name = name  # 私有的属性

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

p = Person(‘alex‘)
print(p.name)
del p.name    # AttributeError: can‘t delete attribute

# 为什么不能删除?因为name被@property伪装了,此时name是只读的。    

那么如何删除呢?看下面的代码

class Person:
    def __init__(self,name):
        self.__name = name  # 私有的属性

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

    @name.deleter
    def name(self):
        del self.__name

p = Person(‘Tony‘)
print(p.name)

del p.name
print(p.__dict__)  # 查看属性

‘‘‘
执行输出:
Tony
{}
‘‘‘

p对象返回的是空字典,说明删除成功了!

3个装饰器的重要程度

  • @property****
  • @name.setter   ***
  • @name.deleter  *

再讲一个列子:商品的 折扣  我想看折后价

class Goods:
    def __init__(self,name,origin_price,discount):
        self.name = name
        self.__price = origin_price                 # 原价
        self.__discount = discount                  # 折扣价

    @property
    def price(self):
        return self.__price * self.__discount

apple = Goods(‘apple‘,5,0.8)
print(apple.price)                          # 4.0

修改苹果的原价

class Goods:
    def __init__(self,name,origin_price,discount):
        self.name = name
        self.__price = origin_price  # 原价
        self.__discount = discount  # 折扣价

    @property
    def price(self):  # 价格
        return self.__price * self.__discount

    @price.setter
    def price(self,new_price):
        if type(new_price) is int or type(new_price) is float:
            self.__price = new_price

apple = Goods(‘apple‘,5,0.8)
print(apple.price)              # 4.0

apple.price = 8                 # # 修改苹果的原价
print(apple.price)              # 6.4

被property装饰的方法,不能修改,只能查看

圆形类,有半径,面积,周长。要求:将方法伪装成属性,方法中一般涉及的都是一些计算过程

from math import pi
class Circle:  # 圆形
    def __init__(self, r):
        self.r = r

    @property
    def area(self):  # 面积
        return pi * self.r ** 2

    @property
    def perimeter(self):  # 周长
        return pi * self.r * 2

c = Circle(10)
print(c.area)
print(c.perimeter)

c.r =15                 # 修改半径
print(c.area)
print(c.perimeter)

‘‘‘
执行输出:
314.1592653589793
62.83185307179586
706.8583470577034
94.24777960769379
‘‘‘

总结:

  • @property --> func 将方法伪装成属性,只观看的事儿
  • @func.setter --> func 对伪装的属性进行赋值的时候调用, 一般情况下用来做修改
  • @func.deleter --> func 在执行del 对象.func的时候调用,一般情况下用来做删除.基本不用

property的作用

  • 将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
  • 将私有的属性保护起来,让修改的部分增加一些约束,来提高程序的稳定性和数据的安全性

在一个类加载的过程中,会先加载这个类的名字,包括被property装饰的。

在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,如果有就不能再在自己对象的空间中创建这个属性了

原文地址:https://www.cnblogs.com/Summer-skr--blog/p/11801424.html

时间: 2024-08-30 03:01:26

Python面向对象 | 类属性的相关文章

Python面向对象—类属性和实例属性

属性:就是属于一个对象的数据或函数元素 类有类方法.实例方法.静态方法.类数据属性(类变量)和实例数据属性(实例变量). 类属性:包括类方法和类变量,可以通过类或实例来访问,只能通过类来修改. 实例属性:包括实例方法和实例变量 class MyClass(object): name = 'Anl' def __init__(self, age): self.age = age @classmethod def class_method(cls): print "I'm class method&

Python面向对象之类属性类方法静态方法

类的结构 实例 使用面向对象开发时,第一步是设计类: 当使用 类名() 创建对象时,会自动执行以下操作: 1.为对象在内存中分配空间--创建对象: 2.为对象的属性 设置初始值--初始化方法(init); 对象创建后,内存中就有了一个对象的实实在在的存在--实例: 因此通常也会把: 1.创建出来的对象叫做类的实例: 2.创建对象的动作叫实例化: 3.对象的属性叫实例属性: 4.对象调用的方法叫实例方法: 在程序执行时: 1.对象各自拥有自己的实例属性: 2.调用对象方法,可以通过self. 访问

python面向对象——类和对象

一.三大编程范式 编程范式即编程的方法论,标识一种编程风格 三大编程范式: 1.面向过程编程(流水线式) 优点:极大的降低了程序的复杂度 缺点:应用场景固定住了,可扩展性差 2.函数式编程 特点: a.不修改外部传来值的状态 b.精简,可读性差 c.模仿数学里的函数 3.面向对象编程(是用来解决程序的可扩展性的) 优点:解决了程序的可扩展性 缺点:可控性差 二.面向对象设计与面向对象编程 1.面向对象设计 面向对象设计(Object oriented design):将一类具体事物的数据和动作整

谨慎修改Python的类属性

Python的类和类实例都是可变对象,可以随时给属性赋值,并且在原处修改. 在对类属性进行修改时需要特别小心,因为所有的类实例都继承共享类属性,除非实例本身存在和类属性同名的属性.对类属性进行修改,会影响到所有由这个类生成的实例. class CA(object): cls_pre = 'aaaaa' def __init__(self): self.obj_pre = 'bbbbb' a = CA() b = CA() print(a.cls_pre, a.obj_pre) print(b.c

python干货-类属性和方法,类的方法重写

类属性与方法 类的私有属性 __private_attrs: 两个下划线开头,表明为私有,外部不可用,内部使用时self.__private_attrs. 类的方法 在类的内部,使用 def 关键字来定义一个方法,类方法必须包含参数 self,且为第一个参数.self的名称也可自己取,如使用this,但是建议还是用self为好. 类的私有方法 __private_method: 两个下划线开头,为私有方法,只能在类的内部调用 ,不能在类的外部调用.self.__private_methods.

python学习-类属性和实例属性

#类属性和实例属性 class Tool(object): #类属性 total = 0 def __init__(self,new_name): #实例属性 self.name = new_name #类属性 Tool.total += 1 tool1 = Tool("a1") tool2 = Tool("a2") tool3 = Tool("a3") print(tool1.name) print(tool2.name) print(tool

Python:类属性,实例属性,私有属性与静态方法,类方法,实例方法

From: http://www.cnblogs.com/pengsixiong/p/4823473.html 属性分为实例属性与类属性 方法分为普通方法,类方法,静态方法 一:属性: 尽量把需要用户传入的属性作为实例属性,而把同类都一样的属性作为类属性.实例属性在每创造一个类是都会初始化一遍,不同的实例的实例属性可能不同,不同实例的类属性都相同.从而减少内存. 1:实例属性: 最好在__init__(self,...)中初始化 内部调用时都需要加上self. 外部调用时用instancenam

【Python】类属性和实例属性的差异

(本文是我自己的理解) 类属性: class本身和实例化的对象都有 实例属性: 只有实例化的对象有,class本身(未实例化之前)是没有的 理由: 类属性直接写于class下,例如 class A(): attr1 = "I'm class attr1" print(A.attr1) print(dir(A)) ''' I'm class attr1 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq

python面向对象类

面向对象变成介绍 面向过程编程 核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西.主要应用在一旦完成很少修改的地方,如linux内核.git.apache服务器等 优点:极大的降低了程序的设计复杂度 缺点:可扩展性差,改动一个地方很可能要改多个地方,牵一发而动全身 面向对象编程:不是编程的全部,只是用来解决软件可扩展性的 核心是对象(上帝式思维),对象作为程序的基本单元,一个对象包含了数据和操作数据的函数.面向对象就是把计算