[ python ] 封装

类中的私有属性

在类中定义一个私有属性如下:

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name    # 定义私有属性 self.__name

p = Person('hkey')
print(p.__name)    # 外部不能直接调用私有属性

执行结果:
Traceback (most recent call last):
  File "E:/learn_python/day26/test6.py", line 11, in <module>
    print(p.__name)
AttributeError: 'Person' object has no attribute '__name'
复制代码

 

 

私有属性的使用场景:

  1. 隐藏起一个属性,不想让类的外部调用
  2. 想要保护这个属性,不想让属性随便被改变
  3. 保护这个属性,不被子类继承

 

虽然私有属性不能直接从外部调用,但是我们可以通过对象.__dict__ 尝试来获取这个属性试试:

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name

p = Person('hkey')
print(p.__dict__)
print(p._Person__name)

执行结果:
{'_Person__name': 'hkey'}    # 执行 p.__dict__ 会直接获取对象的属性和方法
hkey    # 在外部可以通过 p._Person__name 来获取类中的私有属性
复制代码

 

 

使用对象通过 _类名__属性名 来获取属性的方式并不推荐,在python中没有强制不允许查看类中私有属性,一切都靠自觉;

 

将类中的方法当作属性查看修改删除

 

 

property  将方法变成属性


一个实例: 写一个类,计算圆的周长和面积

复制代码
from math import pi


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

    def per(self):    # 圆的周长
        return 2*pi*self.__r

    def area(self):    # 圆的面积
        return pi * self.__r **2

c = Circle(5)
print(c.area())
print(c.per())
复制代码

 

 

在上面的代码中,我们要计算圆的周长和面积,都是通过对象.方法名() 去获取的。当我们使用 property 可以通过 对象.属性名 的方式调用函数内的方法,如下:

复制代码
from math import pi


class Circle(object):
    def __init__(self, r):
        self.__r = r
    @property    # 通过装饰器的形式,将类中方法调用的方式修改为函数调用的方式
    def per(self):
        return 2*pi*self.__r
    @property
    def area(self):
        return pi * self.__r **2

c = Circle(5)
print(c.area)
print(c.per)
复制代码

 

 

属性可以重新赋值,但是当使用 property 转换为属性调用的方式后,是不能直接赋值的。

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name

    @property    # 使用 property 改变类中函数的调用方式
    def name(self):
        return self.__name + ' run.'


p = Person('hkey')
print(p.name)
复制代码

 

 

setter

 

当我们要修改对象 p 的 name 属性时,就需要使用 setter

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name + ' run.'
    @name.setter    # 使用 setter 装饰器
    def name(self, new_name):
        self.__name = new_name


p = Person('hkey')
print(p.name)
p.name = 'xiaofei'    # 就可以实现从新赋值
print(p.name)
复制代码

 

 

当使用 setter 时, 我们要明确命名规则:

 

当使用 setter 时,我们不仅可以赋值,还可以做一些判断

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name + ' run.'

    @name.setter
    def name(self, new_name):
        if new_name.isalpha():  # new_name 必须是有字母或汉字组成
            self.__name = new_name


p = Person('hkey')
print(p.name)
p.name = '123'  # 字符串是由数字组成,赋值失败
print(p.name)
复制代码

 

 

deleter

 

这个组合中最不常用的装饰器:

作用:当要删除类中某个属性的时候使用 deleter 具体使用如下

复制代码
class Person(object):
    def __init__(self, name):
        self.__name = name

    @property
    def name(self):
        return self.__name + ' run.'

    @name.setter
    def name(self, new_name):
        if new_name.isalpha():  # new_name 必须是有字母或汉字组成
            self.__name = new_name
    @name.deleter
    def name(self):
        print('\033[31;1m我要删除类中【__name】属性了.\033[0m')
        del self.__name


p = Person('hkey')
del p.name

执行结果:
我要删除类中【__name】属性了.
复制代码

 

 

一个实例, 商品打折的例子。

复制代码
class Goods(object):
    dicount = 0.5

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

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


apple = Goods('apple', 10)
pear = Goods('pear', 5)
print(apple.price)
print(pear.price)
复制代码

 

 

在上面的实例中,当要改变所有商品的折扣时,只需要修改 dicount, 所有商品的折扣都会改变了。

 

classmethod 类方法

 

当要使用类方法时,需要满足以下两点:

  1. 把一个方法变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象
  2. 当一个方法的操作只涉及静态属性的时候,就应该使用 classmethod来装饰这个方法

 

还是上面商品打折的例子:

dicount 是一个类属性,我们就可以通过定义一个类方法来修改这个属性

复制代码
class Goods(object):
    dicount = 0.5

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

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

    @classmethod    # 定义一个类方法
    def modify_discount(cls, new_discount):    # cls: 类名,普通形参
        cls.dicount = new_discount

apple = Goods('apple', 10)
pear = Goods('pear', 5)
Goods.modify_discount(0.2)  # 打 0.2 折    # 调用方式 类名.类方法(普通形参)
print(apple.price)
print(pear.price)

执行结果:
2.0
1.0
复制代码

 

 

staticmethod 静态方法

 

在完全面向对象的程序中,如果一个函数即和对象没有关系,也和类没有关系。那么就用 staticmethod 将这个函数变成一个静态方法

比如在纯面向对象的编程中,编写一个用户登录的类:

复制代码
class Login(object):
    def __init__(self, user, pwd):
        self.user = user
        self.pwd = pwd
    def login(self):
        pass

    @staticmethod    # 静态方法虽然是在类中,和类是完全无关的;
    def get_user_pwd():
        user = input('输入用户名:')
        pwd = input('输入密码:')
        Login(user, pwd)

Login.get_user_pwd()    # 进行登录
复制代码

 

 

使用类方法和静态方法要注意以下几点:

  1. 类方法和静态方法 都是类调用的
  2. 对象可以调用类方法和静态方法,但是一般建议使用类名去调用
  3. 类方法有一个默认参数 cls 代表这个类,静态方法 没有默认的参数 就像函数一样

 

本文作者:hukey

本文链接:https://www.cnblogs.com/hukey/p/9963474.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hukey  阅读(384)  评论(0编辑  收藏  举报
历史上的今天:
2016-11-15 [ 操作系统 ] 内存篇
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 彩虹 Jay
彩虹 - Jay
00:00 / 00:00
An audio error has occurred.

彩虹 + 轨迹 (Live) - 周杰伦 (Jay Chou)

彩虹

词:周杰伦

曲:周杰伦

哪里有彩虹告诉我

哪里有彩虹告诉我

能不能把我的愿望还给我

能不能把我的愿望还给我

为什么天这么安静

为什么天这么安静

所有的云都跑到我这里

有没有口罩一个给我

有没有口罩一个给我

释怀说了太多就成真不了

释怀说了太多就成真不了

也许时间是一种解药

也许时间是一种解药

也是我现在正服下的毒药

也是我现在正服下的毒药

看不见你的笑 我怎么睡得着

看不见你的笑 我怎么睡得着

你的声音这么近我却抱不到

你的声音这么近我却抱不到

没有地球太阳还是会绕

没有地球太阳还是会绕

没有理由我也能自己走

没有理由我也能自己走

你要离开 我知道很简单

你要离开 我知道很简单

你说依赖 是我们的阻碍

你说依赖 是我们的阻碍

就算放开 但能不能别没收我的爱

就算放开 但能不能别没收我的爱

当作我最后才明白

当作我最后才明白

看不见你的笑 要我怎么睡得着

看不见你的笑 要我怎么睡得着

你的声音这么近我却抱不到

没有地球太阳还是会绕 会绕

没有理由我也能自己走掉

释怀说了太多就成真不了

也许时间是一种解药 解药

也是我现在正服下的毒药

轨迹

词:黄俊郎

曲:周杰伦

我会发着呆然后忘记你

接着紧紧闭上眼

想着哪一天 会有人代替

想着哪一天 会有人代替

让我不再想念你

我会发着呆 然后微微笑

我会发着呆 然后微微笑

接着紧紧闭上眼

又想了一遍 你温柔的脸

又想了一遍 你温柔的脸

在我忘记之前