Python | 编程思想

一、类与对像的创建
1. 类的组成
类属性、实例方法、静态方法、类方法

Class Student:
    pass

Student为类的名称,每个单词的首字母大写,其余小写

直接写在类里的变量,称为类属性


实例方法

def eat(self):
    print("")

 

静态方法

@staticmethoddef method():
    print("staticmethod进行修饰为静态方法,不能使用self")

在类之外定义的称之为函数,在类之内定义的称之为方法
静态方法进行修饰,不能使用self


类方法

@classmethoddef cm(cls):
    print("classmethod进行修饰为类方法,使用cls")

 

init初始化方法

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

self.name称为实体属性,进行了一个赋值操作,将局部变量的name的值赋给实体变量

 

2. 对象的创建
对象的创建又称为类的实例化
语法:
实例名 = 类名()
意义:有了实例,就可以调用类中的内容


总结
类属性:类中方法外的变量称之为类属性,被该类的所有对象所共享
类方法:使用@classmethod修饰的方法,使用类名直接访问的方法
静态方法:使用@staticmethod修饰的方法,使用类名直接访问的方法

Student.native_pace # 访问类属性
Student.cm() # 调用类方法
Student.sm() # 调用静态方法

class Student:
    native_pace='安徽'
    @classmethod
    def cm(cls):
        print("classmethod进行修饰为类方法,使用cls")
    @staticmethod
    def method():
        print("staticmethod进行修饰为静态方法,不能使用self")
print(Student.native_pace)
Student.cm()
Student.method()           

 

面向对象的三大属性

封装:提高程序的安全性
继承:提高代码的复用性
多态:提高代码的可扩展性和可维护性

1.封装
封装:提高程序的安全性
将数据(属性)和行为(方法)包装到类对象中。在方法内部对属性进行操作,在类对象的外部调用方法。这样,无需关心方法内部的具体实现细节,从而隔离了复杂度

在python中没有专门的修饰符用于属性的私有,如果该属性不需要在类对象外部被访问,前面使用两个“_”

class Student:
    def __init__(self,name,age):
        self.name=name
        self.__age=age
    def show(self):
        print(self.name,self.__age)
stu=Student("张三",20)
stu.show()
# print(stu.name)
#print(dir())
# print(stu._Student__age)

年龄不希望在类的外部被调用,所以使用两个“_”
在类的外部可以通过_student__age进行访问


2.继承
语法格式:
class 字典类名(父级1,父级2):
如果一个类都没有继承任何类,则默认继承object

class Person(object):
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def info(self):
        print(self.name,self.age)
class Student(Person):
    def __init__(self,name,age,stu_no):
        super().__init__(name,age)
        self.stu_no=stu_no
class Teacher(Person):
    def __init__(self,name,age,teachofyear):
        super().__init__(name,age)
        self.teachofyear=teachofyear
stu=Student("张三",20,"1001")
teacher=Teacher("李四",34,10)
stu.info()
teacher.info()
打印结果:
张三 20
李四 34

 

多继承

class A(object):
    pass
class B(object):
    pass
class C(A,B):
    pass

 

3.方法重写
如果子类对继承父类的某个属性或方法不满意,可以在子类中对其(方法体)进行重新编写
子类重写后的方法中可以通过super().xxx()调用父类中被重写的方法

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

class Student(Person): #继承
    def __init__(self,name,age,stu_no):
        super().__init__(name,age)
        self.stu_no=stu_no
    def info(self):
        super().info()
        print("学号",self.stu_no)

class Teacher(Person):
    def __init__(self,name,age,teachofyear):
        super().__init__(name,age)
        self.teachofyear=teachofyear
    def info(self):
        super().info()
        print("教龄:",self.teachofyear)
stu=Student("张三",20,"1001")
teacher=Teacher("李四",34,10)
stu.info()
print("-------")
teacher.info()
打印结果:
张三 20
学号 1001
-------
李四 34
教龄: 10


4.object类
object类是所有类的父类,因此所有类都有object类的属性和方法;
内置函数dir()可查看指定对象所有属性;
object有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数str(),
经常用于print()方法,帮我们查看对象的信息,所以我们经常会对__str__()进行重写

class Student:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __str__(self):
        return "我的名字是{0},今年{1}岁".format(self.name,self.age)
stu=Student("张三",20)
print(dir(stu))
print(stu)
print(type(stu))
打印结果:
['__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__', 'age', 'name']
我的名字是张三,今年20岁
<class '__main__.Student'>

 

5.多态

 多态就是“具有多种形态”,它指的是:即便不知道一个变量所引用的对象到底是什么类型,仍然可以通过这个变量调用方法,在运行过程中根据变量所引用对象的类型,动态决定调用哪个对象中的方法

class Animal:
    def eat(self):
        print("动物会吃")
class Dog(Animal):
    def eat(self):
        print("狗吃骨头")
class Cat(Animal):
    def eat(self):
        print("猫吃鱼")
class Peason():
    def eat(self):
        print("人吃五谷杂粮")

#定义一个函数
def fun(obj):
    obj.eat()
#开始调用函数
fun(Cat())
fun(Dog())
fun(Animal())
print("----------")
fun(Peason())
# 打印结果
猫吃鱼
狗吃骨头
动物会吃
----------
人吃五谷杂粮

 

 6.特殊属性和特殊方法

 

 

特殊方法__add__()

stu1 ='张三'
stu2 ='李四'
s=stu1+stu2
print("两个对象相加方法一",s)
s=stu1.__add__(stu2)
print("两个对象相加方法二",s)
# 打印结果
两个对象相加方法一 张三李四
两个对象相加方法二 张三李四

特殊方法__len__()

class Student:
    def __init__(self,name):
        self.name=name
    def __len__(self):
        return len(self.name)
stu1=Student("Python")
print("stu1()中Python的长度",len(stu1))

lst=[11,22,33,44]
print("列表的长度",len(lst))
print("列表的长度",lst.__len__())
# 打印结果
stu1()中Python的长度 6
列表的长度 4
列表的长度 4

特殊方法__new__() 、特殊方法__init__()

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

    def __new__(cls, *args, **kwargs):
        print("__new__被调用执行了,cls的id值为:{0}".format(id(cls)))
        obj=super().__new__(cls)
        print("创建的对象的id为{0}".format(id(obj)))
        return obj

    def __init__(self,name,age):
        print("__init__被调用了,self的id值为:{0}".format(id(self)))
        self.name=name
        self.age=age
        print("object这个类对象的id值为:{0}".format(id(object)))

print("Person这个类对象的id值为:{0}".format(id(Person)))
p1=Person("张三",20)
print("p1这个Person类的实例对象的id:".format(id(p1)))
# 打印结果
Person这个类对象的id值为:52902248
__new__被调用执行了,cls的id值为:52902248
创建的对象的id为43581072
__init__被调用了,self的id值为:43581072
object这个类对象的id值为:257496144
p1这个Person类的实例对象的id:

 

__new__方法的第一个参数是这个类,而其余的参数会在调用成功后全部传递给__init__方法初始化,所以,__new__方法(第一个执行)先于__init__方法执行,

比较两个方法的参数,可以发现__new__方法是传入类(cls),而__init__方法传入类的实例化对象(self),而有意思的是,__new__方法返回的值就是一个实例化对象(ps:如果__new__方法返回None,则__init__方法不会被执行,并且返回值只能调用父类中的__new__方法,而不能调用毫无关系的类的__new__方法),结合到代码,也就是__new__的返回值正是__init__中self。

 

小结: __new__和__init__相配合才是python中真正的类构造器。

 

其中,__new__()不是一定要有,只有继承自object的类才有,该方法可以return父类(通过super(当前类名, cls).__new__())出来的实例,或者直接是object的__new__出来的实例。值得注意的是,在定义子类时没有重新定义__new__()时,Python默认调用该类父类的__new__()方法来构造该类实例,如果该类父类也没有重写__new__(),那么将一直追溯至object的__new__()方法,因为object是所有新式类的基类。如果子类中重写了__new__()方法,那么可以自由选择任意一个其他的新式类。

  可见,当类中同时出现__new__()和__init__()时,先调用__new__(),再调用__init__(),具体的执行过程为:

  1. 调用实例对象代码xiaoming = Student('xiaoming',175);

  2. 传入name和height的参数,执行Student类的__new__()方法,该方法返回一个类的实例,通常会用父类super(Student,cls).__new__(cls),__new__()产生的实例即__init__()的self;

  3. 用实例来调用__init__()方法,进行初始化实例对象的操作。

  可以看到,python中__new__()与__init__()的区别,

  1.首先用法不同,__new__()用于创建实例,所以该方法是在实例创建之前被调用,它是类级别的方法,是个静态方法;

            而 __init__() 用于初始化实例,所以该方法是在实例对象创建后被调用,它是实例级别的方法,用于设置对象属性的一些初始值。

  由此可知,__new__()在__init__() 之前被调用。如果__new__() 创建的是当前类的实例,会自动调用__init__()函数,通过return调用的__new__()的参数cls来保证是当前类实例,如果是其他类的类名,那么创建返回的是其他类实例,就不会调用当前类的__init__()函数。

 

  2.其次传入参数不同

  __new__()至少有一个参数cls,代表当前类,此参数在实例化时由Python解释器自动识别;

  __init__()至少有一个参数self,就是这个__new__()返回的实例,__init__()在__new__()的基础上完成一些初始化的操作。

 

  3.返回值不同

  __new__()必须有返回值,返回实例对象;

  __init__()不需要返回值。

 https://www.cnblogs.com/jayliu/p/9013155.html

https://blog.csdn.net/m0_64118193/article/details/124612710

posted @ 2022-05-14 19:46  卷毛七号  阅读(119)  评论(0编辑  收藏  举报