栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【python】一次性学懂python的面向对象

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【python】一次性学懂python的面向对象

文章目录
  • 1.类与对象的定义
    • 1.1 全都是对象
    • 1.2 创建第一个完整的类
    • 1.3 构造方法
  • 2.私有属性和方法
    • 2.1 定义私有属性
    • 2.2 定义私有方法
  • 3.继承
    • 3.1 单继承
    • 3.2 子类对父类方法的重写
    • 3.3 多继承(继承下的多态)
  • 4.静态方法
  • 5.魔法方法和特殊属性
    • 5.1 __dict__
    • 5.2 __slots__
    • 5.3 __str__()
    • 5.4 __iter__()
    • 5.5 __getitem__()
    • 5.6 __getattr__()
  • 6.可调用对象
  • 7.补充Python内置类属性


1.类与对象的定义 1.1 全都是对象
  • python完全支持面向对象的基本功能:如封装、继承、多态以及对基类的重写和覆盖
  • python中一切内容都是对象,包括字符串、列表、元组、字典、集合、range对象等,函数也是对象、类也是对象
1.2 创建第一个完整的类
#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class Employee:
   '所有员工的基类'
   empCount = 0
 
   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount
 
   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
 
"创建 Employee 类的第一个对象"
emp1 = Employee("Zara", 2000)
"创建 Employee 类的第二个对象"
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print "Total Employee %d" % Employee.empCount
1.3 构造方法

Python中的构造函数时__init__(),一般来说时给类的属性设置初值或者对其它必要的初始化工作,在创建对象的时候会被自动执行。在__init__()方法中定义的属性是实例属性,可以记录这个对象的特别信息。在类的方法中可以通过对self属性的方式获得__init__()方法中初始的值。

class people(object):

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def func(self):
        print(f"{self.name}的性别是{self.gender}")

面向对象编程的一个特点就是数据封装,在people类的__init__方法中初始化的实例属性name和gender,可以在类的方法通过类的对象访问类的实例属性。

if __name__ == '__main__':
    xiaoming = people("小明", "男")
    xiaoming.func()

输出结果:小明的性别是男

也可以通过类的对象访问实例属性,类的实例属性可以被类的对象访问和修改

if __name__ == '__main__':
    xiaoming = people("小明", "男")
    xiaoming.name = "张三"
    xiaoming.func()
结果:张三的性别是男
2.私有属性和方法

在类的内部中可以定义属性和方法,在方法内封装复杂的业务逻辑,可以通过类的对象访问方法。但是类的属性可以在类的内部进行访问和修改,也可以通过类的对象进行访问和修改,这样会破坏类的封装性。

在java中我们可以设置javabean,用private修改属性的访问权限,给属性添加get和set方法。那么在python中我们要私用属性和方法改怎么做呢?我们可以在属性的名称前面加上两个下划线"__"。

2.1 定义私有属性

python中定义类的属性时,如果属性的名称以两个下划线开头则是表示为私有属性。私有属性在类的外部不能访问,需要通过类调用对象的公有方法进行访问。子类可以继承父类的公有成员,但是不能继承私有成员。

class people(object):

    def __init__(self, name, gender):
        self.__name = name
        self.__gender = gender

    def func(self):
        print(f"{self.__name}的性别是{self.__gender}")


if __name__ == '__main__':
    xiaoming = people("小明", "男")
    xiaoming.name = "张三"
    xiaoming.func()
输出结果:小明的性别是男

我们发现不能再通过对象.属性方式修改类的成员变量,并且当我们打印print(xiaoming.__name) 发现程序报错:

AttributeError: ‘people’ object has no attribute ‘__name’

2.2 定义私有方法

除了定义私有属性,还可以定义私有方法,在方法名前面加上两个下划线即可。那么我们如何访问私有方法呢,很简单,通过一个公有方法去调用私有方法即可。

class people(object):

    def __init__(self, name, gender):
        self.__name = name
        self.__gender = gender

    def __func(self):
        print(f"{self.__name}的性别是{self.__gender}")

    def info(self):
        self.__func()


if __name__ == '__main__':
    xiaoming = people("小明", "男")
    xiaoming.info()
输出结果:小明的性别是男
3.继承

在OOP(面向对象程序设计)中继承是为了代码复用和设计复用而设计的。设计一个新类时,如果可以继承一个已有的设计好的类进行二次开发,可以大幅度减少代码量。在继承关系中,已有的,设计好的类被称为父类或者基类,新设计的类被成为子类或者派生类,享有父类的属性和方法。在python中同时支持单继承和多继承(在java中只支持单继承,多继承要通过接口来实现)

3.1 单继承

python中单继承语法:

class newclass(parentclass):
	pass

当子类继承父类时,在子类的构造函数中调用父类的构造函数有两种写法:

  • 经典类的写法:父类._init_(self,kwargs1,kwargs2,…)
  • 新式类的写法: super(子类,self)._init_(self,kwargs1,kwargs2,…)

本例编写两个类,一个people类,一个student,student继承people

class people(object):

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def func(self):
        print(f"{self.name}的性别是{self.gender}")



class student(people):
    def __init__(self,name,gender,age):
        super(student, self).__init__(name, gender)
        self.age = age

    def stu_fun(self):
        print(f"{self.name}的性别是{self.gender},年龄是{self.age}")

if __name__ == '__main__':
    stu = student("小明","男","18")
    stu.stu_fun()
    stu.func()
结果:
小明的性别是男,年龄是18
小明的性别是男
3.2 子类对父类方法的重写

有时候,子类不想继承父类的方法,而是对父类的方法进行一定的修改,这个时候就要对父类方法进行重写。如果子类和父类方法有相同的方法名,输入参数和返回类型,那么新方法会覆盖旧方法。
如果在子类中要调用父类的方法,可以用super()方法名的方式进行调用。

class people(object):

    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    def func(self):
        print(f"{self.name}的性别是{self.gender}")


class student(people):
    def __init__(self, name, gender, age):
        super(student, self).__init__(name, gender)
        self.age = age

    def func(self):
        super().func()
        print(f"{self.name}的性别是{self.gender},年龄是{self.age}")


if __name__ == '__main__':
    stu = student("小明", "男", "18")
    stu.func()

结果:
小明的性别是男
小明的性别是男,年龄是18

本例中,student类继承了people类,在student类中重写了父类的方法func(),还在子类重写的方法中调用了父类的方法。

3.3 多继承(继承下的多态)

什么叫做多态呢?
当子类和父类都有相同的方法时,子类的方法覆盖父类的方法,在代码运行的时候,总是会调用子类的方法,这就是多态。

python中多继承语法:

class newclass(parentclass1,parentclass2,...)
	pass

需要注意的是newclass后面的父类顺序,如果父类中有相同的方法名,而在子类中没有使用指定的父类名,则python解释器会从左向右按顺序进行搜索,如果方法在子类中没找到,则会从左向右查找父类中是否包含该方法。

class Man(object):

    def __init__(self, name):
        self.name = name
        self.gender = "男"

    def func(self):
        print(f"{self.name}的性别是{self.gender}")


class Woman(object):

    def __init__(self, name):
        self.name = name
        self.gender = "女"

    def func(self):
        print(f"{self.name}的性别是{self.gender}")


class Student(Man, Woman):
    def __init__(self, name, age):
        super(Student, self).__init__(name)
        self.age = age

    # def func(self):
    #     super().func()
    #     print(f"{self.name}的性别是{self.gender},年龄是{self.age}")


if __name__ == '__main__':
    stu = Student("小明", "18")
    stu.func()

结果:小明的性别是男
4.静态方法

静态方法是类中的函数,不需要实例。静态方法主要放一些逻辑性代码,主要是一些逻辑属类,但是和类本身没有什么交互,即在静态方法中,不会涉及类中方法和属性的操作。静态方法定义的时候要用@staticmethod装饰器

静态方法可以通过类名访问,也可以通过实例访问

class OperateNum(object):
    def __init__(self,num1,num2):
        self.num1 = num1
        self.num2 = num2

    @staticmethod
    def sum(a,b):
        return a+b

    def fun_sum(self):
        res = OperateNum.sum(self.num1,self.num2)
        print(res)

if __name__ == '__main__':
    test = OperateNum(1,2)
    test.fun_sum()
	print(test.sum(1,2))
结果:
3
3

静态方法不需要创建对象就可以访问类中的方法。

5.魔法方法和特殊属性

魔法方法也被称为特殊方法,总是被双下划线包围,如:_init_(),特殊属性也是以双下划线包围的属性,如:_dict_(),_slots_()。

5.1 _dict_

__dict__可以访问类的所有属性,以字典的方式返回

class Student(object):

    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age

    def func(self):
        print(f"{self.name}的性别是{self.gender},年龄是{self.age}")


if __name__ == '__main__':
    xiaoming = Student("小明", "男", 18)
    print(xiaoming.__dict__)
    print(xiaoming.__dict__['name'])
    xiaoming.func()
结果:
{'name': '小明', 'gender': '男', 'age': 18}
小明
小明的性别是男,年龄是18
5.2 _slots_

Python中新类增加了__slots__内置属性,可以把实例属性锁定到__slots__规定的范围内。在python中,我们创建一个类的实例后,可以给这个实例绑定任何属性和方法,这就是动态语言的灵活性。

class Student(object):
	pass

给动态实例绑定一个属性

s = Student()
s.name = 'zhangsan'
print(s.name)

如果要限制实例的属性怎么办呢?例如只对Student实例添加name和age属性。限制实例的属性就要用到__slots__特殊属性,这个属性可以用元组定义允许绑定的属性名称。只有这个元组中出现的属性可以被类实例调用。

class Student(object):
    __slots__ = ("name", "age", "gender")

    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age


if __name__ == '__main__':
    s = Student("张三", "18", "男")
    print(f"{s.name},{s.age},{s.gender}")
    s.score = 90
    print(s.score)
结果:
AttributeError: 'Student' object has no attribute 'score'
张三,男,18

报错的原因是:score没有在__slots__中,不能绑定score属性。值得注意的是:__slots__定义的属性仅能对当前的类实例起作用,对继承它的子类是不起作用的。

class People(object):
    __slots__ = ("name", "age", "gender")

    def __init__(self, name, gender, age):
        self.name = name
        self.gender = gender
        self.age = age


class Student(People):
    def __init__(self,name, gender, age):
        super(Student, self).__init__(name, gender, age)


if __name__ == '__main__':
    s = Student("张三", "18", "男")
    print(f"{s.name},{s.age},{s.gender}")
    s.score = 90
    print(s.score)
运行结果:
张三,男,18
90

输出结果显示,子类的实例不受父类__slots__束缚

5.3 _str_()

不知道大家再写程序是,打印一个实例化对象时,打印的其实时一个对象的地址。而通过__str__()函数就可以帮助我们打印对象中具体的属性值,或者你想得到的东西。

因为再python中调用print()打印实例化对象时会调用__str__()如果__str__()中有返回值,就会打印其中的返回值。

class ss:
    def __init__(self,age,name):
        self.age = age
        self.name = name
    def __str__(self):
        return str(self.age)+",,wozenmezhemeshuai,,"+self.name
if __name__=="__main__":
    s = ss(21,'aitebao')
    print(s)
结果:
21,,wozenmezhemeshuai,,aitebao
5.4 _iter_()

如果想要一个类用于for…in循环,类似元组或者列表,就必须实现__iter__()方法。该方法返回一个迭代对象,python中的for循环会不断调用该迭代对象的__next__()方法,获得循环的下一个值,下面以斐波那契数列为例,写一个可以作用与for循环的Fib类。

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100:
            raise StopIteration
        return self.a

for n in Fib():
    print(n)
结果:
1
1
2
3
5
8
13
21
34
55
89
5.5 _getitem_()

Fib实例虽然可以作用于for循环,但是,不能将它作为列表来用,比如获取第四个元素。

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1

    def __iter__(self):
        return self

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100:
            raise StopIteration
        return self.a

for n in Fib()[3]:
    print(n)
发现报错: 
for n in Fib()[3]:
TypeError: 'Fib' object is not subscriptable

如果要获取第四个元素,需要实现__getitem__()方法,代码如下:

class Fib(object):
    def __getitem__(self, item):
        a, b = 1, 1
        for x in range(item):
            a, b = b, a + b
        return a


fib = Fib()
print(fib[3])  # 结果是: 3
5.6 _getattr_()

如果调用类的方法或者属性时,类的方法或者属性不存在,就会报错。要避免这个错误,可以使用__getattr_()方法动态的返回一个属性。

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

    def __getattr__(self, item):
        if item == 'age':
            return 18


stu = Student(name="xiaoming")
print(stu.age)
# 18

当调用不存在的属性age时,python解释器会调用__getattr__(self,‘age’)以尝试获取属性,这样就会返回age属性的值。

6.可调用对象

在python中函数也是一个对象。实际上,任何一个有__call__()特殊方法的对象都是函数,示例如下:

class Add(object):
    def __call__(self, *args):
        return sum(*args)


add = Add()	# 定义函数对象,可以把函数对象看作函数
print(add([1,2,3,4]))  # 调用函数,结果为:10

所有的函数都是可调用函数。由于add可以调用,所以add被称为可调用对象。
一个实例也可以变成一个可调用对象,只需要实现__call__()方法,比如把People类变成一个可调用对象。

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

    def __call__(self, friend):
        print(self.name, self.age)
        print(friend)


if __name__ == '__main__':
    p = Person("小明", 18)
    p("张三")
结果:
小明 18
张三

仅仅看p(“张三”)无法确定Person是一个函数还是一个类实例,所以在python中,函数也是对象,对象和函数区别不显著,这也是python灵活的地方。
那么如何判断一个变量是函数还是对象呢?
很多时候判断一个对象能否被调用,可以使用callable()函数。

print(callable(p))			# True
print(callable(["a"]))		# False
print(callable(max))		# True

由输出结果可以知道,通过callable()函数可以判断一个对象是否是可调用对象。

7.补充Python内置类属性

#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
class Employee:
   '所有员工的基类'
   empCount = 0
 
   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1
   
   def displayCount(self):
     print "Total Employee %d" % Employee.empCount
 
   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary
 
print "Employee.__doc__:", Employee.__doc__
print "Employee.__name__:", Employee.__name__
print "Employee.__module__:", Employee.__module__
print "Employee.__bases__:", Employee.__bases__
print "Employee.__dict__:", Employee.__dict__

执行结果如下:

Employee.__doc__: 所有员工的基类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
Employee.__dict__: {'__module__': '__main__', 'displayCount': , 'empCount': 0, 'displayEmployee': , '__doc__': 'xe6x89x80xe6x9cx89xe5x91x98xe5xb7xa5xe7x9ax84xe5x9fxbaxe7xb1xbb', '__init__': }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/920834.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号