day4类的定义
""" 三种类的定义方法: 在Python2中,对于第一种定义的方法,Person类只有有限的几个内建函数'__doc__', '__module__', 'name', 而对于第二种、第三种定义的方法,则会继承Python object对象的更多的内建函数,可以更便捷的操作对象。这是Python2版本的差异。 在Python3中,我们只需要知道这三种方式都可以定义一个类即可。 类的实例化: 定义了类之后,就可以对类进行实例化了,实例化是指,把抽象的类,赋予实物的过程。 比如,定义好Person这个类后,就可以实例化多个Person出来了。创建实例使用类名+(),类似函数调用的形式创建 """ class Person: pass class PersonA(): pass class PersonB(object): pass xiaoming = Person() xiaohong = PersonA() xiaolv = PersonB() """ 练习: 请练习定义一个动物类,并创建出两个实例dog, cat,打印实例,再比较两个实例是否相等 比较两个实例是否相等: == """ class Animal: pass dog = Animal() cat = Animal() print(dog) # <__main__.Animal object at 0x0000020E369C8310> print(cat) # <__main__.Animal object at 0x0000020E369C84F0> print(dog == cat) # False """ 实例属性的定义:赋予实例属性 """ # 直接用上面定义好的Person类 xiaoming.name = 'xiaohong' xiaoming.gender = 'male' xiaoming.age = 18 print(xiaoming.name) print(xiaoming.gender) print(xiaoming.age) xiaoming.age += 1 #实例属性可以计算变化 print(xiaoming.age) """ 打印结果: xiaohong male 18 19 """ """ 练习: 请定义一个动物类,并创建出两个实例dog, cat,分别赋予不同的名字和年龄并打印出来 """ # 直接用上面定义好的Animal类 dog.name = 'xixi' dog.age = 2 cat.name = 'dalin' cat.age = 3 print(dog.name, dog.age) # xixi 2 print(cat.name, cat.age) # dalin 3 """ 实例属性的初始化: 背景: 如果定义属性的过程中使用了不同的属性名字,比如性别,前者使用了sex,后者使用了gender, 那对于一个类的不同实例,存储一个信息就用了两个不同的属性,在后面将会难以维护。 其次,名字、性别、年龄等等,都是人的基本信息,在抽象一个类的时候,理应包含这些信息。 定义方法: 在定义 Person 类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用。 注意:__init__() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定,和定义函数没有任何区别 实例化对象: 定义类后,就可以相应的实例化对象了,需要注意的是,在实例化的时候,需要提供除self以外的所有参数 """ class PersonC: def __init__(self, name, gender, age): self.name = name self.gender = gender self.age = age zoey = PersonC('Zoey', 'female', 18) cibo = PersonC('Cibo', 'male', 19) print(zoey.name) print(zoey.gender) print(zoey.age) # 但当访问不存在的属性时,依然会报错 # print(zoey.sex) # AttributeError: 'PersonC' object has no attribute 'sex' """ 打印结果: Zoey female 18 """ # 练习:请定义一个动物类,抽象出名字、年龄两个属性,并实例化两个实例dog, cat class Animal_B: def __init__(self, name, age): self.name = name self.age = age dog_b = Animal_B('xixi', 2) cat_b = Animal_B('dalin', 3) print(dog_b.name, dog_b.age) print(cat_b.name, cat_b.age) """ 打印结果: xixi 2 dalin 3 """ """ 类属性: 类和实例对象是有区别的,类是抽象,是模板,而实例则是根据类创建的对象, 比如类:动物,只是一个抽象,并没有动物的详细信息,而猫、狗等,则是具体的动物,是类的对象。 实例对象绑定的属性只属于这个实例,绑定在一个实例上的属性不会影响其它实例; 同样的,类也可以绑定属性,但是类的属性不属于任何一个对象,而是属于这个类。 如果在类上绑定一个属性,则所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个! 也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。 """ class Animal_C: localtion = 'Asia' def __init__(self, name, age): self.name = name self.age = age panda = Animal_C('panda', '22') pig = Animal_C('pig', '1') print(panda.localtion) # Asia print(pig.localtion) # Asia # 新增 pig实例的 localtion属性,类属性的值不能通过实例对象修改,只能通过类修改类属性 pig.localtion = 'Africa' print(pig.localtion) # Africa print(Animal_C.localtion) # Asia """ 类属性也可以动态添加和修改: 注意:因为类属性只有一份,所以改变了,所有实例可以访问到的类属性都会变更 """ Animal_C.localtion = 'Africa' print(panda.localtion) # Africa print(pig.localtion) # Africa # 练习:请给 Animal类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Animal的实例 class Animal_D: count = 0 def __init__(self, name, age): self.name = name self.age = age Animal_D.count += 1 a = Animal_D('a', 1) print(Animal_D.count) # 1 b = Animal_D('b', 2) print(Animal_D.count) # 2 c = Animal_D('c', 3) print(Animal_D.count) # 3 c.__init__("d", 4) print(Animal_D.count) # 4 """ 类属性和实例属性的优先级: 属性可以分为类属性和实例属性,如果类属性和实例属性名字相同时,实例属性的优先级是要高于类属性的。 另外,如Animal_C,当实例没有和类同名的时候,通过实例对象,依然可以访问到类属性。 """ class Animal_E: localtion = 'Asia' def __init__(self, name, age, localtion): self.name = name self.age = age self.localtion = localtion d = Animal_E('d', 12, 'Africa') print(d.localtion) # Africa print(Animal_E.localtion) # Asia # 练习:上节的练习题 Animal_D类属性 count 改为 __count,再试试能否从实例和类访问该属性 class Animal_F: # count改为私有__count,私有属性在外部无法访问 __count = 0 def __init__(self, name ,age): self.name = name self.age = age Animal_F.__count += 1 print(Animal_F.__count) # 1 x = Animal_F('x' ,1) # print(Animal_F.__count) # AttributeError: type object 'Animal_F' has no attribute '__count' """ 访问限制: 并不是所有的属性都可以被外部访问的,不能被外部访问的属性称为私有属性。私有属性是以双下划线'__'开头的属性。 在外部访问私有属性将会抛出异常,提示没有这个属性。 虽然私有属性无法从外部访问,但是,从类的内部是可以访问的。私有属性是为了保护类或实例属性不被外部污染而设计的。 """ class Animal_G: def __init__(self, name, localtion): self.name = name self.__localtion = localtion y = Animal_G('y', 'China') print(y.name) # y # print(y.__localtion) # AttributeError: 'Animal_G' object has no attribute '__localtion' """ 私有属性不能从外部访问,只能在类的内部操作;如果外部需要操作私有属性,可以通过定义类或者实例的方法来操作私有属性。 定义实例方法: 实例的方法指的就是在类中定义的函数,实例方法的第一个参数永远都是self,self是一个引用,指向调用该方法的实例对象本身, 除此以外,其他参数和普通函数是完全一样的。 例子: name是实例的私有属性,从外部是无法访问的,而get_name(self) 就是一个实例方法,在实例方法里面是可以操作私有属性的,注意,它的第一个参数是self。 另外,__init__(self, name)其实也可看做是一个特殊的实例方法。 通过定义get_name(self)方法,在外部就可以通过这个方法访问私有属性了。 """ class PersonD: def __init__(self, name): self.__name = name def get_name(self): return self.__name zoey = PersonD('Zoey') print(zoey.get_name()) # Zoey """ 注意,在外部调用实例方法时,是不需要显式传递self参数的。 另外,通过定义实例方法来操作私有属性的这种方法是推荐的,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度。 当然,实例方法并不仅仅是为私有属性服务的,我们可以把和类的实例有关的操作都抽象成实例方法,比如:打印实例的详细信息等等。 """ class Animal_H: def __init__(self, name, age, localtion): self.name = name self.age = age self.localtion = localtion def get_info(self): return 'name = {}, age = {}, loacltion = {}' .format(self.name, self.age, self.localtion) z = Animal_H('wangwang', 5, 'Hubei') res = z.get_info() print(res) # name = wangwang, age = 5, loacltion = Hubei # 练习:把Animal类的age、name、localtion定义成私有属性,并定义对应的方法修改和获取他们的值 class Animal_I: def __init__(self, age, name, localtion): self.__age = age self.__name = name self.__localtion = localtion def set_age(self, age): self.__age = age def get_age(self): return self.__age def set_name(self, name): self.__name = name def get_name(self): return self.__name def set_localtion(self, localtion): self.__localtion = localtion def get_localtion(self): return self.__localtion a1 = Animal_I(1.5, 'xixi', 'China') a1.set_name('dalin') print(a1.get_name()) """ 如果需要需要操作类的私有属性,则应该定义类的方法。 在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。 定义类方法: 类方法需要使用@classmethod来标记为类方法,否则定义的还是实例方法 类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.__localtion 实际上相当于Animal.__localtion。 因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。 """ class Animal_J: __localtion = 'Asia' def __init__(self, name, age): self.name = name self.age = age @classmethod def set_localtion(cls, localtion): cls.__localtion = localtion @classmethod def get_localtion(cls): return cls.__localtion print(Animal_J.get_localtion()) i = Animal_J('zhuzhu', 2) i.set_localtion('Beijing') print(i.get_localtion()) """ 打印结果: Asia Beijing """ # 练习:如果将类属性count改为私有属性__count,则外部无法获取__count,但是可以通过一个类方法获取,请编写类方法获得__count值 class Food: __count = 0 def __init__(self, name): self.name = name Food.__count += 1 @classmethod def get_count(cls): return cls.__count print(Food.get_count()) apple = Food('apple') count = Food.get_count() print(count) print(apple.get_count()) """ 打印结果: 0 1 1 """