Python3 - self语法面向对象内置属性魔法方法

Posted 韩俊强

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python3 - self语法面向对象内置属性魔法方法相关的知识,希望对你有一定的参考价值。

文章目录

1.uuid

# uuid 用来生成一个全局唯一的id模块
# 一般而言, 在对uuid的需求不是很复杂的时候, uuid1或者uuid4方法就已经够用了
import uuid
print(uuid.uuid1())  # e703f4d4-92e3-11ec-a109-acde48001122,  32个长度 每一个字符有16个选择, 16**32选择
# print(uuid.uuid2) python 不让用

# uuid3 和 uuid5 是使用传入的字符串根据指定的算法算出来的, 是固定的
print(uuid.uuid3(uuid.NAMESPACE_DNS, 'xiaohange'))  # uuid3生成固定的uuid  基于md5
print(uuid.uuid5(uuid.NAMESPACE_DNS, 'xiaohange'))  # uuid5生成固定的uuid  采用散列算法sha1

print(uuid.uuid4())  # 使用的最多, 基于随机数, 每次生成不一样, 有一定概率重复的

2.使用第三方模块

pip install <package_name> 用来下载一个第三方的模块
pip uninstall <package_name> 用来删除第三方模块
pip list 用来列出当前环境安装的模块名和版本号
pip freeze  用来列出当前环境安装的模块名和版本号

临时修改, 只修改这一个文件的下载路径
pip install flask -i https://pypi.douban.com/simple/  从指定地址下载包

pip freeze > requirements.txt   将安装的模块名和版本号重定向输出到指定的文件
pip install -r requirements.txt  读取文件里模块名和版本号并安装

python 在查找模块的时候, 在哪些路径下查找

from flask import Flask
import sys
print(sys.path)

如果模块里没有定义 all 才会导入所有不以 _ 开头的变量和函数

# 没有设置 __all__ , 会读取所有不以下划线开始的所有变量和函数
x = 'hello'
y = 1000

# 以一个下划线开始变量, 建议只在本模块里使用, 别的模块不要导入
_age = 19  # 使用from 模块名 import * 这种方式无法导入
_age += 1 # _外界就不要用我了

def _bar():
    print('我是hello里的bar函数, 我只能hello文件内使用')

del (_age, _bar)  # 外部不让用
# from demo import * 只会识别__all__标记的属性和函数
# from demo import n 想读到n, 也可以这样导入
__all__ = ['m', 'test']

a = 'hello'
n = 100


def test():
    print('我是my_module模块里的test函数')


def add(x, y):
    return x + y
from demo import *
from demo import n


print(my_module.a)
my_module.test()
print(my_module.add(10, 20))

# 使用from demo import * 写法, 不需要再写模块名
print(m)
test()

print(n)

from hello import *
print(x)
print(y)
# print(_age)

# 不建议导入_的
# import hello
# print(hello._age)


# from datetime import *  # 不能导入_is_leao , 不建议在模块外使用, 否则有可能出问题
# import datetime
# datetime._is_leap(2000)

3.包的使用

可以将多个具有相似或者有关联的多个模块放到一个文件夹里, 便于统一管理; 这个文件夹, 我们就可以称之为包

# python包里, 会有一个 __init__.py 文件
from chat import recv_msg
from chat.send_msg import y
import json
import flask
print(recv_msg.x)
print(y)

import chat
print(chat.send_msg.y)
print(recv_msg.x)

4.self语法的使用

class Student(object):
    __slots__ = ('name','age', 'city')  # 这个属性直接定义在类里, 是一个元祖, 用来规定对象可以存在的属性
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say_hello(self):
        print('大家好, 我是', self.name)


# Student('张三', 18) 具体干了什么
# 1. 调用__new__方法, 用来申请内存空间
# 2. 调用__init__方法, 并让self指向申请好的内存空间
# 3. 让变量 s1 也指向创建好的这段内存空间

s1 = Student('张三', 18)
print('0x%X' % id(s1)) # 0x7F7CA01FEFD0
s1.say_hello()

s2 = Student('赵四', 20)
s2.say_hello()

# 直接使用等号给一个属性赋值
# 如果这个属性以前不存在, 会给对象添加一个新的属性
# 动态属性
s1.city = '上海'  # 给对象添加一个city属性
print(s1.city)

# 如果这个属性以前存在, 会修改这个属性对应的值
s1.name = 'jack'
print(s1.name)  # jack

5.魔法方法

魔法方法, 也叫魔术方法, 是类里的特殊的一些方法

特点:

  1. 不需要手动调用, 会在合适的时机自动调用

  2. 这些方法, 都是使用__开始, 使用__结束

  3. 方法名都是系统规定好的, 在合适的时机自己调用


import time
import datetime


x = datetime.datetime(2022, 2, 23, 12, 13, 45, 200)
print(x)  # __str__ 方法  2022-02-23 12:13:45.000200
print(repr(x))  # __repr__ 方法  datetime.datetime(2022, 2, 23, 12, 13, 45, 200)


class Person(object):
    # 在创建对象时, 会自动调用这个方法
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def __del__(self):
        # 当对象被销毁时, 会自动调用这个方法
        print('__del__方法被调用了')

    def __repr__(self):
        return 'hello'

    def __str__(self):
        return '姓名:,年龄'.format(self.name, self.age)

    def __call__(self, *args, **kwargs):
        print('__call__方法被调用了')
        # args 是一个元祖, 保存(1, 2)
        # kwargs 是一个字典 fn: lambda x, y: x + y 
        print('args=,kwargs='.format(args, kwargs)) # args=(1, 2),kwargs='fn': <function <lambda> at 0x7fa6100e7040>
        return kwargs['fn'](args[0],  args[1])


p = Person('张三', 10)

# 手动立即销毁
# del p

# 如果不做任何的修改, 直接打印这个对象, 是文件__name__.类型 内存地址
# print(p)  # <__main__.Person object at 0x7febc020efd0>

# 当打印一个对象的时候, 会调用这个对象的 __str__ 或者 __repr__ 方法
# 如果两个方法都写了, 选择 __str__
print(p)

# print(repr('name': '张三', 'age': 18))  # 'name': '张三', 'age': 18

# print(repr(p))  # 'hello' 调用内置函数repr, 会触发对象的 __repr__ 方法
# print(p.__repr__())  # 魔法方法, 一般不手动的调用


# p()  # 对象名() ==> 调用这个对象的 __call__ 方法
# p(1, 2)  # 对象名() ==> 调用这个对象的 p.__call__(1, 2) 方法
n = p(1, 2, fn=lambda x, y: x + y)
print(n)  # 3

6.运算符相关的魔法方法

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

    def __eq__(self, other):
        # print('__eq__方法被调用了, other=', other)  # __eq__方法被调用了, other= <__main__.Person object at 0x7fc23820ef10>
        # if self.name == other.name and self.age == other.age:
        #     return True
        # return False
        return self.name == other.name and self.age == other.age

# 调用 __new__ 方法申请内存空间
p1 = Person('zhangsan', 12)
p2 = Person('zhangsan', 12)
p3 = Person('zhangsan', 13)
print(p1==p3)  # False

# p1 和 p2 是同一个对象吗? 不一个地址
print('0x%X' % id(p1))  # 0x7FAE58156FD0
print('0x%X' % id(p2))  # 0x7FAE58156F10

# is 身份运算符, 可以用来判断两个对象是否是同一个对象
print('p1 is p2: ', p1 is p2)  # False

# __eq__ 如果不重写, 默认比较的依然是内存地址,
print('p1==p2: ', p1 == p2)  # False 本质上是调用 p1.__eq__(p2), 获取这个方法的返回值

# is 比较两个对象的内存地址
# == 会调用 __eq__ 方法, 获取这个方法的比较结果
# num1 = [1, 2, 3]
# num2 = [1, 2, 3]
# print(num1 is num2)  # False
# print((num1 == num2))  # True

7.内置属性

class Person(object):
    # 在创建对象时, 会自动调用这个方法
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + '正在吃饭')


p = Person('张三', '23')
print(p.__class__)  # <class '__main__.Person'>
print(p.__dict__)  # 'name': '张三', 'age': '23' 把对象属性的值转换为一个字典
# print(p.__dir__())  # 等价于dir(p)
print(p.__doc__)  # 对象名.__doc__
print(Person.__doc__)  # 类名.__doc__
print(p.__module__)  # __main__

8.如何把对象当做一个字典使用

class Person(object):
    type = '人类'  # 这个属性定义在类里, 函数之外, 我们称之为类属性
    __enname = 'person'  # 私有属性
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + '正在吃饭')

    def __setitem__(self, key, value):
        print(f'__setitem__被调用key, value')
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

p = Person('张三', '23')
print(p.__dict__)  # 将对象转换成字典 'name': '张三', 'age': '23'
# 不能直接把字典当成字典使用
p['name'] = 'jack'  # [] 语法会调用对象的 __set_item_ 方法
p['age'] = 20
print(p.name, p.age)
print(p['name'])  # 会调用 __getitem__方法
print(p.type)
# print(p.__enname)  不允许访问私有属性(__属性名)

9.私有属性的使用

class Person(object):
    type = '人类'  # 这个属性定义在类里, 函数之外, 我们称之为类属性
    __enname = 'person'  # 私有属性
    def __init__(self, name, age):
        print('__init__方法被调用了')
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + '正在吃饭')

    def __setitem__(self, key, value):
        print(f'__setitem__被调用key, value')
        self.__dict__[key] = value

    def __getitem__(self, item):
        return self.__dict__[item]

p = Person('张三', '23')
print(p.__dict__)  # 将对象转换成字典 'name': '张三', 'age': '23'
# 不能直接把字典当成字典使用
p['name'] = 'jack'  # [] 语法会调用对象的 __set_item_ 方法
p['age'] = 20
print(p.name, p.age)
print(p['name'])  # 会调用 __getitem__方法
print(p.type)
# print(p.__enname)  不允许访问私有属性(__属性名)

10.类方法和静态方法

class Calculator(object):
    def __init__(self, m, n):
        self.m = m
        self.n = n

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


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

    def eat(self, food):  # 对象方法有一个参数self, 指的是实例方法
        print(self.name + '正在吃' + food)

    # 如果一个方法没有用到任何的实例对象的任何属性, 可以将这个方法定义成static, 静态方法
    @staticmethod
    def demo():  # 默认的方法都是对象方法
        print('hello')

    @classmethod
    def test(cls):  # 如果这个函数只用到了类属性, 我们把这个定义称为一个类方法
        # 类方法会有一个参数 cls, 也不需要手动传参, 会自动传参, cls指的是类对象  cls is Person
        print('yes')

p = Person('张三', 18)

# 实例对象在调用方法时, 不需要给形参self传参, 会自动的把实例传递给self
p.eat('香蕉')  # 直接使用实例对象调用方法
print(Person.eat(p, '香蕉'))   # 使用类调用实例方法

# 静态方法: 没有用到实例对象的任何属性
Person.demo()
p.demo()
print(Calculator.add(1, 2))

# 类方法: 可以使用实例对象和类对象调用
print(Person.test())

11.面向对象练习

# 房子 有户型, 总面积, 剩余面积(等于总面积的60%)和家具的具体列表属性
# 新房子没有任何家具
# 将家具的名称追加到家具名称列表中
# 判断 家具的面积是否超过剩余面积, 如果超过, 提示不能添加这件家具

class House(object):
    # 缺省参数
    def __init__(self, house_type, total_area, fru_list=None):
        if fru_list is None:  # 如果这个值是None
            fru_list = []  # 将fru_list设置为空列表
        self.house_type = house_type
        self.total_area = total_area
        self.free_area = total_area * 0.6
        self.fru_list = fru_list

    def add_fru(self, x):
        if self.free_area < x.area:
            print('面积不足!')
        else:
            print(f'将x.name添加到房子里')
            self.fru_list.append(x.name)
            self.free_area -= x.area

    def __str__(self):
        return '户型=, 总面积=,剩余面积=, 家具列表='.format(self.house_type, self.total_area, self.free_area, self.fru_list)

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


# 创建房间对象的时候, 传入户型和总面积
house = House('一室一厅', 20)

sofa = Furniture('沙发', 10)
bed = Furniture('席梦思', 4)
sched = Furniture('衣柜', 2)
table = Furniture('餐桌', 1.5)


# 把家具添加到房间里(面向对象关注点: 让谁做)
house.add_fru(sofa)
house.add_fru(bed)
house.add_fru(sched)
house.add_fru(table)

print(house.__str__())
print(house)

12.函数练习

# 编写一个函数, 求多个数中的最大值
import random


def get_max(*args):
    x = args[0]
    for arg in args:
        if arg > x:
            x = arg
    return x

# 编写一个函数, 实现摇骰子的功能, 打印N个骰子的点数之和
def get_sum(n):
    m = 0
    for i in range(n):
        x = random.randint(1, 6)
        m += x
    return m

# 编写一个函数, 提取指定字符串中所有的字母, 然后拼接在一起产生一个新的字符串
def get_alphas(word):
    new_str = ''
    for w in word:
        if w.isalpha():
            new_str += w
    return new_str

# 写一个函数, 默认求10的阶乘, 也可以求其他数字的阶乘
def get_factorial(n=10):
    x = 1
    for i in range(1, n + 1):
        x *= i
    return x

# 写一个函数, 求多个数的平均值
def get_average(*args):
    x = 0
    for arg in args:
        x += arg
    return x / len(args)


# 写一个自己的capitalize函数, 能够将指定的字符串的首字母变成大写字母
def my_capitalize(word):
    c = word[0]

    if 'z' >= c >= 'a':
        new_str = word[1:]
        return c.upper() + new_str
    return word


# 写一个自己的endwith函数, 判断一个字符串是否以指定的字符串结束
def my_endswith(old_str, str1):
     return old_str[-len(str1):] == str1

# 写一个自己的isdigit函数, 判断一个字符串是否是纯数字字符串
def my_isdigit(old_str):
    for s in old_str:
        if not '0' <= s <= '9':
            return False
    return True


# 写一个自己的upper函数, 将一个字符串中所有的小写字母变成大写字母
# a===> 97 A ==> 65 差32
def my_upper(old_str):
    new_str = ''
    for s in old_str:
        if 'a' <= s <= 'z':
            upper_s = chr(ord(s) - 32)
            new_str += upper_s
        else:
            new_str += s
    return new_str


# 写一个函数实现自己in操作, 判断指定序列中, 指定的元素是否存在
def my_in(it, els):
    for i in it:
        if i == els:
            return True
    else:
        return False


# 写一个自己的replace函数, 将指定字符串中指定的旧字符串转换成指定的新字符串
def my_replace(all_str, old_str, new_str):
    # 第一种: return new_str.join(all_str.split(old_str))
    # 第二种:
    result = ''
    i = 0
    while i < len(all_str):
        temp = all_str[i:i+ len(old_str)]
        if temp != old_str:
            result += all_str[i]
            i += 1
        else:
            result += new_str
            i += len(old_str)
    return result


# 写一个自己的max函数, 获取指定序列中元素的最大值, 如果序列是字典, 取字典值的最大值
def get_max2(seq):
    # if type(seq) == dict:
    if isinstance(seq, dict): # 看对象seq是否是通过dict类创建出来的实例
        seq =以上是关于Python3 - self语法面向对象内置属性魔法方法的主要内容,如果未能解决你的问题,请参考以下文章

python3 面向对象

3.2面向对象基础语法

python语法基础-面向对象-进阶-长期维护

Day5—面向对象

面向对象:反射内置方法

Python-面向对象高级语法之属性方法