Python——面向对象思想编程(一)

我的第一个类

设计类

类名:见名知意,首字母大写,其他遵循驼峰原则
属性:见名知意,其他遵循驼峰原则
行为方法/功能):见名知意,其他遵循驼峰原则

举个栗子:
类名:Wife(首字母大写)
属性:性别、年龄、身高、体重
行为:洗衣、做饭、逛街等等

类名:Husband(首字母大写)
属性:性别、年龄、身高、体重
行为:赚钱、洗衣、做饭等等

创建类

:一种数据类型,本身并不占内存空间,跟平时学过的NumberStringBoolean等类似。用类创建实例化对象(变量),对象占内存空间
格式

class 类名(父类列表):
    属性
    行为

示例

 # object:基类,也叫超类,是所有类的父类,一般没有合适的父类就写object
class Person(object):
    # 定义这个Person的属性
    name = ""
    age = 0
    height = 0
    weight = 0

    # 定义方法(定义函数)
    # 注意:方法的参数必须以self当第一个参数
    # self代表类的实例(某个对象)
    def run(self):
        print("run")
        
    def eat(self, food):
        print("eat", food)

实例化对象

格式:对象名 = 类名(参数列表)
注意:没有参数,小括号也不能省略

jack = Person()
print(jack)

bob = Person()
print(bob)

打印结果:

<__main__.Person object at 0x000002A56679FEF0>
<class '__main__.Person'>
<__main__.Person object at 0x000002A56679FF28>
<class '__main__.Person'>

可以发现,他们的地址id是不一样的,但是他们类型是一样的,他们是两个完全不一样的变量
在这里插入图片描述

访问对象的属性与方法

访问属性

格式对象名.属性名
赋值对象名.属性名 = 新值

jack.name = "jack"
jack.age = 18
print(jack.name, jack.age)

打印结果:

jack 18
访问方法

格式对象名.方法(参数列表)

# 这是不需要传参的
jack.run()
# 这是需要传参的
jack.eat(apple)

运行结果:

run
eat apple

问题:目前来看Person类创建的所有对象属性都是一样的

P1 = Person()
P2 = Person()
print(P1.age)
print(P2.age)

运行结果:

0
0

对象的初始状态(构造函数)

构造函数__ init __()在使用类创建对象的时候自动调用
注意:如果不显示的写出构造函数,默认会自动添加一个空的构造函数

def __init__(self):
    print("这里是init")

当你只是去实例化这个对象时,这个构造函数也跟着执行了:

# 这里是紧接着上面的来的
这里是init
这里是init
0
0

所以我们可以把属性写入init里面去故每次实例化对象时,属性也跟着执行了

class Person(object):
    def __init__(self, name, age):
        print(name, age)
        
P1 = Person("A", 18)

运行结果:

A 18

所以现在我们就可以直接用self去把属性跟这个类绑定

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
P1 = Person("A", 18)
print(P1.name, P1.age)

运行结果也是一样的

self

self代表类的实例,而非类
哪个对象调用方法,那么该方法中的self就代表哪个对象

其实把self也可以换成其他的,self不是关键字,换成其他的标识符也是可以的,但是帅的人都用self,这应该是Python中的惯例

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

    def run(a):
        print("run", a.name, "!")

P1 = Person("jack", 18)
P1.run()

运行结果:

run jack !

self.__class__:返回的是当前类的类名

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

    def run(a):
        print(self.__class__)

P1 = Person("jack", 18)
P1.run()

运行结果:

<class '__main__.Person'>

析构函数

实例被销毁的时候执行的,__ del__就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数,另外当对象在某个作用域中调用完毕,在跳出其作用域的同时析构函数也会被调用一次,这样可以用来释放内存空间。

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

    def __del__(self):
        print("析构函数被调用了")

P1 = Person("jack", 18)

运行结果:

析构函数被调用了

这里只是实例化了,但是析构函数就被调用了,这是因为在程序结束的时候,系统会自动释放对象,这样可以用来减少内存空间的浪费
在函数里面定义的对象,也会被自动释放

__repr__函数与__str__函数

__repr____str__是类里面本来就有的,因为一些原因,为了更方便的去计算出结果或者去维护,我们可以重写这两个函数,它的意思是返回一个对象的描述信息
下面有个问题,如果我想打印出这个类里面的属性呢
很简单,我们只需要这样

print(P1.name, P1.age)

但是要是有一百个,一千个需要我们去打印呢
下面就需要运用到这两个函数了,在我们去打印对象的时候,这两个函数会被自动调用

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

    def __str__(self):
        return "这里是str"

P1 = Person("jack", 18)
print(P1)

打印结果:

这里是str

所以我们可以在def __str__(self):里面修改成我们想要的结果

def __str__(self):
        return ""%s, %d" % (self.name, self.age)"

打印结果:

jack, 18

结论:
__str__:在调用print打印对象时自动调用,是给用户用的,是一个描述对象的方法
__repr__:是给机器用的,相当于是cmd黑屏终端,给我们返回的信息,在Python解释器里面直接敲对象名在回车后调用的方法
注意:在没有str时,且有repr,则 str = repr
这里的print(P1)相当于是print(P1.__str__()),只不过是可以省略的
优点:当一个对象的属性值很多,并且都需要打印,重写了__str__方法后,简化了代码

访问限制

有时候我们定义一个类,内部属性并不想被外部直接访问,比如定义,女人的体重是个隐私问题,并不想让别人知道
如果要让内部属性不被外部直接访问,在属性前面加两个下划线(__),在python中如果在属性前面加两个下划线,那么这个属性就变成了私有属性

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

P1 = Person("jack", 18, 180)
print(P1.__weight)

打印结果:

AttributeError: 'Person' object has no attribute '__weight'

显而易见,结果是不可取的,但是一般我们用私有属性,是定义一个方法,通过定义一个存方法,一个取方法来获得私有属性的值

class Person(object):
    def __init__(self, name, age, weight):
        self.name = name
        self.age = age
        self.__weight = weight
        
    # 通过内部的方法,去修改私有属性
    # 通过自定义·的方法实现对私有属性的赋值与取值
    def setWeight(self, weight):
        # 数据的过滤,这个其实可以更完善一些
        if weight < 0:
            weight = 0
        self.__weight = weight

    def getWeight(self):
        return self.__weight
        
P1 = Person('jack', 18, 180)
P1.setWeight(160)
print(P1.getWeight())

运行结果:

160

不能直接访问P1.__weight是因为Python解释器把__weight变成了_Person__weight,但是仍然可以通过_Person__weight去访问,但是强烈不建议这么去干,因为帅的人都不这么干,不同的解释器可能存在解释的变量名不一致,导致最后出现bug

P1._Person__weight = 1
print(P1.getWeight())

运行结果:

1

在Python中__XXX__属于特殊变量,可以直接访问,但是我们一般不self.__XXX__这么定义,因为容易跟Python中的特殊变量弄混,这样不好
在Python中_XXX变量,这样的实例变量外部是可以访问的,但是!!!按照约定的规则,当我们看到这样的变量时,意思就是"虽然我们可以被访问,但是请尊重我们,请把我们视为私有变量,不要直接访问我"

发布了17 篇原创文章 · 获赞 7 · 访问量 736

猜你喜欢

转载自blog.csdn.net/qq_44168690/article/details/104147769
今日推荐