zoukankan      html  css  js  c++  java
  • [ 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('33[31;1m我要删除类中【__name】属性了.33[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 代表这个类,静态方法 没有默认的参数 就像函数一样
  • 相关阅读:
    git version info & svn version info map(七)
    /proc/pid/statm content analysis
    git log filter(六)
    git create remote branch (五)
    learning svn diff --summarize
    learning scala akka ask_pattern
    learning scala akka tell pattern(二)
    learning scala akka actorySystem create and close
    hibernate 自动生成数据库
    STRICT_TRANS_TABLES STRICT_ALL_TABLES
  • 原文地址:https://www.cnblogs.com/hukey/p/9963474.html
Copyright © 2011-2022 走看看