第十章 初识面向对象(续)

1.封装                                                         

什么是封装:

广义上的封装:把变量和函数都放在类中(例:人狗大战中,将狗咬人的函数放到dog类中)

狭义上的封装:把一些变量或者方法隐藏起来,不对外公开

  公有的:静态属性,动态属性(方法),对象属性

  私有的:__名字

私有静态属性

# 例:
class Person:
    __country = '中国' # 私有的静态属性
    # print(__country) # 执行文件会输出结果,因为定义类的时候会开辟一块内存空间存储类中的名字

print(Person.__country)
#     print(Person.__country)
# AttributeError: type object 'Person' has no attribute '__country'
# 说明:私有的名字 只能在类的内部使用,不能在类的外部使用

print(Person.__dict__)
# {'__module__': '__main__', '_Person__country': '中国', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
print(Person._Person__country)
# 中国
# 说明:如果非要在类的外部调用一个私有的名字,name必须是在私有的名字前面加_类名__私有的名字
# *****注意:不能使用上面这种方式去调用私有的变量*****
#
Person.__name = 'xxx'
print(Person.__name)
# xxx
print(Person.__dict__)
# {'__module__': '__main__', '_Person__country': '中国', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None, '__name': 'xxx'}
# 说明:在类的外部不能定义一个私有变量
# 私有的变量:
# 在类的内部 如果使用__变量的形式会发生变形,python会自动的为你加上_类名

 私有的对象属性

# 私有的对象属性
class Person:
    __country = '中国'
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd # 私有的对象属性
alex = Person('alex', 'alex123')
# print(alex.__pwd)
# #     print(alex.__pwd)
# # AttributeError: 'Person' object has no attribute '__pwd'

# 私有的对象属性的使用 -- 类中的登录方法
class Person:
    __country = '中国'
    def __init__(self, name, pwd):
        self.name = name
        self.__pwd = pwd # 私有的对象属性
    def login(self):
        if self.name == 'alex' and self.__pwd == 'alex123':
            print('登录成功')
alex = Person('alex', 'alex123')
alex.login()
# 登录成功

私有的方法

# 私有的方法
class Person:
    def __init__(self):pass
    def __eat(self):
        print('eating')

alex = Person()
# alex.__eat()
#     alex.__eat()
# AttributeError: 'Person' object has no attribute '__eat'
# 说明:不希望类中的一些方法,对外提供服务,但可以对内提供服务
# 使用场景:用户注册,进行密码转换

总结:在静态属性、对象属性、方法(动态属性)前面加上双下划线都会变成私有的

          私有的特点就是只能在类的内部调用,不能在类的外部使用

测试题

# 测试题:实例化s,打印结果是什么
# 1.有关方法继承的练习
# 说明:就近原则,现在自己的命名空间中找,然后到父类中找
class Foo:
    def __init__(self):
        self.func()
    def func(self):
        print('in Foo')
class Son(Foo):
    def func(self):
        print('in son')
s = Son()
# in son

# 2.有关方私有法继承的练习
class Foo:
    def __init__(self):
        self.__func() # self._Foo_func(没有)
    def __func(self):
        print('in Foo')

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

s = Son()
# in Foo

2.类中的装饰器方法                                             

三个面向对象的内置函数 -- 三个装饰器函数

classmethod、staticmethod、property

2.1 property

未使用property和使用property的类的比较

# 例 -  圆形类:
# 未使用property
from cmath import pi
class Cricle:
    def __init__(self,r):
        self.r = r
    def area(self):
        return self.r ** 2 * pi
    def perimeter(self):
        return self.r * 2 * pi
c = Cricle(3)
print(c.area())
# 28.274333882308138
print(c.perimeter())
# 18.84955592153876

# 方法 动词 -- 动作或者技能
# 名词 圆的面积 圆的周长 圆的半径
# 将一个函数伪装成为属性@property
# 一旦一个方法添加了@property,就不能使用c.area()调用了
from cmath import pi
class Cricle:
    def __init__(self,r):
        self.r = r
    @property
    def area(self):
        return self.r ** 2 * pi
    @property
    def perimeter(self):
        return self.r * 2 * pi

c = Cricle(3)
print(c.area)
# 28.274333882308138
print(c.perimeter)
# 18.84955592153876

练习1:编写类,求房间的表面积和体积

# 练习:已知房间的长宽高,计算表面积和体积
class Room:
    def __init__(self, length, width , height):
        self.length = length
        self.width = width
        self.height = height
    @property
    def area(self):
        return (self.length * self.width + self.length * self.height + self.width * self.height) * 2
    @property
    def volume(self):
        return self.length * self.width * self.height

room = Room(3, 5, 3)
print(room.area)
# 78
print(room.volume)
# 45

练习2:property结合__私有的名字,setter更新私有对象属性,deleter删除私有对象属性

# property __私有的名字
# 商场打折行为
class Goods:
    def __init__(self,price, discount):
        self.__price = price
        self.discount = discount
    @property #添加property因为不添加括号了,所以不能添加参数了
    def price(self):
        return self.__price * self.discount
    @price.setter  # 使用前提,必须已经price方法,并使用property进行隐藏
    def price(self, newprice):
        self.__price = newprice
    @price.deleter # 删除price方法,但是并不常用
    def price(self):
        del self.__price
apple = Goods(8, 0.7)
print(apple.price)
# 5.6
apple.price = 10
print(apple.price)
# 7.0
print(apple.__dict__)
# {'_Goods__price': 10, 'discount': 0.7}
del apple.price
print(apple.__dict__)
{'discount': 0.7}
print(apple.price)
#     return self.__price * self.discount
# AttributeError: 'Goods' object has no attribute '_Goods__price'

2.2classmethod类方法

class Person:
    Country = '中国人'
    def func(self):
        print('当前的角色的国籍是%s' % Person.Country)

alex = Person()
alex.func()
# 当前的角色的国籍是中国人
Person.func()
#     Person.func()
# TypeError: func() missing 1 required positional argument: 'self'

# 类方法
class Person:
    Country = '中国人'
    @classmethod   # 把func变成一个类方法,这样就不需要实例化对象才能调用类中的方法
    def func(cls): # cls是指向类的内存空间
        print('当前的角色的国籍是%s' % Person.Country)

Person.func()
# 当前的角色的国籍是中国人
# 说明: 如果某一个类中的方法 并没有用到这个类的实例中的具体属性
# 只是用到了类中的静态变量 就使用类方法

2.3staticmethod静态方法

如果一个方法既不会用到对象中的属性,也不会用到类中的属性,就应该被定义成为一个静态方法

# 静态方法staticmethod
class Student:
    @staticmethod
    def login():
        name = input('name: ')
        pwd = input('pwd: ')
        if name == '' and pwd == '':
            print('实例化')

Student.login()
# name: alex
# pwd: alex123
# 使用场景:在没有创建student对象的时候,进行学员登录
# 如果登录成功,再进行实例化

猜你喜欢

转载自www.cnblogs.com/gnaix/p/9077191.html