一、內(nèi)置類函數(shù)
聲明類的時(shí)候系統(tǒng)會(huì)自動(dòng)添加的屬性(可能會(huì)是字段也可能是對(duì)象自己)
__name__、__slots__、__class__、__dot__、__dict__、__module__
定制當(dāng)前對(duì)象的打印
class Person:
"""
說明文檔:人類
num - 人類的數(shù)量
name - 人的名字
""""
num = 61
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
def eat(self, food):
print('%s在吃%s' % (self.name, food))
# 定制當(dāng)前對(duì)象的打印
# 1)重寫__str__方法
def __str__(self):
# return '姓名:{},年齡:{},性別:{}'.format(self.name, self.age, self.gender)
return '<' + str(self.__dict__)[1:-1] + '>'
# 2)重寫__reper__方法
# def __repr__(self)
def __repr__(self):
return '<' + str(self.__dict__)[1:-1] + 'id: ' + hex(id(self)) + '>'
p1 = Person('小明', '男', 18)
print(p1)
# <'name': '小明', 'gender': '男', 'age': 18>
1. __name__
__name__指的是類的字段
print(type(Person), person)
print(int)
print(Person.__name__) # 沒有p1.__name__
print(type(Person.__name__))
"""
<class 'type'> <class '__main__.Person'>
<class 'type'>
Person
<class 'str'>
"""
2.__dot__
'doc'指的是說明文檔
print(Person.__doc__)
# print(int.__doc__)
print(p1.__doc__)
"""
說明文檔:人類
num - 人類的數(shù)量
name -人的名字
說明文檔:人類
num - 人類的數(shù)量
name -人的名字
"""
3.__class__
__class__指的是對(duì)象屬性;
對(duì)象.__class__ —— 獲取對(duì)象對(duì)應(yīng)的類(和type(對(duì)象)功能一樣)
print(p1.__class__)
print(type(p1))
type1 = p1.__class__ # type1可以當(dāng)做Person來用
print(type1.__name__)
p2 = type1('小花', '女', 17)
print(p2.name, p2.gender, p2.age)
"""
<class '__main__.Person'>
<class '__main__.Person'>
Person
小花 女 17
"""
4.__dict__(將對(duì)象轉(zhuǎn)換成字典)
對(duì)象屬性;對(duì)象.__dict__ —— 將字典中所有的屬性以屬性和對(duì)應(yīng)的值轉(zhuǎn)換成一個(gè)字典中的鍵值對(duì)(一個(gè)對(duì)象一個(gè)字典)
類的字段;類.__dict__ —— 將類轉(zhuǎn)換成一個(gè)字典,字典中的元素是類中所有的字段對(duì)應(yīng)的值
print(p1.__dict__)
print(Person.__dict__)
print(p1)
persons = [p1, p2] # 因?yàn)開_repr__的方法
print(persons)
"""
{'name': '小明', 'gender': '男', 'age': 18}
{'__module__': '__main__', '__doc__': '\n 說明文檔:人類\n num - 人類的數(shù)量\n name -人的名字\n ', 'num': 61, '__init__': <function Person.__init__ at 0x000000000279F0D8>, 'eat': <function Person.eat at 0x000000000279F168>, '__str__': <function Person.__str__ at 0x000000000279F1F8>, '__repr__': <function Person.__repr__ at 0x000000000279F288>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
<'name': '小明', 'gender': '男', 'age': 18>
[<'name': '小明', 'gender': '男', 'age': 18,id:0x279e848>, <'name': '小花', 'gender': '女', 'age': 17,id:0x279e948>]
"""
5.__module__
__module__是類的字段;類.__module__ —— 獲取當(dāng)前類是在那個(gè)模塊中聲明的返回的是模塊的名字
print(Person.__module__)
print(bool.__module__)
print(p1.__module__)
"""
__main__
builtins
__main__
"""
6.__bases__
__bases__類的字段;類.__bases__ —— 獲取當(dāng)前類的父親(返回的是一個(gè)元組)
print(Person.__bases__)
"""
(<class 'object'>,)
"""
練習(xí)將數(shù)據(jù)轉(zhuǎn)換成對(duì)象
import json
with open('data.json', 'r', encoding='utf-8') as f:
content = json.loads(f.read())
datas = content
class Data:
# 注意:如果設(shè)置了__slots__的值,那么當(dāng)前類的對(duì)象就不能使用__dict__屬性
# __slots__ = ('name', 'age', 'dict1')
def __init__(self, dict1: dict):
for key in dict1:
steattr(self, key, dict1[key])
def __repr__(self):
return '<' + str(self, __dict__)[1:-1] + '>'
for item in datas:
data = Data(item)
print(data.name, '\n', data)
"""
a0
<'name': 'a0', 'pwd': '12345', 'add': [], 'alter': [], 'del': [{'name': 'stu0', 'age': 10, 'phone': '12345678901', 'time': 1565170335.1302288}]>
b
<'name': 'b', 'pwd': '45678'>
"""
####二、私有化
######1.訪問權(quán)限:公開、保護(hù)、私有
```python
公開 - 公開的屬性和方法在類的內(nèi)部、外部能夠使用,也能繼承
保護(hù) - 保護(hù)的屬性和方法在類的內(nèi)部能夠使用,外部不能使用,可以被繼承
私有 - 私有的屬性和方法只能在類的內(nèi)部使用,外部不能使用,也不能被繼承
2.python中屬性和方法的訪問權(quán)限
python類中所有的屬性和方法本質(zhì)都是公開的;私有化是假的私有化,只是提示程序員這個(gè)屬性和方法在外部不能使用,也不能被繼承
在需要私有化的屬性名或者方法名前加'__'(不能以'__'結(jié)尾)
python私有化的原理:在私有的屬性和方法前加了'_類名'
class Person:
__num = 61
def __init__(self, name, age):
self.name = name
self.__age = age
self.func1()
def eat(self, food='米飯'):
print('%s吃%s' % (self.name, food))
print('內(nèi)部num', self.__num)
self.func1()
def func1(self):
print('函數(shù)')
print('內(nèi)部age:', self.__age)
def __func2(self):
print('私有函數(shù)')
p1 = Person('小明', 20)
# print(Person.num, p1.name, p1.age)
# p1.eat()
# print(p1.__num) # AttributeError: type object 'Person' has no attribute 'num'
# p1.eat('西瓜')
# p1.func2() # AttributeError: 'Person' object has no attribute 'func2'
p1.eat()
p1.func1()
print(Person.__dict__)
print(p1.__dict__)
# print(p1._Person__age) # 不建議使用
"""
函數(shù)
內(nèi)部age: 20
小明吃米飯
內(nèi)部num 61
函數(shù)
內(nèi)部age: 20
函數(shù)
內(nèi)部age: 20
{'__module__': '__main__', '_Person__num': 61, '__init__': <function Person.__init__ at 0x0000000002784EE8>, 'eat': <function Person.eat at 0x0000000002784F78>, 'func1': <function Person.func1 at 0x000000000278E048>, '_Person__func2': <function Person.__func2 at 0x000000000278E0D8>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__': None}
{'name': '小明', '_Person__age': 20}
"""
三、屬性的getter和setter
1.什么是getter和setter
當(dāng)我們需要在獲取屬性值之前做點(diǎn)別的事情就需要給這個(gè)屬性添加getter
當(dāng)我們需要給屬性值賦值之前做點(diǎn)別的事情,就需要給這個(gè)屬性添加setter
2.給屬性添加getter
1)屬性命名的時(shí)候在前面加一個(gè)下劃線_
2)在@property裝飾器的后面聲明一個(gè)對(duì)象方法
a. 將屬性去掉下劃線作為方法名
b.方法除了self外不需要其他參數(shù)
c.函數(shù)的返回值就是獲取這個(gè)屬性的時(shí)候得到的值
3)在外部使用屬性的時(shí)候,通過對(duì)象.不帶下劃線的屬性去使用
注意:獲取屬性值的時(shí)候,就會(huì)自動(dòng)調(diào)用getter對(duì)應(yīng)的函數(shù)
3.給屬性添加setter
屬性添加setter之前必須先添加getter
1)保證屬性名前有一個(gè)_
2)在@getter名.setter后面聲明函數(shù)
a.將屬性去掉下劃線作為方法名
b.需要一個(gè)self以外的參數(shù)
c.不需要返回值
3)在外部使用屬性的時(shí)候,通過'對(duì)象.不帶下劃線的屬性'去使用
注意:當(dāng)給屬性賦值的時(shí)候,實(shí)質(zhì)是調(diào)用setter對(duì)應(yīng)的方法
class Person:
count = 0
def __init__(self, name, age, gender):
self.name = name
self._age = age
self._gender = gender
self._week = 0
# 添加getter
@property
def week(self):
if self._week == 0:
return '星期天'
if self._week == 1:
return '星期一'
if self._week == 2:
return '星期二'
if self._week == 3:
return '星期三'
if self._week == 4:
return '星期四'
if self._week == 5:
return '星期五'
if self._week == 6:
return '星期六'
# return 'abc'
# return self._week
@property
def age(self):
Person.count += 1
print('年齡值被訪問!', Person.count)
return self._age
@age.setter
def age(self, value):
print('年齡值被修改?。。?)
if not isinstance(value, int):
raise ValueError
if not 0 <= value <= 200:
raise ValueError
# print('~~~~~~~')
# print('value: ', value)
self._age = value
@property
def gender(self):
# return self._gender
if self._gender == 1:
return '女'
if self._gender == 0:
return '男'
@gender.setter
def gender(self):
return ValueError
p1 = Person('小米糕', 18, '女')
# p1.age = 1908
# p1.age = 'abc'
# print(p1.name, p1.age, p1.gender, p1.week)
print(p1.week) # 這兒實(shí)質(zhì)就是在調(diào)用week方法獲取返回值
p2 = Person('小花', 20, '男')
print(p1.age) # p1.age()
age1 = p1.age
print(p2.age) # p2.age()
p1.age = 200 # p1.age(200)
"""
星期天
年齡值被訪問! 1
18
年齡值被訪問! 2
年齡值被訪問! 3
20
年齡值被修改?。?!
"""
練習(xí):寫一個(gè)矩形類
有屬性:長、寬、面積和周長
要求從生活的角度看這個(gè)矩形
class WriteError(Exception):
def __str__(self):
return '修改只讀屬性'
class Rect:
def __init__(self, width, length):
self._width = width
self._length = length
self._area = 0
self._perimeter = 0
@property
def length(self):
return self._length
@length.setter
def length(self, value):
if not isinstance(value, int) and not isinstance(value, float):
raise ValueError
if value < 0:
raise ValueError
self._length = value
@property
def width(self):
return self._width
@width.setter
def width(self, value):
if not isinstance(value, int) and not isinstance(value, float):
raise ValueError
if value < 0:
raise ValueError
self._width = value
@property
def area(self):
self._area = self._length * self._width
return self._area
@area.setter
def area(self, value):
raise WriteError
@property
def perimeter(self):
self._perimeter = 2 * (self._length + self._width)
return self._perimeter
@perimeter.setter
def perimeter(self, value):
raise WriteError
rect1 = Rect(1, 2)
print(rect1.area)
print(rect1.perimeter)
rect1.length = 3
print(rect1.area)
print(rect1.perimeter)
# rect1.area = 22
# print(rect1.area)
"""
2
6
3
8
"""
####四、類方法和靜態(tài)方法
######1.類中的函數(shù)
類中的方法分為:對(duì)象方法、類方法、靜態(tài)法
1)對(duì)象方法
a.怎么聲明:直接聲明
b.怎么調(diào)用:用對(duì)象來調(diào)用
c.特點(diǎn):有指向當(dāng)前對(duì)象的`self`
d.什么時(shí)候用:如果實(shí)現(xiàn)函數(shù)的功能需要用到對(duì)象屬性,就是引用對(duì)象方法
2)類方法
a.怎么聲明:聲明在@classmethod后面
b.怎么調(diào)用:用類來調(diào)用,`類.類方法()`
c.特點(diǎn):有自帶的參數(shù)`cls`,表示當(dāng)前類;這個(gè)參數(shù)在調(diào)用的時(shí)候不用傳參,系統(tǒng)會(huì)自動(dòng)將當(dāng)前類傳給它;
`cls`:誰調(diào)用就指向誰(如果是對(duì)象指向的是對(duì)象對(duì)應(yīng)的類)
d.什么時(shí)候用:如果實(shí)現(xiàn)函數(shù)的功能不需要屬性對(duì)象屬性,但需要類的字段,就使用類方法
3)靜態(tài)方法
a.怎么聲明:聲明在@staticmethod的后面
b,怎么調(diào)用:通過類來調(diào)用,`類.靜態(tài)方法()`
c.特點(diǎn):沒有默認(rèn)參數(shù)
d.什么時(shí)候用:實(shí)現(xiàn)函數(shù)的功能既不需要類又不需要對(duì)象額,就是用靜態(tài)方法
```python
class Person:
num = 61
def __init__(self, name: str, age: int, gender: str):
self.name = name
self.age = age
self.gender = gender
def eat(self, food: str):
# 對(duì)象能做的事情,self都能做
print(self.name + '在吃' + food)
@classmethod
def func1(cls):
# 類能做的事情,cls都能做
print(cls)
t = cls('a', 10, '男')
print('t:', t)
print(cls.num)
print('這是一個(gè)類方法!')
@staticmethod
def func2():
print('這是一個(gè)靜態(tài)方法!')
def func3(self):
print('這是一個(gè)函數(shù)!', self.name)
def func4(self):
print(self.age, Person.num)
print(Person)
Person.func1()
p1 = Person('西西里', 90, '女')
p1.func1()
Person.func2()
p1.func3()
p1.func4()
print('=' * 60)
class Student(Person):
num = 10
print('====================1============================')
Student.func1()
Person.func1()
print('====================2============================')
Student.func2()
Person.func2()
"""
<class '__main__.Person'>
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD388>
61
這是一個(gè)類方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD408>
61
這是一個(gè)類方法!
這是一個(gè)靜態(tài)方法!
這是一個(gè)函數(shù)! 西西里
90 61
============================================================
====================1============================
<class '__main__.Student'>
t: <__main__.Student object at 0x00000000027FD408>
10
這是一個(gè)類方法!
<class '__main__.Person'>
t: <__main__.Person object at 0x00000000027FD448>
61
這是一個(gè)類方法!
====================2============================
這是一個(gè)靜態(tài)方法!
這是一個(gè)靜態(tài)方法!
"""
五、繼承
1.什么是繼承
繼承就是讓子類直接擁有父類的屬性和方法
子類 —— 繼承者
父類 / 超類 —— 被繼承著
2.怎么繼承
1)語法
class 類名(父類1, 父類2, ...):
說明文檔
類的類容
2)說明
() —— 固定寫法,如果省略相當(dāng)于(object)
聲明類的時(shí)候如果沒有寫父類,默認(rèn)繼承object(object又叫基類)
父類 —— 一個(gè)類的分類可以有多個(gè),一般情況下只有一個(gè)(支持多繼承)
class Person:
num = 61
def __init__(self):
print('Person中的init')
self.name = '小明'
self.age = 18
self.gender = '男'
self.__a = 12
def eat(self, food='米飯'):
print('{}在吃{}'.format(self.name, food))
@classmethod
def show(cls):
print('人類的數(shù)量:%d' % cls.num)
@staticmethod
def func1():
print('人類')
def func2(self):
print('我是' + self.name)
class Student(Person):
num = 10 # 重寫
def __init__(self):
print('Student中的init')
self.study_id = '001'
self.classes = 'py'
# 在子類中添加對(duì)象屬性,需要先通過super去調(diào)用父類的__init__來繼承父類的對(duì)象屬性
super().__init__()
@staticmethod
def func1():
print('學(xué)生')
def func2(self):
print('我是學(xué)生')
# 在子類中可以通過super方法可以去調(diào)用父類的方法
# 注意:super()只能在對(duì)象方法和類方法中使用,靜態(tài)方法用不了
super(Student, self).func2()
# 添加功能
def study(self):
print(self.name + '在好好學(xué)習(xí)!')
stu1 = Student()
print(stu1.num)
print(stu1.name, stu1.age, stu1.gender)
stu1.eat()
Student.show()
print(stu1.__dict__)
stu1.func1()
stu1.func2()
# import sys
# print(sys.stdout.flush())
"""
Student中的init
Person中的init
10
小明 18 男
小明在吃米飯
人類的數(shù)量:10
{'study_id': '001', 'classes': 'py', 'name': '小明', 'age': 18, 'gender': '男', '_Person__a': 12}
學(xué)生
我是學(xué)生
我是小明
"""
``