python-封装-property-classmethod-staticmethod

封装

假设我们在设计类的时候,有些类的属性,我们不想人让人看见,应该怎么样去做呢?
封装可以分为广义上的封装和狭义上的封装

  • 广义上的封装 : 把方法和属性根据根据类别装到类中
  • 狭义上的封装 : 私有化的方法和属性

方法\静态变量\实例变量(对象属性)都可以私有化
所谓的私有化 : 就是只能在类的内部可见,类的外部是不能访问或者查看的

设置私有属性和方法的方式是:在属性或者方法的的前面加上双下划线,如下所示:

__price = 123  # 设置私有属性
def __pay(): #设置私有方法
    pass
class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price    # 私有属性

    def get_price(self):
        print(self.__price)

apple= Goods('苹果',5)
print(apple.name)
apple.get_price()
# print(apple.__price)

如上所示的代码:print(apple.__price),在进行打印的时候,将会报错,原因是在类的中定义的私有变量(方法)在外界是无法进行访问的。

AttributeError: 'Goods' object has no attribute '__price'

设置私有的方法

import hashlib
class Auth:
    yang_md5_code ='403cbf42b9d680f7f97efe0ed08453b9'
    def __init__(self,user,pwd):
        self.username = user
        self.password = pwd

    def __md5_code(self): # 设置私有方法
        md5 = hashlib.md5(self.username.encode('utf-8'))
        md5.update(self.password.encode('utf-8'))
        return md5.hexdigest()

    def login(self):
        if self.username == 'Yang' and self.__md5_code() == self.yang_md5_code:
            return True

user = input('>>>')
pwd = input('>>>')
obj = Auth(user,pwd)
# obj.__md5_code()   # 报错的,私有的方法不能在类的外部被使用
# obj._Auth__md5_code()   # 不报错的
ret = obj.login()
if ret:
    print('登陆成功')

在外面其实可以使用私有变量,看看上述代码中的__md5__code是个啥?

其实在创建类的时候,系统就将__md5__code变成了_Auth_md5_code,当外界在也__md5__code变量名加括号去方实现这个方法的时候,就会报错。
知道了在内部的名字,就可以在内外进行调用,但是一般不会怎么样去使用,破化了设计的初衷,定义私有属性和方法,其实是对代码的一种规范(自我感觉)。

obj._Auth__md5_code() # 将方法名变成_类名__函数名()

私有化是怎么样完成的?

class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price    # 私有属性

    def get_price(self):
        print(self.__price)

    def set_num(self):
        self.__num = 20

apple = Goods('苹果',5)
apple.set_num()
apple.__orange = 4
print(apple.__dict__)
print(apple._Goods__price)   # 私有的形成

'''
{'name': '苹果', '_Goods__price': 5, '__orange': 4, '_Goods__num': 20}
'''
# 上述的在外添加了一个orange一个属性,没有将去变成_类名__方法名的形式,而在类里面定义的self.__num = 20直接将变量变成了_Goods__num': 20,说明所有的私有的变化都是在类的[内部]定义的时候完成的

私有的属性可以被继承么?

class Foo:
    def __init__(self):
        self.__func()

    def __func(self):
        print('in foo')

class Son(Foo):
    def __func(self):
        print('in son')

Son()  # in foo

class User:
    def func(self):
        self.__wahaha()  # 在所有的空间里找不到 _User__wahaha

class VipUser(User):
    def __wahaha(self):
        print('in vip user')

VipUser().func()  # 报错

class User:
    def __wahaha(self):
        print('in user')

class VipUser(User):
    def func(self):
        self.__wahaha()  # 保错

v = VipUser()
v.func()  # AttributeError: 'VipUser' object has no attribute '_VipUser__wahaha'

私有的这个概念 但凡在类的外面 都不能用
私有的所有内容 :实例变量(对象属性),静态变量(类变量),方法都不能被子类继承
公有的 在类的内部外部随便用 public
私有的 private 只能在类的内部使用 既不能被继承 也不能在类的外部使用

property

有时候,我们在计算面积和周长的时候,发现和我们的理解的不一样,一个面积或周长不应该是直接用对象就可以直接
就可以取到吗?但是往往我们都是通过相应的逻辑运算,才得到一个结果,要得到一个结果,就需要在后面跟一个括号?
这是我们不能接受的,有没有不用加括号就能使用得到结果的? 函数通过property的装饰就可以了

class Circle:
    def __init__(self,r):
        self.r = r

    @property  # 把装饰的一个方法伪装成一个属性
    def area(self):
        return 3.14*self.r**2

    @property
    def perimeter(self):
        return 2*3.14*self.r

c1 = Circle(5)
c1.r=10
print(c1.area)  
print(c1.perimeter)

print(c1.area) 就是将def area(self)...方法伪装成为一个属性。

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

    @property
    def age(self):
        struct_t = time.localtime()
        age = struct_t.tm_year - int(self.birth.split('-')[0])
        return age

tom = Person('Tom','1965-5-12')
print(tom.age)  # age函数伪装称为一个属性

现在有一个需求,一个类中的属性只能查看,不能修改,怎么样才能实现?

class Goods(object):
    discount = 1  # 打折率
    def __init__(self,name, price):
        self.name = name
        self.__price = price

    @property  #只支持obj.price的方式查看这个结果,不支持修改,也不支持删除
    def price(self):
        return self.__price * self.discount


apple = Goods("apple", 8)
Goods.discount = 0.8
print(apple.price)

现在又有一个需求,可以对属性进行修改,也可以查看?

class Goods(object):
    discount = 1  # 打折率

    def __init__(self, name, price):
        self.name = name
        self.__price = price

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

    @price.setter  # 注意:@price.setter的实现,必须有 @property,否则将会报错。。。
    def price(self, value):
        self.__price = value


apple = Goods("apple", 8)
Goods.discount = 0.8
apple.price = 10
print(apple.price)  # 8.0

可以对属性进行修改,查看,删除?

class Goods(object):
    discount = 1  # 打折率

    def __init__(self, name, price):
        self.name = name
        self.__price = price

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

    # @price.setter  # 注意:@price.setter的实现,必须有 @property,否则将会报错。。。
    # def price(self, value):
    #     self.__price = value
    @price.deleter
    def price(self):  # # 注意:@price.setter的实现,必须有 @property,否则将会报错。。。
        del self.__price


apple = Goods("apple", 8)
Goods.discount = 0.8
# apple.price = 10
print(apple.price)  # 8.0

del apple.price
print(apple.__dict__)  # {'name': 'apple'}

不同的表达式,会去找不同的装饰过的方法

总结:

# 如果我们定义的是普通的变量或者属性
    # 那么这个属性可以从外部直接访问
    # 可以任意的修改 obj.attr = 123
    # 甚至可以删除 del obj.attr
# 私有化
    # 把一个属性加上双下划线 __属性名
    # 这个属性就连在外面看都看不见了
    # 我们实际上有些场景允许别人看,不许改
        # __属性
        # @property装饰的属性名
        # def 属性():

    # 我们允许别人看,也允许别人改,但是不能瞎改,有一些要求:数据类型 范围
        # __属性
        # @property装饰的属性名
        # def 属性():return __属性

        # @属性.setter
        # def 属性(self,value):
            # 加点儿条件
            # 修改__属性



# 私有的 :通过过给__名字这样的属性或者方法加上当前所在类的前缀,把属性隐藏起来了
        # 只能在本类的内部使用,不能在类的外部使用,不能被继承
# property 把一个方法伪装成属性
# property和私有的两个概念一起用
    # 定义一个私有的
    # 再定义一个同名共有的方法,被property装饰

    # @方法名.setter
    # @方法名.deleter

classmethod

把一个方法从对象方法,变成一个类方法


class Fruits:
    __discount = 0.8

    def __init__(self, name, price):
        print('init', self)
        self.name = name
        self.__price = price

    @classmethod  # 把一个方法从对象方法,变成一个类方法
    def change_discount(cls, value):
        cls.__discount = value  # cls到底是谁??? Fruits

    @classmethod
    def get_discount(cls):
        return cls.__discount


print(Fruits.get_discount())  # 0.8
Fruits.change_discount(1)
print(Fruits.get_discount())  # 1

class Fruits:
    __discount = 12.0

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

    # @classmethod  # 其中的类方法 是可以改变全局的变中数据(_discount ) 也就是说改变全局变量的值 可以使用classmethod eg:爸妈(两个对象)往一个银行卡中存钱
    def change_discount(cls, value):
        cls.__discount += value

    def get_discount(self):
        print(self)
        return self.__discount


f1 = Fruits("apple")
f1.change_discount(12)
print(f1.get_discount())


f2 = Fruits("apple")
f2.change_discount(12.30)
print(f2.get_discount())

"""
<__main__.Fruits object at 0x000001458AC47978>
24.0
<__main__.Fruits object at 0x000001458AC47860>
36.3
"""
# 如果change_discount不是类方法

"""
<__main__.Fruits object at 0x0000028702637898>
24.0  # 也就每一个对象设置change_discount(value)和原数据进行相加 __discount += value
<__main__.Fruits object at 0x0000028702637978>
24.3
"""

类方法

  1. 有些时候我们要修改的是类中的静态变量/类变量
  2. 此时根本不会和self有任何的操作关联
  3. 这时传一个self参数对我们来说完全没有用
  4. 我们希望接受的是当前我们所在的类
apple = Fruits('apple',8)
apple.change_discount(0.5)
print(Fruits.get_discount())

# 类方法推荐使用类名调用而不是使用对象名调用

staticmethod

class A:
    @staticmethod  # 声明这个方法只是一个普通的不会使用任何和这个类中的变量相关的方法
    def func():    # 此时 func是一个静态方法
        print('既不操作和self相关的内容')
        print('也不操作和类名相关的内容')

A.func()


# login 登录

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

    @staticmethod
    def login():
        pass

# 先获取这个学生的用户名和密码
# 判断他登录成功之后进行实例化
# Student.login()
# stu = Student('Tom')
posted @ 2019-08-04 22:22  yangchangjie  阅读(201)  评论(0编辑  收藏  举报