python面向对象编程(一)类

相信前端的小伙伴都熟悉ES6中的类,在ES6中类只不过是构造函数一个语法糖而已。而在Python中的类与其类似,类就是一个模板,里边定义了许多变量、方法,传入不同的数据,会产生不同的结果(像是一个生产工厂一样,通过生产加工,会产生不同的产品)。使用关键字class来定义一个类。下边我们还是以代码说下:

class Person ():
    pass
p = Person('lxc')

上边代码,创建了一个类:我们用class定义了一个名子为Person的类类名通常首字母大写,通过类名加括号的形式来创建一个类的实例,在ES6中,创建类要用 new + 类名 +括号。

补充:(这里要说明下类中的所有函数,统一称为方法)

因为下边多次提到一些名词,初学者肯定会很蒙,所以我这里先说下:

你需要知道在python的类中可定义:

  • 构造函数
  • 实例方法
  • 类方法
  • 静态方法
  • 类变量

1、构造函数:在类中有一个内置的构造函数__init__,在实例初始化时自动执行此方法;

2、实例方法:第一个参数永远都是self(类似js对象中的this),self指向调用实例方法的实例;在实例中的变量叫实例变量,

有两种方法定义实例变量:

(1)在构造函数 或者 实例方法中用 self . xxx 定义实例变量;

(2)在外部用实例去定义一个变量

class Person():
    def __init__(self,name):
        self.name = name # 定义实例变量name
p = Person('lxc')
p.age = 20 # 定义实例变量age

3、类方法:第一个参数永远都是cls,注意:cls也可以换成别的名,只是python中统一这么写。(cls与self类似,但是它指向类本身)且在类方法上边需要定义 一个装饰器  @classmethod  这时的方法才是类方法;(补充:在类方法中用到类变量的时候,才定义类方法)

class Person():
    @classmethod # @ 表示装饰器的意思,在一个函数上边增加 @classmethod就可以让下边函数成为类方法
    def class_fn(cls): # 类方法
        pass
p = Person('lxc',20)

4、静态方法:静态方法参数没有指定实例或者类,但是在定义静态方法的同时,也要定义一个装饰器 @staticmethod,这时的方法才是静态方法;(补充:在静态方法中没用到实例方法、实例变量,也没用到类方法、类变量的时候,才定义静态方法)

class Person():
    @staticmethod
    def static_fn():
        pass
p = Person()

5、类变量:在类中定义的变量就是类变量,与普通变量定义无差别

class Person():
    name = '呆呆君' # 类变量
p = Person()

 

下边主要介绍类中方法和变量定义及如何互相调用,零零散散的小知识点比较多!

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

类有七点需要注意:______________________________________________________

1、类中可定义:变量、方法(注意这里所说的方法就是其实就是函数,只不过更加好理解,因为ES6类中定义的就是一个个方法);

2、self:在下边代码中,实例方法(函数)的参数中我们定义了一个self,它就相当于js对象中的this,如果你在类方法或实例方法中调用实例变量需要用到self。使用self或实例对象---->调用实例方法时,传递参数,无需关心self,实参只需要填写传递的参数,self后边填写与实参相对应的变量即可。

同样self也可以赋值给另外一个变量,使用另外的变量去调用实例变量;调用问题:其实self指向创建的实例本身,谁调用的类中的方法,self就是谁:

class Person ():
    def __init__(self,name):
        self.name = name
    def fn (self):
        # 这里的self指向实例 P 
        s = self
        print(s.name) # 'lxc'
    def fn1 (self):
        # 这里的self指向实例 P1 
        s = self
p = Person('lxc')
p1 = Person('xxl')
p.fn()
p1.fn1()

上边代码,出现了__init__方法,下边我们会聊到,别慌!

3、在类中创建的实例方法与普通函数的差别在于:类中的实例方法第一个参数永远是self,其它无差别,实例方法的参数也可以使用可变参数、关键字参数等等。

4、所谓的实例,就是由类创建的对象(object)而已(上边代码实例是p和p1);

5、在外界调用类中实例方法:直接用实例(self)调用即可;

class Person ():
    name = 'lxc'
    age = 20
    def fn (self):
        print(self) # <__main__.Person object at 0x0000000001E04390>
        print(self.name) # 20
p = Person()
print(p.name) # 'lxc'
p.fn()

上边代码,在调用类中实例方法时,我们先输出self看看它到底是啥,其实self就是Person这个类创建出来的实例,后边那一长串是实例在内存中的地址,每个实例在内存中的地址都不一样,下边有例子。

6、同一个类构造出来的不同实例,是不相等的,因为他们的内存地址不同:

class Person(object):
      def __init__(self):
          pass
      def fn (self):
          pass
p1 = Person()
p2 = Person()
p3 = Person()
# id 函数可以输出实例在内存中的地址,证明三个实例不相等
print(id(person1)) # 31148912
print(id(person2)) # 31175848
print(id(person3)) # 3117478

 

7、实例方法中调用类变量:

在这说这个问题,有点早,不妨先了解下:

方法一:

class Person():
    name = '呆呆君'
    age = 100
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def fn(self):
        print(Person.name) # '呆呆君'
p = Person('lxc',20)
p.fn()

上边代码,使用类名Person可以在实例方法中调用类变量,原因是类中包含类变量,下边有详细说道!同理,如果我们在__init__构造函数里边不带self去访问一个在类和方法中都有的变量,会打印什么呢:

class Person():
    name = '呆呆君'
    def __init__(self,name):
        self.name = name
        print(name) # 'lxc'
    def fn(self):
        pass
p = Person('lxc')

上边代码,打印的是‘lxc’,真是这样的吗?我们把形参改下:

class Person():
    name = '呆呆君'
    def __init__(self,name1):
        self.name = name1
        print(name) # name 'name' is not defined
    def fn(self):
        pass
p = Person('lxc')

上边代码,我们把形参改为name1,在输出name的时候结果报错了;不带self打印的变量是形参中的变量,这点要知道,不过平时最好还是带上self来输出实例变量为宜。

方法二:(通过self.__class__去访问类变量,self.___class__指向类本身!!!

class Person():
    name = 'lxc'
    def fn(self):
        print(self.__class__.name) # 'lxc'
p = Person()
p.fn()

8、在外界如何调用类变量,其实与在实例方法中调用类变量一样,也是用类名去调用类变量:

class Person():
    name = '呆呆君'
    def __init__(self):
        pass
    def fn(self):
        pass
p = Person()
print(Person.name) # '呆呆君'

__init __构造函数

类中定义的__init__方法,是一个内置方法,在python中叫构造函数,此函数有几个特点:

      1、类在实例化的时候,__init__构造函数会自动执行;

      2、此构造函数默认返回None,如果显示的return数据类型,会报错!!!

class Person():
    def __init__(self):
        return 123
p = Person() #TypeError: __init__() should return None, not 'int'

      3、一般在__init__方法(函数)中,初始化一些实例变量;

class Person():
    name = '呆呆君'
    def __init__ (self,name,age):
        self.name = name
        self.age = age
    def fn(self):
        pass
p = Person('lxc',20)
print(p.name) # 'lxc'

上边代码,用实例p调用name变量,为什么输出的是 'lxc' 呢(输出的是实例变量),而不是 '呆呆君' ,(类变量) 在类中定义的变量在python中叫做类变量,在实例中定义的变量叫实例变量,变量p就是类构造出来的实例,所以说用实例去调用内部的变量必然是实例变量 'lxc'。

     4、如果我们在外界和实例方法调用一个实例中没有的变量,但是类中定义了此变量,它会输出什么呢???

class Person():
    name = '呆呆君'
    def __init__ (self):
        pass
    def fn(self):
        print(self.name) # 呆呆君
p = Person()
print(p.name) # 呆呆君
p.fn()

结果打印的都是 ' 呆呆君 ' ,结果是不是很震惊!!!即使是实例中没有此变量,应该返回None才对啊!!!这里是Python的一个内部机制,输出一个变量的时候,python内部它会先去实例对象中去找此变量,如果没有,它会尝试去类中寻找此变量,类中有此变量,所以输出了;如果类中还是没有,它会去父类中寻找此变量,这里涉及到继承问题,我们下一篇文章详细来聊下!!!

说了这么多,来放松下脑子,下边我们来看下类和实例中分别都存了哪一些值:

class Person():
    name = '呆呆君'
    def __init__ (self,name,age):
        self.name = name
        self.age = age
    def fn(self):
        pass
p = Person('lxc',20)
# 实例中的变量
print(p.__dict__) # {'name': 'lxc', 'age': 20}
# 类中的变量和方法
print(Person.__dict__)
#   {   '__module__': '__main__', 
#       'sum': 0, 
#       'name': '呆呆君', 
#       '__init__': <function Person.__init__ at 0x00000000023BA730>, 
#       'fn': <function Person.fn at 0x00000000023BA9D8>, 
#       '__dict__': <attribute '__dict__' of 'Person' objects>, 
#       '__weakref__': <attribute '__weakref__' of 'Person' objects>, 
#       '__doc__': None
#   }

上边代码,调用__dict__方法可以输出一个对象内部所有的成员组成的字典。。。可以看出他们都是以字典dict形式存放的,很显然,类中存放的是类变量、构造函数 __init__、实例方法(特点参数有一个self)、静态方法、内置方法等等,而实例中存放的是实例变量;了解了这些,你会更加清晰明白在外界 或 方法中  类变量和实例变量 是如何调用! 

类方法

上边有提到过类方法,但是大部分是在说变量和实例方法,下边我们着重来看下类方法的定义调用

定义类方法:(1)要定义一个装饰器 classmethod ; (2)第一个参数永远都是cls,与self类似,但是它指向的是类本身,满足这两点,才能称为类方法,类方法关注的类本身。

class Person():
    # ··· ···
    @classmethod # @ 表示装饰器的意思,在一个函数上边增加 @classmethod就可以让下边函数成为类方法
    def class_fn(cls): # 类方法
        print(cls) # <class '__main__.Person'>
p = Person()
p.class_fn()

外部调用类方法:(用实例对象也可以调用类方法,但是不推荐!!!)

class Person():
    @classmethod 
    def class_fn(cls): # 类方法
        print("类方法")
p = Person()
Person.class_fn() # "类方法"

实例方法中调用类方法:

class Person():
    def fn (self): # 实例方法
        Person.class_fn()

    @classmethod 
    def class_fn(cls):
        print("类方法")  # 类方法

p = Person()
p.fn()

类方法中调用类变量(二个方法):

class Person():
    name = 'lxc'
    @classmethod
    def class_fn(cls):
        # 方法一
        print(cls.name) #'lxc'
        # 方法二
        print(Person.name) #'lxc'
p = Person()
Person.class_fn()

静态方法

静态方法定义及调用:

静态方法不像实例方法或类方法一样要指定第一个参数为xxx,静态方法里边没有指代参数,但是需在方法上边加上装饰器:

@staticmethod。

外界调用静态方法(两种方法,实例对象调用,类调用)

class Person():
    @staticmethod
    def fn():
        print('静态方法')
p = Person()
p.fn() # '静态方法'
Person.fn() # '静态方法'

静态方法里边访问类变量

class Person():
    name = 'lxc'
    @staticmethod
    def fn():
        print(Person.name) # 'lxc'
p = Person()
p.fn() 

在类方法或静态方法中访问实例变量

————————————通过实例对象访问实例变量,(使用self访问实例变量会报错,大家自己试下,这里就不举例了!)

class Person():
    def __init__(self,name,age):
        self.name = name
        self.age = age
    @classmethod
    def class_fn(cls):
        print(p.name) # '呆呆君'
    @staticmethod
    def static_fn():
        print(p.age) # 100
p = Person('呆呆君',100)
Person.class_fn()
Person.static_fn()

 

最后我们在类中__init__方法(构造函数)中普通方法中分别输出一个值,我们看下执行顺序:

class Person():
    name = '呆呆君'
    print("1")
    def fn(self):
        print('fn')
    print('2')
    def __init__ (self,name,age):
        self.name = name
        self.age = age
        print('__init__')
    print('3')
    def fn1 (self):
        print('fn1')
p = Person('lxc',20)
p.fn()
p.fn1()
# 执行顺序如下:
# 1
# 2
# 3
# __init__
# fn
# fn1

上边代码,类中的print从上至下先执行 ---------> 然后在执行__init__方法中的print --------> 最后执行调用方法里的print,执行顺序大家要明白!!!

 

补充:

类调用实例方法:

1、类调用实例方法时,参数必须要传该类的实例对象,否则将报错,且实例self不会被绑定:

class Person():
    def __init__(self,name):
        self.name = name
    def fn(self):
        print(self.name) # 'lxc'
p = Person('lxc')
Person.fn(p)

上边代码,Person调用实例方法,参数需要手动的传类的实例对象p,self才能绑定到实例对象上边。

 

通过实例对象给类动态添加实例方法:(需要手动添加self)

1、在动态添加类实例方法时,self不会自动绑定实例对象,(也就是说self不会自动指向调用它的实例),需要手动的添加:

def fn1(self):
    print(self.name) # 'lxc'

class Person():
    def __init__(self,name):
        self.name = name
p = Person('lxc')
p.foo = fn1
p.foo(p)

上边代码,为Person类动态添加实例方法 fn1 ,执行fn1方法,self不会自动绑定实例对象,参数需要传一个实例对象。

 

通过类给类动态添加实例方法:(不需要手动添加self)

def son(self):
    print(self.name) # 'lxc'

class Cat:
    def __init__(self,name):
        self.name = name
c = Cat('lxc')
Cat.son_fun = son
c.son_fun()

 

 

 

总结:我们用一张脑图总结下,以上主要介绍了类的定义及创建一个类、类中变量方法构造函数的定义及调用,在实际开发中经常会在一个方法中去操作变量,或者调用方法。还是那句话,多写、多练,自然而然你会明白。就这么多,有不足之处,望指正,有不懂地方欢迎留言!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值