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
"""

 

posted @ 2023-03-06 00:39  雪儿来  阅读(17)  评论(0编辑  收藏  举报