欢迎食用『主界面』~,这里是赵苦瓜的看板娘desu~

#
【点滴记录】Python进阶——类和实例、面向对象
首页 > 点滴记录    作者:赵苦瓜   2020年12月21日 16:57 星期一   热度:1520°   百度已收录  
时间:2020-12-21 16:57   热度:1520° 

Python基础部分已经学了一点了。接下来就是进阶部分。

众所周知,Python是面向对象的编程。本篇就来记录Python是如何面向对象的。


我是跟着慕课课程:https://www.imooc.com/learn/1264进行学习的。


第二章  Python面向对象编程


2-2 Python类的定义与实例化

Python中通过class定义一个类。按照编程习惯通常命名类时首字母大写。

class Person:  pass
上述定义没有继承任何类。还有以下两种定义方式:


 class Person(): pass 
 class Person(object):  pass
Python3中,这三种方式是没有区别的。


但是在Python2中,对于第一种定义的方法,Person类只有有限的几个内建函数'__doc__', '__module__', 'name',而对于第二种、第三种定义的方法,则会继承Python object对象的更多的内建函数,可以更便捷的操作对象。

定义完类就可以对它进行实例化了。实例化好比把抽象的类,赋予实物的过程。

创建实例使用  类名+()  类似于函数调用

class Person(object):  pass
xiaohong = Person()
xiaoming = Person()
2-3 Python实例属性的定义

前面创建的xiaohong和xiaoming可以通过以下方式赋予属性。

xiaohong.name = 'xiaohong'
xiaohong.sex = 'girl'
xiaohong.age = 13

print(xiaohong.name)
print(xiaohong.sex)
print(xiaohong.age)
除此之外,这些属性也可以当成普通变量进行运算。

xiaohong.age = xiaohong.age + 1

2-4 Python实例属性的初始化

定义属性时使用了不同的属性名字,如性别分别使用了sex和gender,后期维护就不方便。

抽象一个类时,应当包含基本属性信息。

比如在定义 Person 类时,可以为Person类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用(也就是说我们可以在这个方法里面写一些其它的东西,比如自动计数),我们就能在此为每个实例都统一加上以下属性:

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


__init__()方法的第一个参数习惯上都用self,后续参数可以自由指定,和定义函数没有区别。

之后实例化对象时需要提供除self以外的所有参数。

xiaoming = Person('Xiao Ming', 'boy', 13)
xiaohong = Person('Xiao Hong', 'girl', 14)
访问和使用和之前一样。但是访问不存在的属性会报错。



2-5 Python类属性

如果类上绑定一个属性,所有实例都可以访问类的属性,而且都是同一个。

类属性可以直接在calss中定义。

class Animal(object):
    localtion = 'Asia'
    def __init__(self, name, age):
        self.name = name
        self.age = age
dog = Animal('wangwang', 1)
cat = Animal('mimi', 3)
print(dog.localtion) # ==> Asia
print(cat.localtion) # ==> Asia
# 类属性,也可以通过类名直接访问
print(Animal.localtion) # ==> Asia
类属性也可以动态添加和修改。因为类属性只有一份,所以改变了,所有的实例访问都会变更。


2-6 类属性和实例属性的优先级

在类属性和实例属性同名并同时存在的情况下,实例属性的优先级要高于类属性。

比如类属性和实例属性都有location,类属性是Asia,实例属性是Guangdong,这时候实例.location就是Guangdong

不能通过实例修改类属性!!可能会引发各种错误!

这种只是给实例新增了一个实例属性。


2-7 Python中的访问限制

并不是所有属性都可以被外部访问。不能被外部访问的属性称为私有属性。

私有属性以双下划线__开头

# 类私有属性
class Animal(object):
    __localtion = 'Asia'

print(Animal.__localtion)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Animal' has no attribute '__localtion'


# 实例私有属性
class Animal(object):
    def __init__(self, name, age, localtion):
        self.name = name
        self.age = age
        self.__localtion = localtion dog = Animal('wangwang', 1, 'GuangDong')
print(dog.name) # ==> wangwang
print(dog.age) # ==> 1
print(dog.__localtion)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Animal' object has no attribute '__localtion'
外部访问私有属性将抛出异常,但是从类的内部是可以访问的。



2-8 定义实例的方法

通过定义实例的方法可以操作私有属性。

class Person(object):

    def __init__(self, name):
        self.__name = name  def get_name(self):
        return self.__name
name是实例的私有属性,从外部是无法访问的,而get_name(self) 就是一个实例方法,在实例方法里面是可以操作私有属性的,注意,它的第一个参数是self。


实例方法需要在class中定义!!

外部调用实例方法时不需要显示传递self参数。

p = Person('Alice')
print(p.get_name()) # ==> Alice
使用实例方法来操作私有属性非常方便。实例方法也可以抽象有关类和实例的操作。



2-9 Python定义类方法

类方法也要在class中定义。在类方法前面要写上:

@classmethod

来注明是类方法,否则将被定义为实例方法。

类方法第一个参数,通常命名为cls

class Animal(object):
    __localtion = 'Asia'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    @classmethod
    def set_localtion(cls, localtion):
        cls.__localtion = localtion

    @classmethod
    def get_localtion(cls):
        return cls.__localtion

print(Animal.get_localtion()) # ==> Asia
Animal.set_localtion('Afica')
print(Animal.get_localtion()) # ==> Africa


3-2 Python继承类



Python GUI时钟

# coding=utf-8
from tkinter import *
import _tkinter
import math
import time
from threading import Thread
class Clock:
  def __init__(self, master, x, y, width, height, radius):
    '''
    :param master: 父窗口
    :param x: 时钟中心点的x坐标
    :param y: 时钟中心点的y坐标
    :param width: 画布的宽度
    :param height: 画布的高度
    :param radius: 时钟钟盘的半径
    '''
    self.centerX = x
    self.centerY = y
    self.radius = radius
    self.canvas = Canvas(master, width=width, height=height) # 画布
    self.canvas.pack()
    self.canvas.create_line(100,40,300,40,width=3)
    self.canvas.create_line(300,40,390,213,width=3)
    self.canvas.create_line(100,40,10,213,width=3)
    self.canvas.create_line(10,213,100,380,width=3)
    self.canvas.create_line(100,380,300,380,width=3)
    self.canvas.create_line(390,213,300,380,width=3)
    # self.canvas.create_oval(x - radius,y - radius,x + radius,y + radius) # 画钟框
    self.id_lists = []
    self.hourHandRadius = self.radius * 1.0 / 4  # 指针长度
    self.minHandRadius = self.radius * 2.0 / 3  # 分针长度
    self.secHandRadius = self.radius * 4.0 / 5  # 秒针长度
    self.timeVar = StringVar()
    # self.timeVar.set('')
    self.timeLabel = Label(self.canvas.master, textvariable=self.timeVar)
    self.timeLabel.pack(side=BOTTOM)
    #self.canvas.master.protocol('WM_DELETE_WINDOW', self.canvas.master.destroy)
  def __del__(self):
    self._deleteItems(self.id_lists)
  # 绘制时钟钟盘
  def drawClockDial(self):
    # 绘制钟盘上的数字1-12
    r = self.radius - 15
    for i in range(1, 13):
      rad = 2 * math.pi / 12 * i
      x = self.centerX + math.sin(rad) * r
      y = self.centerY - math.cos(rad) * r
      id = self.canvas.create_text(x, y, text=str(i))
      self.id_lists.append(id)
    # 绘制钟盘上的刻度
    r1 = self.radius - 5
    r2 = self.radius
    for i in range(1, 61):
      rad = 2 * math.pi / 60 * i
      x1, y1 = self._getPosByRadAndRadius(rad, r1)
      x2, y2 = self._getPosByRadAndRadius(rad, r2)
      id = self.canvas.create_line(x1, y1, x2, y2)
      self.id_lists.append(id)
  # 显示时间
  def showTime(self, tm):
    hour = tm.tm_hour % 12
    min = tm.tm_min
    sec = tm.tm_sec
    sec_rad = 2 * math.pi / 60 * sec
    min_rad = 2 * math.pi / 60 * (min + sec / 60.0)
    hour_rad = 2 * math.pi / 12 * (hour + min / 60.0)
    timeStr = '当前时间: %d-%02d-%02d %02d:%02d:%02d' % (
      tm.tm_year, tm.tm_mon, tm.tm_mday, hour, min, sec)
    self.timeVar.set(timeStr)
    hour_id = self._drawLine(hour_rad, self.hourHandRadius, 6)
    min_id = self._drawLine(min_rad, self.minHandRadius, 4)
    sec_id = self._drawLine(sec_rad, self.secHandRadius, 3)
    return (hour_id, min_id, sec_id)
  def run(self):
    def _run():
      while True:
        tm = time.localtime()
        id_lists = self.showTime(tm)
        self.canvas.master.update()
        time.sleep(1)
        self._deleteItems(id_lists)
    thrd = Thread(target=_run) # 创建新的线程
    thrd.run() # 启动线程
  def _drawLine(self, rad, radius, width):
    x, y = self._getPosByRadAndRadius(rad, radius)
    fill = 'black' if width==3 else 'green' if width==4 else 'red'
    id = self.canvas.create_line(
      self.centerX, self.centerY, x, y, width=width, fill=fill)
    return id
  def _getPosByRadAndRadius(self, rad, radius):
    x = self.centerX + radius * math.sin(rad)
    y = self.centerY - radius * math.cos(rad)
    return (x, y)
  def _deleteItems(self, id_lists):
    for id in id_lists:
      try:
        self.canvas.delete(id)
      except BaseException:
        pass
if __name__ == '__main__':
  root = Tk()
  root.title('赵苦瓜的Python时钟')
  clock = Clock(root, 200, 200, 400, 400, 150)
  clock.drawClockDial()
  clock.run()
  root.mainloop()





本文作者:赵苦瓜      文章标题: 【点滴记录】Python进阶——类和实例、面向对象
本文地址:https://blog.jixiaob.cn/?post=32
版权声明:若无注明,本文皆为“赵苦瓜のBlog~”原创,转载请保留文章出处。

返回顶部    首页    后花园  
版权所有:赵苦瓜のBlog~    站长: 赵苦瓜    程序:emlog   鲁ICP备20030743号-1   鲁公网安备37048102006726 萌ICP备20222268号    sitemap