首页 > 编程语言 >python基础-面向对象

python基础-面向对象

时间:2022-11-30 12:22:44浏览次数:41  
标签:__ run python self 基础 面向对象 test print def

1.面向对象

  面向对象编程是在面向过程编程的基础上发展来的,它比面向过程编程具有更强的灵活性和扩展性,所以可以先了解下什么是面向过程编程:

  面向过程编程的核心是过程,就是分析出实现需求所需要的步骤,通过函数一步一步实现这些步骤,接着依次调用即可,再简单理解就是程序

  从上到下一步步执行,从头到尾的解决问题;

  而面向对象编程是把构成事物的整个需求按照特点、功能划分,将这些存在共性的部分封装成对象,创建对象的目的不是为了完成某一个步骤,

  而是为了描述某个事物在整个解决问题的步骤中的行为。     

  eg: 小明用美的洗衣机洗脏衣服,流程是怎样的?

  面向过程的解决方法:

    1、执行加洗衣液方法;

    2、执行开启洗衣机方法;

    3、执行加水方法;

    4、执行洗衣服方法;

    5、执行甩干方法;

    6、取出衣服;

    以上就是将解决这个问题的过程拆成一个个方法,通过按顺序执行方法来解决问题。

  面向对象的解决方法:

    1、可以先归纳出两个对象:“美的洗衣机”对象和“小明”对象

    2、针对对象“美的洗衣机”加入一些它的方法:“自动注水方法”“洗衣方法”、“烘干方法”

    3、针对对象“小明”加入他的方法:“加洗衣液方法”、“开启洗衣机方法”、“取出衣服方法”

    4、然后执行,使用对象.动作 的方式,执行各步骤

    小明.加洗衣液

    小明.开启洗衣机

    美的洗衣机.自动注水

    美的洗衣机.洗衣服

    美的洗衣机.烘干

    小明.取出衣服

    解决同一个问题 ,面向对象编程就是先抽象出对象,然后用对象执行方法的方式解决问题。

 

2.类

  如果想通过面向对象编程,首先需要创建一个类(class),才能实例化(或叫具象化)对象;

  (洗衣例子中要先有人这个类,才能有“小明”对象、先有洗衣机类,才能有“美的洗衣机”这个对象)

  类可以理解成一个模板,通过它可以创建出无数个具体实例(对象);

  使用类的关键字class,来声明类,首字母大写,多个单词时每个单词首字母要大写(驼峰命名法);

  eg: class MyName(object): 

      (object)可以不写,object是python中的一个通用对象,添加它后可以使用更多的内置功能;

class Test(object):
    name = 'test'   # 定义一个类属性

    def run(self):
        print(f'{self.name}在跑步!')


xiaoming = Test()  # 实例化一个对象xiaoming
print(xiaoming.name)  # 对象xiaoming可以调用类属性
xiaoming.run()  # 对象xiaoming可以调用类方法
'''
test
test在跑步!
'''

  类的参数self

  可以看到类的方法中默认第一个参数是self,且是必填的;(python中的self关键字只用于类的方法中);

  self也是一个对象,它代表实例化变量(例子中的xiaoming)本身(xiaoming可以调用name属性和run方法,都是self帮助找到的)

class Person(object):

    name = None  # 类属性(也叫类实例化属性)
    age = None

    def run(self):
        print('可以直接使用self调用类属性')
        print('打印属性:'+str(self.name))
        a = 'new'   # 类方法中定义的变量无self时,属于方法中的局部变量
        print('打印局部变量:'+a)

    def work(self):
        print('利用self可直接调用类中其它类函数')
        self.run()

    def jump():
        print('不添加self参数,就不属于类函数,就不可以被实例化的对象调用')


# 实例化一个对象xiaoming
xiaoming = Person()
# 可以直接调用类属性(类实例化属性)
print(xiaoming.name)  # None
# 也可为类属性(类实例化属性)重新赋值
xiaoming.name = 'xiaoming'
# 调用类方法, 调用时无需传递self参数值
xiaoming.work()
'''
利用self调用类中其它函数
可以直接使用self调用类属性
打印属性:xiaoming  (此时类属性值已被实例化对象修改)
打印局部变量:new
'''
# print(xiaoming.a)  # AttributeError: 'Person' object has no attribute 'a'  方法中的局部变量不可被实例化对象调用

# 实例化另一个对象xiaohong
xiaohong = Person()
print(xiaohong.name)  # None # 对象xiaohong并不会使用到对象xiaoming修改的类属性(类实例化属性)值;对象修改的类属性(类实例化属性),只能作用于对象本身
xiaohong.jump()  # 非类函数无法被对象调用,直接报错
'''
Traceback (most recent call last):
  File "D:\python_exercise\test_calss.py", line 44, in <module>
    xiaohong.jump()
TypeError: Person.jump() takes 0 positional arguments but 1 was given
'''
# 可以看到报错信息是函数无参数值,却被传递了一个,说明对象在调用方法时,自动传递了self参数,所以直接报错了

 

3.类的构造函数

  类中的一种默认函数,用来将类实例化的同时,将参数传入类中;(类似于函数执行时,可以传一些参数)

  def __init__(self, a, b):

    self.a = a      # 类实例化对象的属性

    self.b = b

  此时self.a和self.b就可以在类的各个类函数中使用了;

class Person(object):

    def __init__(self, name):
        self.name = name  # self.声明的变量是类实例属性

    def run(self):
        print(f"{self.name}在跑")


test = Person('x')
test.run()  # x在跑

'''
此时已经见过了类中可定义的多种变量
类下直接定义的变量,属于类属性、又属于类实例化对象属性 (可被实例化后的对象直接引用)
构造函数中self.开头定义的属性,属于类实例化对象属性,不属于类属性(可被实例化后的对象直接引用)(工作中多用,且多在构造函数中提前定义好)
类函数中a=''定义的变量,属于局部变量,既不属于类实例化对象属性,也不属于类属性(不可被实例化后的对象直接引用)
'''

 

4.对象的生命周期

  一个对象从出生到消亡的过程;

  实例化对象后,会调用内置函数__init__, 此时对象生命开始,该对象会被内存分配一个内存块;

  对象不再使用类中的方法属性时、或整个脚本结束执行时,对象会自动调用内置函数__del__通知内存管家,从内存中释放占用的内存块,对象生命结束;

  无论是数字、字符串、列表、元组等对象,生命周期皆是如此;

  python中会让对象自动调用__del__的操作,无需在程序中书写;

 

  __def__所有这种书写形式的方法,都是类的内置函数,定义类时书写object(class Name(object)),就可以调用这些内置函数了。

 

5.私有函数和私有变量

  私有:独有的、不公开;

  无法被实例化后的对象调用的类中的函数和变量,就是私有函数、私有变量;

  类的内部可以在类函数中调用私有函数和私有变量;

  使用场景:某一方法只希望内部业务调用使用,不希望被使用者调用;

  定义方法:在类函数、类变量前添加__ (两个下划线);

class Cat(object):

    def __init__(self, name):
        self.name = name
        self.__sex = 'boy'  # 私有类实例化属性

    def run(self):
        # 类函数可以调用私有函数
        self.__run(self.__sex)

    # 私有函数
    def __run(self, sex):
        # 私有函数可以使用类实例化属性
        print(f'{self.name},是个{sex},它在跑!')


cat = Cat('ll')
cat.run()  # ll,是个boy,它在跑!
# 对象不可调用私有函数,直接报错
# cat.__run()  # AttributeError: 'Cat' object has no attribute '__run'

# 也有可调用的方法,但既然创建了私有函数、私有变量,建议遵守使用规则
print(dir(cat))  # 打印所有类的内置函数,就可以看到私有函数的调用名了
'''
['_Cat__run', '_Cat__sex', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'run']
'''
cat._Cat__run('girl')  # ll,是个girl,它在跑!
print(cat._Cat__sex)  # boy

 

6.python中封装

  python中封装的概念:

    我们在类中把某些属性和方法隐藏起来、定义为私有,只能在类的内部使用,外部无法访问,或者留下少量的接口(函数)供外部访问,就是封装的概念;

    这样做的目的是为了保护隐私、明确区分内外。

 

7.类的装饰器

  装饰器也是一种函数;

  它可以接收函数作为参数;且可以返回一个函数;

  接收一个函数,内部对其进行处理,然后返回一个新函数,动态的增强函数功能;

# 简单梳理下装饰器的大概由来

# 有一个业务函数print_test()
def print_test(info):
    print('业务函数'+info)
'''
此时想在执行业务函数前后增加日志输出,
且有多个类似的业务函数需要完成同样的操作,
可以编写另一个公用函数,以业务函数为参数,业务函数前后完成相应日志输出
'''
def add_info(func, info):
    print('开始的日志')
    func(info)
    print('结束的日志')

# 执行add_info
add_info(print_test, 'test')
'''
开始的日志
业务函数test
结束的日志
'''
# 但是这样改变了原有的print_test(info)完成业务操作的写法,可以借助装饰器写法优化下
def add_info_new(func):
    def wrapper(*args, **kwargs):
        print('打印开始的日志')
        func(*args, **kwargs)
        print('打印结束的日志')
    return wrapper

print_test = add_info_new(print_test)
print_test('test')
'''
打印开始的日志
业务函数test
打印结束的日志
'''
# python中可以借助@语法糖,优化上面print_test = add_info_new(print_test)的写法

@add_info_new
def print_test_final(info):
    print('借助语法糖的业务函数'+info)

print_test_final('test')
'''
打印开始的日志
借助语法糖的业务函数test
打印结束的日志
'''

# 装饰器调用时,也可以传递参数,对业务处理进行再次的判断
def add_print_args(handle):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print('依旧执行前打印日志')
            func(*args, **kwargs)
            print('依旧执行后打印日志')
            if handle:
                print('额外处理')
        return wrapper
    return decorator


@add_print_args(handle=True)
def print_test_args(info):
    print('打印一下'+info)

print_test_args('test')
'''
依旧执行前打印日志
打印一下test
依旧执行后打印日志
额外处理
'''

'''
使用装饰器后,被装饰函数的元信息会被修改,例如__name__, doc等
'''
print(print_test_args.__name__)
# wrapper  (这里也很好理解,已经被返回成新的装饰函数了)
'''
若想保存元信息不变,
可以使用wrap库,from functools import wraps
wraps也是一个装饰器,它是把原函数元信息拷贝到了装饰器函数中
'''
from functools import wraps
def add_print_wrap(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print('执行前打印')
        func(*args, **kwargs)
        print('执行后打印')
    return wrapper

@add_print_wrap
def print_test_wrap(info):
    print('业务函数'+info)

print_test_wrap('test')
print(print_test_wrap.__name__)
'''
执行前打印
业务函数test
执行后打印
print_test_wrap
'''

'''
类装饰器
通过内置函数__call__处理额外操作
'''
class AddPrint(object):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print('开始的打印foo')
        self.func(*args, **kwargs)
        print('结束的打印foo')

@AddPrint
def print_test_foo(info):
    print('业务函数'+info)

print_test_foo('test')
'''
开始的打印foo
业务函数test
结束的打印foo
'''

'''
类装饰器也可以通过传参做额外操作
'''
class Foo(object):
    def __init__(self, handle):
        self.handle = handle

    def __call__(self, func):
        def wrapper(*args, **kwargs):
            print('执行前操作')
            func(*args, **kwargs)
            print('执行后操作')
            if self.handle:
                print('额外操作')
        return wrapper

@Foo(handle=True)
def print_test5(info):
    print('业务操作'+info)

print_test5('test')
'''
执行前操作
业务操作test
执行后操作
额外操作
'''

  

8.几种内置的常见装饰器

  @classmethod

  将类的函数定义为可以不经过实例化而直接被调用;此时可以不实例化,直接调用该方法;

class Foo(object):

    def __init__(self, a):
        self.a = a

    def run(self):
        print('run')

    @classmethod
    def jump(cls):
        print('jump')
    # 此时self被替换成cls,代表类本身

# Foo.run()
'''
Traceback (most recent call last):
  File "D:\python_exercise\test5.py", line 21, in <module>
    Foo.run()
TypeError: Foo.run() missing 1 required positional argument: 'self'
因为正常我们实例化的时候,python会自动帮我们将self参数传递进去
此时没有实例化,所以报错没有传self参数
'''
Foo.jump()  # jump
# 类函数就可以不用实例化直接调用了

  cls函数不可引用self函数

class Foo(object):

    def __init__(self, a):
        self.a = a

    def run(self):
        print('run')

    @classmethod
    def jump(cls):
        print('jump')
        cls.run()

Foo.jump()
'''
TypeError: Foo.run() missing 1 required positional argument: 'self'
'''

  self函数可以引用cls函数

class Foo(object):

    def __init__(self, a):
        self.a = a

    def run(self):
        print('run')
        self.jump()

    @classmethod
    def jump(cls):
        print('jump')

foo = Foo('test')
foo.run()
foo.jump()   # 实例化对象也可使用cls函数
'''
run
jump
jump
'''

  @staticmethod

  将类函数定义为可以不经过实例化而直接被调用,且该函数不需要传递self或cls,且无法在该函数内调用其它类函数或类变量;

class Foo(object):

    def __init__(self):
        pass

    def run(self):
        print('run')
        self.jump()

    @staticmethod
    def jump():
        print('jump')

Foo.jump()  # jump
foo = Foo()
foo.jump()  # jump (也可以通过对象调用)
foo.run()  # static函数也可以被其它类函数调用
'''
run
jump
'''

  @property

  将类函数的调用免去括弧,类似于调用属性;

class Foo(object):

    @property
    def run(self):
        print('run')


foo = Foo()
foo.run  # run

  同样使用这种调用方法,需要传参时,有自己的写法;

class Foo(object):

    @property
    def run(self):
        print('run')

    @run.setter
    def run(self, info):
        print(info)


foo = Foo()
foo.run = 'test info'  # test info

 

9.类的继承

  通过继承,子类可以拥有父类所有的属性和方法;

  父类不具备子类自有的属性和方法;

  定义方法 class Child(Parent):  Child类继承Parent类;

class Parent(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def walk(self):
        print(f'{self.name}在行走')


class Child(Parent):
    def run(self):
        self.walk()    # 子类可以调用父类的方法
        print(f"{self.name}在跑步")   # 子类可以直接调用父类的属性


child = Child('ll', 13)   # 继承父类后,父类的初始化参数子类也要传递
child.walk()  # ll在行走 (子类实例化对象可以调用父类的方法)
child.run()
'''
ll在行走
ll在跑步
'''

  

10.类的多态

  子类继承父类后,对于父类中的同一功能可以表现出多状态变化(多种执行方式、结果等),且是通过子类对父类方法的重写实现的;

class Parent(object):
    def __init__(self, name):
        self.name = name

    def walk(self):
        print('父类在行走')


class Child(Parent):

    def walk(self):
        print('子类在行走')


child = Child('儿子')
child.walk()  # 子类在行走

'''
为什么要继承
为了使用已经写好的类中的方法

为什么要多态
为了保留子类中和父类名称相同的函数的功能
'''

 

11.python中的super函数

  在子类重新书写父类方法时,此时想既保留父类方法的逻辑、同时增加新逻辑,就可以借助super函数;

  用法:super(当前类,self(类的实例)).父类的方法();python3.0时代,super()中两个参数可以省略;

class Parent(object):
    def __init__(self, name):
        self.name = name
        print('父类构造函数'+self.name)


class Child(Parent):
    def __init__(self, name, age):
        super(Child, self).__init__(name)
        self.age = age
        print('子类新的构造函数'+str(self.age))


child = Child('xiaoming', 23)
'''
父类构造函数xiaoming
子类新的构造函数23
'''
# 例子中子类对于父类中的构造函数参数进行了扩充,在工作中很常用

 

12.类的多重继承

  子类可以继承多个父类;

  class Child(Parent, Parent2, Parent3...):

class Father(object):
    def run(self):
        print('父亲跑')

    def walk(self):
        print('父亲走')


class Mother(object):
    def run(self):
        print('母亲跑')

    def sing(self):
        print('母亲唱')


class Child(Father, Mother):
    pass


child = Child()
child.sing()  # 母亲唱
child.run()  # 父亲跑 (多个父类有重名方法时,优先继承写在第一位的类)
print(Child.__mro__)  # (<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Mother'>, <class 'object'>)
'''
__mro__ 方法可以打印类的继承链
'''

  

13.类的几个高级函数

  __str__  返回类的描述信息;

class Test(object):
    pass


test = Test()
print(test)  # <__main__.Test object at 0x00000298AC9264D0>


class Test2(object):
    def __str__(self):
        return 'this is a test class'


test2 = Test2()
print(test2)  # this is a test class

  __getattr__ 当调用的属性或方法不存在时,会返回该方法定义的信息;

class Test(object):
    pass


test = Test()
print(test.a)  # 调用类的属性不存在时,会直接报错
'''
Traceback (most recent call last):
  File "D:\python_exercise\test7.py", line 14, in <module>
    print(test.a)
AttributeError: 'Test' object has no attribute 'a'
'''

class Test2(object):
    def __getattr__(self, item):
        return f'{item}不存在'


test2 = Test2()
print(test2.a)  # a不存在

  __setattr__  拦截当前类中不存在的属性和值,并做处理;

class Test(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __setattr__(self, key, value):
        print(key, value)
        # 打印所有的属性字典
        print(self.__dict__)
        self.__dict__[key] = value
        print(self.__dict__)


test = Test('xiao', 32)
test.sex = 'boy'
print(test.sex)
'''
name xiao
{}
{'name': 'xiao'}
age 32
{'name': 'xiao'}
{'name': 'xiao', 'age': 32}
sex boy
{'name': 'xiao', 'age': 32}
{'name': 'xiao', 'age': 32, 'sex': 'boy'}
boy
'''
# 可以看到每一次生成新的属性,都会调用__setattr__方法,无论是在构造函数,还是在实例对象test.sex = 'boy'
test.name = 'new_xiaoming'
# 也可修改原属性的值
'''
{'name': 'new_xiaoming', 'age': 32, 'sex': 'boy'}
'''

  __call__  将实例化对象直接变成函数使用;

class Test(object):
    def __call__(self, *args, **kwargs):
        print(f'call 函数开始: {args[0]}')


test = Test()
test('test')  # call 函数开始: test
# eg: 编写一个可以通过 对象.a.b.c() 执行的类
class Test(object):
    def __init__(self, args=''):
        print('------')
        self.args = args
        
    def __getattr__(self, item):
        print('开始的item:'+item)
        print('self.args:'+self.args)
        if self.args:
            item = f'{self.args}.{item}'
        print('后来的item:'+item)
        return Test(item)
    
    def __call__(self, *args, **kwargs):
        print('ttttt')
        
        
test = Test()
test.a.b.c()  # ttttt
'''
------
开始的item:a
self.args:
后来的item:a
------
开始的item:b
self.args:a
后来的item:a.b
------
开始的item:c
self.args:a.b
后来的item:a.b.c
------
ttttt
'''

 

总结

  

标签:__,run,python,self,基础,面向对象,test,print,def
From: https://www.cnblogs.com/white-list/p/16846464.html

相关文章

  • Python日学壹技:性能分析
    导读相信日常使用Python作为生产力的读者,一定会存在想要分析代码中每一行的运行时间与变量占用内存大小的需求,本文主要分析两个模块,用于分析每行代码的内存使用情况和运行......
  • 1python解释器的下载和安装
    1.1python解释器:一款用于执行python代码的应用程序。下载网址:https://www.python.org/downloads选择自定义安装,添加环境变量1.2pycharm下载和配置安装完成后进行许可证激......
  • python multiprocessing使用容易遇到的坑记录随笔
    python因为有GIL(GlobalInterpreterLock)锁的问题,所以在计算密集型程序中,推荐使用multiprocessing多进程编程。在使用multiprocessing创建子进程时,很容易遇到一个不易发现......
  • day02 Python基础
    1.Python语法1.1编码使用工具写汉字、字母、数字,写完之后,你是需要保存到硬盘上卢慧yyds66601010101010101101010101001010101000111101一套编......
  • day01 环境搭建及python介绍
    1.Typora安装为什么要使用Typora的软件呢?是因为程序员不只是写代码这一件事,还需要给编写的代码写README文档,这个文档是说明程序如何使用的,README编写使用的就是Markd......
  • Python 中 -m 的典型用法、原理解析与发展演变
    在命令行中使用Python时,它可以接收大约20个选项(option),语法格式如下:python[-bBdEhiIOqsSuvVWx?][-ccommand|-mmodule-name|script|-][args]本文想要聊聊比较......
  • Python 依赖库管理哪家强?pipreqs、pigar、pip-tools、pipdeptree 任君挑选
    在Python的项目中,如何管理所用的全部依赖库呢?最主流的做法是维护一份“requirements.txt”,记录下依赖库的名字及其版本号。那么,如何来生成这份文件呢?在上篇文章《​​由浅......
  • 开发者请注意:Python2 的最后版本将于 4 月发布,但它确实是在 1 月 1 日就寿命终止了!
    2020年1月1日是Python2的寿命终止日,这个日期在两年前经"Python之父"GuidovanRossum宣布,此后一直成为开发者社区翘首以盼的一天。昨天就是这个大快人心的日子,各种......
  • JavaScript入门①-基础知识筑基
    01、JavaScript基础知识JavaScript(缩写:JS)是一种具有面向对象能力的、解释型的程序语言,基于对象和事件驱动,具有相对安全性的客户端脚本语言。JavaScript是一门完备的动态......
  • 0 基础晋级 Serverless 高手课 — 初识 Serverless(下)
    冷启动     1.流量预测2.提前启动3.实例复用每个厂商规范不一致;,兼容,适配层;adapter;fs+oss     云厂商对比                产品维度   功能......