Python(7)——Python中的类和对象

关注微信公众号IT小组,获取更多知识干货~


目录:

面向过程和面向对象的编程思想

Python中的类和对象


一:面向过程和面向对象编程的思想

编程思想通常分为了两种:面向过程面向对象

面向过程:

面向过程是根据开发需求的逻辑从上到下编写代码,面向过程编程的关注点在于怎么把代码开发出来,根据需求将所有的步骤从头到尾逐步实现。将能独立的代码封装成一个个的函数,最后通过调用不同的函数来完成。

面向对象:

面向对象是将变量和数据类型绑定到一起,分类进行封装,减少重复代码量。对象是对函数和变量的封装,面向对象的关注点在于谁来做,根据谁来做将一个对象中封装多个方法。

面向对象中有两个核心的概念:类和对象。

类:

类是对一群具有相同特征或者行为事物的一个统称,是抽象的,类不能直接被使用。(特征是指:在类中的变量,通常称为属性。行为是指:在类中的函数,通常称为方法。)
类的举例:
可以将人定义为一个类。人的“属性”有年龄、身高、性别、姓名等。
人的“方法”有:“吃饭”、“走路”、“睡觉”等等。在人这个大类的基础上,我们可以创建一个儿童这个小类(子类),儿童这个类继承了人这个类,所以儿童这个类可以使用人这个类中的所有属性和方法,儿童这个类可以有自己独有的方法和属性等。
(在Python中所有的类都会默认继承一个父类object,object是所有类的父类,我们称为“god”。)
类其实就是由属性和方法组成的一个抽象的概念。

对象:

对象是根据类来创建的一个具体的实例,它具有所属类的属性和方法。
在上面我们定义了儿童这个类,便可以用此类来创建一个儿童类的实例,它具有人这个类和儿童这个类中的所有属性和方法。在使用属性和方法的时候格式为:对象名.方法/属性

Python是面向对象的高级语言,在Python中一切都是对象。
根据不同的类(class)来创建不同的对象(object),使用对象所继承该类的方法来完成处理各种数据等操作。

而面向对象编程思想又有三大特点:封装继承多态

封装:

将重复的代码打包成为一个函数,使用时仅需调用函数即可,所以函数是对语句的封装。类是将许多事物共同的特征提取出来,进行抽象化封装相同的特征。可见的类是更大的封装,它封装了方法(函数)和属性(变量)。如果想要使用该类则可以创建该类的实例对象来使用该类的方法和属性。(面向对象封装更大的范围。面向对象封装的是类和对象,面向对象的封装先提取抽象的共有的方法和属性组成类,使用时再具体的根据该类进行创建对象实例。)

继承:

继承是为了增加代码的可用性,减少代码的重复率。针对于相同的行为和属性此进行提取,抽象一个更大的类,让具有此相同方法属性的类继承该类即可。

多态:

多态是在继承的基础上进行的,子类在继承父类的方法时,可以进行重写方法,但不改变方法名,这样可以使得不同的对象调用相同的父类方法得到的是不同的重写方法。多态可以提高代码的灵活性,但是灵活性并不是体现在方法定义里面,而是不同的子类调用父类的方法上面。

二:Python中的类和对象

如上面所说,类是一个抽象的概念,类是由属性和方法组成的,类可以被继承,类的方法可以子类被重写等。
在Python中所有的类默认都继承object类,类的定义是以“class”作为关键字,代码如下:

class User(object): # class是定义类的关键字

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储,self指向的是这个类的地址空间
        self.age = age
        self.address = address

    def sleep(self):
        print('{}正在睡觉'.format(self.name))

    def eat(self):
        print('{}正在吃饭'.format(self.name))

    def add(self):
        print('{}居住在{}'.format(self.name,self.address))

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
user.eat() # user对象继承了User类中的eat方法
user.sleep() # user对象继承了User类中的sleep方法
user.add() # user对象继承了User类中的add方法
# 打印结果如下:
小明正在吃饭
小明正在睡觉
小明居住在上海

在Python中,创建一个类的时候,首先会自动调用__new__方法,用来向系统申请内存空间地址,再自动调用__init__方法来初始化类的属性。(在上面代码中,User类重写了__init__方法,使得User类在每次调用__init__的时候不会使用object父类中的__init__方法,而是优先使用自己的。)

申请内存地址空间的__new__方法,一般直接继承object类:

class User(object):
    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        self.name = name
        self.age = age

user1 = object.__new__(User) # __new__方法默认使用的object类中的方法,用来申请内存,并把这个空间命名为User数据类型
user1.__init__('小王',16) # 利用创建好的实例对象来调用__init__方法初始化参数写入对象所属的内存空间
# user1 = User('李四', 18) 这个等同于上面两种方法
# 使用object.__new__方法的时候需要手动传入类对象作为参数

可以对__new__方法重写来实现“单例模式”。所谓的“单例模式”是指具有相同的属性的对象,例如:“通过相同的类来创建内存地址相同的实例对象”,代码如下:

class User(object):
    __instance = None  # instance类属性作为内存地址的存储
    def __new__(cls,*args,**kwargs): # 重写__new__方法,使得User类所创建的对象都分配到同一地址空间
        if not cls.__instance : # 判断如果instance为None则用object__new__方法来申请空间
            cls.__instance = object.__new__(cls)
        return  cls.__instance # 否则返回此空间

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        self.name = name
        self.age = age

user1 = User('李四', 18)
user2 = User('小红',13)
print('user1的地址空间是{},user2的地址空间是{}'.format(hex(id(user1)),hex(id(user2))))
# 打印结果如下:
user1的地址空间是0x59a080,user2的地址空间是0x59a080

user1对象实例和user2对象实例使用了是相同的地址空间,这就导致了user2写入的内容会将user1的内容覆盖。
如果不想对数据进行覆盖,可以通过对重写__init__方法中加入一个判断条件,来实现只能写入一次数据并且不会被后面的实例对象属性覆盖,代码如下:

class User(object):
    __instance = None  # instance类属性作为内存地址的存储
    __first = 1 # 默认第一次使用可以填入数据
    def __new__(cls,*args,**kwargs): # 重写__new__方法,使得User类所创建的对象都分配到同一空间
        if not cls.__instance : # 判断如果instance为None则用object__new__方法来申请空间
            cls.__instance = object.__new__(cls)
        return  cls.__instance # 否则返回此空间

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        if  self.__first: # 如果__first为真,则执行
            self.name = name
            self.age = age
            self.__first = 0 # 实例对象中的属性和类对象属性重名的时候则优先使用自己的属性


user1 = User('李四', 18)
user2 = User('小红',13)
print('user1的name值是{}'.format(user1.name))
print('user2的name值是{}'.format(user2.name))
# 打印结果如下:
user1的name值是李四
user2的name值是李四

上面代码中的user1=User(‘李四’,18),这是创建了一个User类的实例对象,并传入了参数。也可以使用如下语句来创建一个实例对象:

user1 = object.__new__( User ).__init( '李四' , 18  ) # 等同于user1=User( '小明',16 )

关于代码中self这个变量:
__new__方法是类在创建一个实例对象的时候自动执行的,用来向系统申请一块内存地址空间,并且把这个实例对象指向这个地址空间。
而self的本质就是存储了对象的地址空间。如下图:
内存地址
由此可见self本质上就代表了对象本身。(self不需要手动传参,会自动传递)
上图__init__方法中:self.name = name,self.age = age , self.address = address;这些代码是将之前传递过去的参数保存到对象自己的地址空间中。

类中的方法可以通过实例对象来调用,代码如下:

class User(object): # class是定义类的关键字

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储,self指向的是这个类的地址空间
        self.age = age
        self.address = address

    def sleep(self):
        print('{}正在睡觉'.format(self.name))

    def eat(self):
        print('{}正在吃饭'.format(self.name))

    def add(self):
        print('{}居住在{}'.format(self.name,self.address))
user = User('jerry', 17,'shanghai' )
user.eat() 

user.eat( )表示是用user这个实例对象调用了User这个类中的eat方法,除了这种方法以外还有另一种不常用的调用方法,如下:

User.eat( user ) # 使用类名调用类方法的时候,需要手动将对象实例传递给self

类中除了__new__方法,__init__方法等方法外,还有许多默认的方法,如下:
__str__方法:这个方法默认返回对象的内存地址。
通常在print函数打印对象的时候,自动返回内存地址,如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
print ( user ) # 打印这个实例对象,它会自动调用__str__或__repr__方法打印对象内存地址
# 打印结果如下:
<__main__.User object at 0x0000000002806400>

因为在上面的User类中没有对__str__这个方法重写,所以自动找到了object这个超级类中的__str__方法,如果我们想每次打印对象的时候返回的是对象的属性,那么就可以在User类中重写这个方法,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

    def __str__(self):
        return  '{},{},{}'.format(self.name,self.age,self.address)

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
print(user)
# 打印结果如下:
小明,16,上海

# 在使用str类的时候它也会自动调用对象所属类中的__str__方法,可以通过在类中重新此方法来实现特定的需求。
# 在使用int类的时候它也会自动调用对象所属类中的__int__方法
# 在使用bool类的时候它也会自动调用对象所属类中的__bool__方法
# 在使用float类的时候它也会自动调用对象所属类中的__float__方法
# 在使用==运算符的时候本质上是调用类的__seq__方法
# 在使用is运算符的时候本质上是调用类的
# 在使用对象的各种方法的时候,都会自动的调用对象本身继承的方法
# 也都可以通过重写方法来达到我们想要的结果
动态属性的概念:

在之前创建的类中,定义了name、age、address等属性,通过创建一个实例对象便可以调用这些属性,如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
print(user.name)
# 打印结果如下:
小明

利用对象名.属性名,是可以获取到对象属性的值,这样看起来是很正常的并且是很方便快捷的,但是有一个很大的风险,那就是从而失去了属性可控的风险,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
user.height = 180 # 私自定义了一个属性height,并成功传递到user对象所属的地址空间里
print(user.height)
# 打印结果如下:
180

为了提高类属性的安全性,可以利用__slots__方法来强制规定对象所能设置的属性:

class User(object):

    __slots__ = ( 'name', 'age', 'address') # 规定了对象只能对__slots__元组里面的变量进行设置
    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
user.height = 180 # 因为height没有在__slots__里面,所以会报错,如下:
# AttributeError: 'User' object has no attribute 'height'
私有属性:

通过__属性(双下滑线加属性名)的格式,来设置私有属性。对于私有属性而言,外部不可直接访问,代码如下:

lass User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address
        self.__a = 1 # 利用__定义了一个私有属性,外部不可直接访问

user = User('小明',16,'上海')
print ( user.a )
# 打印结果如下:
AttributeError: 'User' object has no attribute 'a'

虽然通过双下划线定义的属性都是私有的属性,外部不可以直接访问,但是可以通过对象名._类名__属性名来强制访问,但是不推荐这样使用,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address
        self.__a = 1 # 定义了一个私有属性


user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
print ( user._User__a ) # 对象名._类名__属性名,这种格式便可以强制访问私有属性
# 打印结果如下:
1

虽然可以通过对象名._类名__私有属性这种格式来访问私有属性,但是定义了私有属性的意义就是不想让用户从外部直接访问,通常情况下都是使用类里面的内部方法来进行对私有属性的访问,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address
        self.__a = 1  # 定义了一个私有属性__a,并给赋值为1

    def  get_a(self): # 定义了一个方法用来访问私有属性__a
        return  self.__a

user = User('小明',16,'上海') #根据上面的User类创建了一个实例user对象
a = user.get_a() # 通过get__a方法来获取私有属性__a的值
print(a)
# 打印结果如下:
1

既然可以通过方法来获取私有属性,那也可以利用方法来控制私有属性,如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address
        self.__a = 1 # 定义了一个私有属性__a,并给赋值为1

    def  get_a(self): # 定义了一个方法用来访问私有属性__a
        return  self.__a

    def set_a(self,num): # 定义了一个方法来设置私有属性
        self.__a += num

user = User('小明',16,'上海') #根据上面的User类创建了一个实例user对象
user.set_a(100) # 通过set_a方法来对私有属性__a进行设置
a = user.get_a() # 通过get__a方法来获取私有属性__a的值
print(a)
# 打印结果如下:
101
私有方法:

可以定义私有属性,那就也可以定义私有方法,私有方法的格式和私有属性一致,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

    def __test(self): # 定义了一个私有的方法__test
         print('我是User类中的私有方法test,我被调用了')


user = User('小明',16,'上海') #根据上面的User类创建了一个实例user对象
user.__test() # 私有方法不能通过对象从外部直接访问
# 打印结果如下:
AttributeError: 'User' object has no attribute '__test'

私有方法也可以通过和私有属性强制访问的格式来访问私有方法,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

    def __test(self): # 定义了一个私有的方法__test
         print('我是User类中的私有方法test,我被调用了')


user = User('小明',16,'上海') # 根据上面的User类创建了一个实例user对象
user._User__test() # 通过使用对象名._类名__私有方法,这种格式来强制访问
# 打印结果如下:
我是User类中的私有方法test,我被调用了

和私有属性一样,这样调用私有的方法也是不推荐的,和私有属性的访问一样,通过定义内部方法来访问私有方法,代码如下:

class User(object):

    def __init__(self,name,age,address): # __init__方法里面存储的是类的属性,也就是变量。
        self.name = name # User类中的属性,将传递过来的参数存储
        self.age = age
        self.address = address

    def __test(self): # 定义了一个私有的方法__test
        print('我是User类中的私有方法test,我被调用了')

    def get_test(self): # 定义了一个get_test方法来访问私有方法__test
        self.__test() # 在内部方法中调用私有方法

user = User('小明',16,'上海') #根据上面的User类创建了一个实例user对象
user.get_test() # 利用内部方法get_test来调用私有方法__test
# 打印结果如下:
我是User类中的私有方法test,我被调用了
类的继承:

在Python中所有的类都是默认继承了object这个超级类,格式如下:

class User( object ): # User这个类继承了object超类
    def demo( self ):
        print ( '我是user类里面的demo函数' )

user = User()
也可以继承自定义的类,代码如下:

class A(object): # 创建了一个自定义的类A,并且继承了object这个超类
    def  hello(self):
        print('我是A类中的hello,world')


class B(A): # 自定义一个B类,继承了A类
    def hi(self):
        print('我是B类中的hi,world')


b = B() # 根据B类创建了一个b对象实例
b.hello() # 因为B类继承了A类,所以B的实例对象也可以调用A类中的方法
b.hi() # b实例对象调用B类中自己的方法
# 打印结果如下:
我是A类中的hello,world
我是B类中的hi,world
类的多继承:

一个类可以继承多个类,代码如下:

class A(object): # 创建了一个自定义的类A,并且继承了object这个超类
    def  hello(self):
        print('我是A类中的hello,world')

class C(object): # 创建了另一个自定义的类C类,也继承了object这个超类
    def demo(self):
        print('我是C类中的demo方法')



class B(A,C): # 自定义一个B类,继承了A类和C类(多继承)
    def hi(self):
        print('我是B类中的hi,world')


b = B() # 根据B类创建了一个b实例对象
b.hello() # 因为B类继承了A类,所以B的实例对象也可以调用A类中的方法
b.hi() # B类中自带的方法hi
b.demo() # 因为B类多继承了A类和C类,所以B类创建的实例对象可以使用C类中的方法
# 打印结果如下:
我是A类中的hello,world
我是B类中的hi,world
我是C类中的demo方法
类方法的重写:

子类可以对父类中的方法进行重写,代码如下:

class A(object): # 创建了一个自定义的类A,并且继承了object这个超类
    def  hello(self): # A类中有hello方法
        print('我是A类中的hello方法')

class B(A): # B类继承了A类
    def hello(self):  # B类中对A类的hello方法进行了重写
        print('我是B类中的hello方法')

b = B() # 根据B类创建了一个实例对象
b.hello() # 调用hello方法的时候,会首先寻找B类是否有hello方法,如果有则用B类中的,如果没有则用A类中的hello
# 打印结果如下:
我是B类中的hello方法 # 调用了自己的hello方法
类方法的高级重写:

如果想要对父类中的方法进行高级的重写,例如:在子类中重写父类方法时又需要父类这个方法中相同的代码段,则可以使用super、父类名.方法等再重写父类方法的基础上再调用父类方法,代码如下:

class User(object): # 创建了一个自定义的类User,并且继承了object这个超类
    def __init__(self,name,age): # __init__方法初始化参数
        self.name = name
        self.age = age
    def  hello(self): # User类中有hello方法
        print('我是User类中的hello,world')

class B(User): # 创建了一个B类,并且B类先继承了User类
    def __init__(self,name,age,height): # 重写了父类User的__init__方法

        # 可以通过父类名.方法名传入self和参数来调用父类的方法
        # User.__init__(self,name,age)# 对User类中的__init__方法进行了重写,并且调用了User类中的__init__代码。

        # 也可以通过内置的super类传入父类名和self来使用父类中的方法
        # super(User,self).__init__(name,age)

        super().__init__(name,age) # 还可以通过super直接使用来调用父类的方法,
        # 本质上,上面三种方法都可以,常用的是最后一种
        self.height = height # 增加了新的属性

    def demo(self):
        print('我是B类中的demo方法')

b = B('小明',18,180) # 根据B类创建了一个实例对象
print(b.name,b.age,b.height) # 实例对象b新增了一个height属性
# 打印结果如下:
小明 18 180

类的多继承遇到同名方法时:
当多继承时,继承的类中有重名的方法,则会优先调用第一个继承的类,代码如下:

class A(object): # 创建了一个自定义的类A,并且继承了object这个超类
    def  hello(self): # A类中有hello方法
        print('我是A类中的hello方法')

class C(object): # 定义了一个C类
    def hello(self):
        print('我是C类中的hello方法')

class B(A,C): # 创建了一个B类,并且B类先继承了A类,再继承了C类
    def demo(self):
        print('我是B类中的demo方法')
b = B() # 根据B类创建了一个实例对象b
b.hello() 
# 实例对象b调用hello方法的时候,
# 会首先寻找自己是否有hello方法,如果有则用自己的方法,
# 在寻找A类是否有hello方法,如果有则用A类中的,
# 如果没有则在C类中寻找hello方法,如果C也没有则报错
# 打印结果如下:
我是A类中的hello方法

(可以利用类的__mro__属性来查看类的递进关系)

所谓新式类和经典类:

新式类是指手动在类中指定父类,代码如下:

class A( object ): # 在类后面指定父类的都是新式类
    def test( self ):
        print ( 'A类中的test方法' )

Python3中只有新式类,因为在Python3中如果不指定父类,则默认继承object类,而如果在Python2中如果没有指定父类,则不会自动继承object类,这种类被戏称为“幽灵类”,代码如下:

class A: # 这是python2中的经典类,没有指定父类,不会自动继承object类
    def demo( self ):
        print ( 'A类中的demo方法被调用' )

让继承多一点选择:
如果父类中的方法和属性不想让子类继承,则可以将方法和属性定义为私有,代码如下:

class User(object): # 创建了一个自定义的类User,并且继承了object这个超类
    def __init__(self,name,age): # __init__方法初始化参数
        self.name = name
        self.age = age
        self.__height = 180 # 私有属性__height

    def  hello(self): # User类中有hello方法
        print('我是User类中的hello方法')

    def __test(self): # 创建了一个私有方法__test
        print('我是User类中的私有方法test')


class B(User): # 创建了一个B类,并且B类先继承了User类
    def demo(self):
        print('我是B类中的demo方法')
b = B('小明',18) # 根据B类创建了一个实例对象
b.hello() # 因为B类继承了User类,所以可以使用User类中的hello方法
print(b.__height) # 不能使用User类中的私有属性,因为私有属性不会被继承
print(b.__test()) # 不能使用User类中的__test方法,因为__test方法是私有的
# 打印结果如下:
我是User类中的hello方法
AttributeError: 'B' object has no attribute '__height' # 报错,因为B没有继承到User的私有属性

类属性和实例(对象)属性的概念:
在类中,定义在__init__初始化方法中的属性,一般是实例属性。
而类的属性,一般定义在类的方法外部,类属性只能通过类.属性名来更改,实例对象不能更改,代码如下:

class User(object):
    address = '上海' # 定义在初始化方法外部的作为类属性
    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        self.name = name
        self.age = age

user = User('李四', 18)
user.address = '北京' # 通过对象.属性名来新增属性
print(user.age)
print(user.name) # 用实例对象动态的增加实例对象自己的属性
print('user实例对象内部的address值是{}'.format(user.address)) # 一旦实例对象自己添加了和类相同的属性后便优先使用自己的属性
# 打印结果如下:
18
李四
user实例对象内部的address值是北京

# 当实例没有添加时,默认继承类属性
user1 = User('小王',19) # 创建一个新的实例对象,但是没有给定address的值,默认使用类的属性
print(user1.address)
# 打印结果如下:
user1实例对象内部的address值是上海
小王
19
类方法和实例(对象)方法:

类方法和实例对象方法是不同的,类方法通常作为操作类属性的接口,如下:

class User(object):

    address = '上海' # 定义在初始化方法外部的作为类属性

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        self.name = name
        self.age = age

    def Uname(self):
        print(user.name)


    @classmethod  # 类方法前面用“@classmethod”标识,类方法可以使用类对象来调,也可以使用实例对象来调用
    def get_value(cls):  # cls表示的是类对象(类也是作为一个对象来看待)
        print(cls.address)

user1 = User('李四', 18)


user1.Uname()   # 通过实例对象.实例方法可以调用
User.Uname(user1) # 通过类对象.实例方法也可以调用,不过self需要手动传参为实例对象
# 打印结果如下:
李四
李四

# 类方法的调用:
user1.get_value() # 类方法可以通过实例对象.类方法来调用,这里需要注意的是,使用对象.类方法调用时,系统会自动的将type(实例对象)传递到cls中
User.get_value() # 类方法可以通过类.类方法名来调用,直接将类名传递到cls中
# 打印结果如下:
上海
上海

除了类方法和实例方法,类中还有一种特殊的方法:静态方法。
代码如下:

class User(object):

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
        self.name = name
        self.age = age


    @staticmethod # 静态方法以“@staticmethod”来标识,静态方法可以通过实例对象和类对象都可调用
    def test():  # 静态方法默认不能访问实例对象属性和类对象属性。
        print('我是静态方法')             

user1 = User('李四', 18)
# (静态方法不能访问任何属性,因为实例对象属性通过self指向其内存空间,而类对象通过cls指向其内存空间,而静态方法没有任何指向)
# 可以把静态方法当成一个被写入到类中普通函数
user1.test() # 实例对象访问静态方法
User.test() # 类对象访问静态方法
# 打印结果如下:
我是静态方法
我是静态方法

(需要注意的是:当实例方法、类方法、静态方法重名的时候,最后一个方法会覆盖前面所有的方法)
使用property类,可以自动识别调用的方法,将方法变为属性来使用(即使方法名相同),代码如下:

class User(object):

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
            self.name = name
            self.age = age

    @property # 通过使用property可以将函数变为属性来调用
    def set_name(self):
        print(self.name)

    @set_name.setter # 虽然两个方法同名,Python自动将识别是否在参数,如果带了参数则使用下面这个方法
    def set_name(self,name):
        self.name = name


user1 = User('李四', 18)

user1.set_name # 通过property将函数变为属性来使用
user1.set_name = '老王' # property自动识别是否在参数,如果传入参数则使用带参数的方法
user1.set_name
# 打印结果如下:
李四 # 这是User类中不带参数的set_name方法打印的
老王 # 这是User类中带参数的set_name方法里面的name数据

使用property类可以自动的识别想要调用的方法,但是上面的方法是同名的。如果想要不同名可以设置property参数,代码如下:

class User(object):

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
            self.__name = name
            self.__age = age

    def get_name(self):
        return  self.__name

    def set_name(self,name):
        self.__name = name

    def del_name(self):
        del self.__name

    name = property(fget=get_name,fset=set_name,fdel=del_name,doc='通过name来操作私有属性name') # 设置property属性,可以自动识别所要调用的函数


user1 = User('李四', 18)
print(user1.name) # 当不传递参数是将自动调用get_name方法
user1.name = '小王'
print(user1.name) # 当传递参数时将自动调用set_name方法
help(User.name) # 获取上面property中的doc字符串
# 打印结果如下:
李四
小王
Help on property:

通过name来操作私有属性name

通过类创建的对象默认继承了类的很多方法(对象的父类基本上都是继承object类的方法),如:strnewintdicteq,__bool__等等。

可以通过重写默认的方法来完成很多功能的实现,将对象能够进行排序操作,对象排序是可以实现的,因为sort方法调用的是对象的__lt__方法,只要重写此方法即可,如下:

class User(object):

    def __init__(self,name,age): # 定义在__init__初始化中的一般作为实例对象属性
            self.name = name
            self.age = age

    def __lt__(self, other): # 重写了__lt__方法,以对象age作为排序依据
        return  self.age < other.age


user1 = User('xiaowang',15)
user2 = User('laoli',34)
user3 = User('xiaoming',56)
user4 = User('lisi',16)
user5 = User('wangwu',19)

num = [ user1,user2,user3,user4,user5 ]
num.sort() # sort是就地排序(会改变原有列表)
for n in num: # 
    print( n.name ,n.age )
    
# 打印结果如下:
xiaowang 15
lisi 16
wangwu 19
laoli 34
xiaoming 56
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值