python基础-day22

# 说点关于java与python的something:
# python中只有共有的和私有的,
# java中除此之外还有保护的,




# 封装:把函数和属性装到一个非全局的命名空间,
#类,就是封装而来,不过好像其实好像也是通过函数来实现的,
class A:
    __N = 'aaa'
    #首先从位置上看,它是静态变量,
    #其次在类内部!!!定义的时候,前面有双_,说明是私有的,
    #私有的第一反应可能是不能从外部直接访问,

    def func(self):
        print(self.__N)     #在类内部访问是OK的,
a = A()
a.func()

# print(A.__N)
#报错:AttributeError: type object 'A' has no attribute '__N',说明私有的,确实不能直接访问,

print(A.__dict__)
#打印的字典中会有 '_A__N': 'aaa',这么一项,不过有点改变,
#也就是说,我们定义的私有变量,编译器会在前面加_A,即_类名,的形式,

print(A._A__N)  #打印:aaa
#说明,上面我们关于编译器对私有变量的处理,说对了,
#不过虽然你可以这样访问私有变量,但是不要这么做,违背了私有变量出现的初衷,
#!!!!!其次此处的转换过程,一定要记住,后面此处可能掉进吭里,
#就是说,在类的内部,你的代码遇到__名字,会被自动转换为_类名__变量名




class B:
    def __init__(self,name):
        self.__name = name
    def func(self):
        print('in func : %s'%self.__name)
b = B('alex')


print(b.__dict__)       #打印:{'_B__name': 'alex'},在类的对象中也这么打印,
# print(b.__name)       #报错,这里是外部,你得在前面加_B,类的内部就会自动帮我们加_类名,所以可以直接__name打印,
print(b._B__name)       #没问题,
b.func()    #这里是类的内部,所以可以self.__name直接使用,而不必self._B__name
print('_B__name' in B.__dict__)     #打印False,说明这里的name是对象属性,类中没有,




# 私有的方法
class C:
    def __wahaha(self):
        print('wahaha')
    def ADCa(self):
        self.__wahaha()
c = C()
# c._C__wahaha()      #这里与私有变量的道理一样的,
# c.ADCa()            #这里能直接调用,是因为你通过非私有方法,在类的内部调用了私有方法,所以OK,






class D:
    def __func(self):      # '_D__func'
        print('in func')

class E(D):
    def __init__(self):
        pass
        # self.__func()      # 这里会报错,因为私有的,不会被继承,
e = E()

print('_D__func' in E.__dict__) #False
print('_D__func' in D.__dict__) #True




#☆☆☆☆☆,五颗星
class D:
    def __init__(self):
        self.__func()
    def __func(self):
        print('in D')

class E(D):
    def __func(self):
        print('in E')
e = E()
# 私有的名字,在类内使用的时候,就是会变形成_该类名__方法名
# 以此为例 :没有双下换线会先找E中的func
# 但是有了双下划线,会在调用这个名字的类D中直接找_D__func



class F:
    pass
F.__name = 'alex'  # 不是在创建私有属性
print(F.__name)     #打印:alex,能直接打印,说明不是私有的,
print('_F__name' in F.__dict__) #False
print('__name' in F.__dict__)   #True
# ps:编译器对私有变量的处理是反生在类的内部的,




# 上面这张图,可以体现@property和@setter的牵连,




# 在init方法中,变量不应该是被计算出来的,虽然在语法上没有不允许你这么做,还有个坏处,就是这么做写死了,若体重改变,bmi无法跟着改变,
# @property,函数属性化,之后你不能直接修改了,并且不能在类中出现同名的变量,

# @property   4颗星,将一个方法伪装成属性,调用的时候,不在需要(),如果加了()反而会报错,重要程度4颗星
# @name.setter    3颗星
# @name.deleter   1颗星


class Person:
    def __init__(self,name,weight,height):
        self.name = name
        self.__height = height
        self.__weight = weight
        # self.bmi = 'haha'     #这里会报错,原因如下,
    # 在一个类加载的过程中,会先加载这个中的名字,包括被property装饰的
    # 在实例化对象的时候,python解释器会先到类的空间里看看有没有这个被装饰的属性,
    # 如果有就不能再在自己对象的空间中创建这个属性了
    @property
    def bmi(self):
        return self.__weight / self.__height ** 2

p = Person('大哥',92,1.85)
print(p.bmi)
p._Person__weight = 900
print(p.bmi)
print('bmi' in Person.__dict__) #True,这个是方法,只是调用看起来像属性,所以它在类中,而不是对象中,
print('bmi' in p.__dict__)  #False




#这是一个完整的@property,@setter,@deleter,的例子,
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('您提供的姓名数据类型不合法')

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


p = Person('YQ')
print(p.name)   #相当于返回值了,
p.name = 'WW'   #相当于传参进去了,
print(p.name)
del p.name      #执行了被@name.deleter装饰的函数,其它同理,
print(p.name)

# 通过下面两个报错,来讲讲这三个修饰
#1,AttributeError: 'function' object has no attribute 'deleter'
#2,NameError: name 'name' is not defined
#首先,这3个你可以理解为一套的,起关键作用的是@property,没有它后面2个都无从谈起!!!
#如果仅仅是没有@property,会报第一个错误,即找不到装饰器提供的方法,
#如果将整个@property修饰的方法删掉,后面会提示name未定义,




#这个例子,可以来个搞笑的解说:商品要做打折活动前,先涨价~~~~
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)
apple.price = 8
print(apple.price)

# ps:
#将一些需要随着一部分属性的变化而变化的值的计算过程 从方法 伪装成属性
#比如折后价,就会随着原价(原价也会变)和打折力度的变化而变化,



#关于classmethod
class Goods:
    __discount = 1
    def __init__(self,name,origin_price):
        self.name = name
        self.__price = origin_price

    @property
    def price(self):
        print('查看',self._Goods__discount)
        return self._Goods__discount*self.__price

    @price.setter
    def price(self,new_discount):
        Goods.__discount = new_discount         #这种可以
        Goods._Goods__discount = new_discount   #这种也可以
        print('设置后',self.__discount)



    def func(self,num):
        Goods._Goods__discount = num            #这个函数的出现,最开始是想证明是不是@setter修饰器有使用限制,进而导致的错误,实际上并不是,
        print(self._Goods__discount)


    @property
    def change_discount(self):
        pass

    @change_discount.setter             #我想验证这两个混合到一起,混怎么样,结果'change_discount': 5,
    @classmethod                        #结论:不能这样用.
    def change_discount(cls, new_count):
        cls.__discount = new_count

apple = Goods('apple',5)
banana = Goods('banana',8)
# Goods.change_discount = 5     #混合,不能用,
# apple.change_discount = 5     #混合,不能用,
# apple.price = 4               #可以,
# apple.func(5)                 #可以,
# Goods._Goods__discount = 222  #可以
print(apple.price)
print(banana.price)
print(apple.__dict__)
print(Goods.__dict__)


# 最新版,
# python中的类,除了可以在init中创建类对象的属性,
# 而且可以在init函数,比如类的其它函数中通过self.新的变量名 = xx的形式,添加一个新的属性,
# 所以在我们这里,我们通过self.__discount,相当于为类对象,添加了一个新的私有变量,仅仅对当前这个对象有效,
# 前面我总结的有些问题,只要你能唯一定位到类本身的静态变量,就可以改变他, 和@setter装饰器没关系,
# @classmethod的需求,是基于不需要实例化对象的情况下,并不是唯一的解决方案,不过被classmethod修饰的函数,有一个cls指针,直接指向类本身,可以直接访问类的变量,
# 而对于非@classmethod修饰的方法,你若想访问或者修改静态私有变量,你就得用类名._类名__静态变量名 = xx,的形式来修改,访问类似,\
# 在访问中还好,因为编译器找不到,就自动到类中去找;而对于修改,就是我们前面说的,会为类的对象添加一个新的,



# ps:
#这里有个要注意的地方,python对于你没有的变量,如果你直接修改,可能就直接帮你添加了,以至于不会报错,让你傻傻的不知道什么情况,



# 关于staticmethod
class Student:
    def __init__(self,name):pass
    @staticmethod
    def login(a):                   # login方法没有默认参数self,它的使用可以理解为当普通函数那样使用,前面加个类名即可
        user = input('user :')
        if user == 'alex':
            print('success')
        else:
            print('faild')

Student.login(1)

# 完全面向对象编程,比如你还没用户登录进入,即没有实例化对象的时候,但是又有登录的需求,就用静态方法,


# 当一个方法要使用对象的属性时 就是用普通的方法
# 当一个方法要使用类中的静态属性时 就是用类方法
# 当一个方法要既不使用对象的属性也不使用类中的静态属性时,就可以使用staticmethod静态方法
#上面是使用总结,建议你这样使用,但是如果你不这样来做,比如我想用对象方法来修改类属性,像上面那个例子,也可以,但是麻烦一些,并且可能出现一些不会报错的问题

阅读更多

没有更多推荐了,返回首页