day18

day18

1.静态方法和类方法

"""
之前我们在类中定义的方法都是对象方法,换句话说这些方法都是对象可以接收的消息。除了对象方法外,类中还可以有静态方法和类方法,者两类方法时发给类的消息,二者并没有实质性的区别,在面向对象的世界里,一切皆为对象,我们定义的每一个类其实就是一个对象,而静态方法和类方法就是发送给类对象的消息
"""       
import math
# 定义类,描述平面上的点,提供移动点,计算一个点到另一个点的距离的方法
class Point:
    """点"""
    
    def __init__(self, x, y):
        """
        计算两点之间的距离
        :param other: 另外一个点的坐标
        :return: 两点间的距离
        """
        self.x = x
        self.y = y
    def distance(self, other):
        return math.sqrt((self.x - other.x) ** 2 + (self.y - other.y) ** 2)
    
    def move_to(self, x, y):
         """
        移动点
        :param x:移动到那点的横坐标
        :param y: 移动到那点的纵坐标
        :return: None
        """
        self.x = x
        self.y = y
    def move_by(self, dx, dy):
         """
        偏移
        :param dx: 横坐标的偏移量
        :param dy: 纵坐标的偏移量
        :return: None
        """
        self.x += bx
        self.y += by
        
     def __repr__(self):
        return f'<{self.x}, {self.y}>'
  # 定义类描述平面上的线段,提供计算线段的长度,判断一个线段与另一个线段是否相交

class Line:
    """线段"""
    def __init__(self, start:Point, end:Point):
        """
       初始化方法
       :param start: 开始点
       :param end: 结束点
       """
        self.start = start
        self.end = end
        
    def length(self):
        """
        计算线段长度
        :return: 线段长度
        """
        return self.start.distance(self.end)
    
    def intersected(self, other):
         """
        判断两线段是否相交
        :param other: 另一条线段
        :return: 两线段是否相交
        """
        sx1,sy1,ex1,ey1 = self.start.x, self.start.y, self.end.x, self.end.y
        sx2,sy2,ex2,ey2 = other.start.x, other.start.y,other.end.x,self.end.y
             # 德摩根率来判断,当一条线段的最大的横坐标小于另一条线段最小的横坐标,或者一条线段的的最大的纵坐标小于另一条线段的最小的纵坐标,这两条线段一定不相交
        
        return not(
        	max(sx1, ex1) < min(sx2, ex2) or
            max(sx2, ex2) < min(sx1, ex1) or
            max(sy1, ey1) < min(sy2, ey2) or
            max(sy2, ey2) < min(sy1, ey1)
        )

# 定义三角形类,判断三条线是否能组成三角形,求面积方法 
# 静态方法:不是三角形对象的消息,而是发给三角形类的消息 - @staticmethod
# Triangle.is_triangle()
# 类方法:发给类的消息(比静态方法多一个参数,代表接收消息的类) - @classmethod
class Triangle:
    
    def __init__(self, line1:Line, line2:Line, line3:Line):
        self.line1 = line1
        self.line2 = line2
        self.line3 = line3
    # 发给类的消息
    @classmethod
    def is_valid_sides(cls, line1, line2, line3):
        return line3+line2>line1 and line1+line3>line2 and line1+line2>line3
    @staticmethod
    def is_triangle(line1, line2, line3):
        return line3+line2>line1 and line1+line3>line2 and line1+line2>line3
    def perimerter(self):
        p = self.line1 + self.line2 + self.line3
        return p
    def area(self):
        a, b, c = self.line1, self.line2, self.line3
        p = (a+b+c)/2
        return math.sqrt(p(p-a)(p-b)(p-c))

p1 = Point(3, 5)
p2 = Point(6, 1)
print(p1, p2)
print(f'两点距离:{p1.distance(p2):.2f}')
p1.move_to(0, 0)
p2.move_by(1, -1)
print(p1, p2)
print(p1.distance(p2))
line1 = Line(p1, p2)
print(line1.length())
p3 = Point(-1, -2)
p4 = Point(6, 2)
line2 = Line(p3, p4)
print(line1.instersected(line2))
p3.move_to(4, 5)
print(line1.intersected(line2))

p1 = Point(0, 0)
p2 = Point(3, 0)
p3 = Point(3, 4)
l1 = Line(p1, p2).length()
l2 = Line(p1, p3).length()
l3 = Line(p2, p3).length()
s1 = Triangle(l1, l2, l3)
print(s1.perimeter())

def main():
    line1, line2, line3 = map(float, input('请输入三条边的长度').split())
    if Triangle.is_triangle(line1, line2, line3):
        tri = Triangle(line1, line2, line3)
        print(f'三角形的周长:{tri.perimeter()}')
        print(f'三角形的面积:{tri.area()}')
    else:
        print('构不成三角形')
if __name__ == '__main__':
    main()

​ 上面的三角形类Triangle使用了staticmethod装饰器说明了is_triangle方法是Triangle类的静态方法,如果要声明类方法,可以使用classmethod装饰器。可以直接使用类名.方法名的方式来调用静态方法和类方法,二者的区别在于,类方法的第一个参数就是“类对象本身”,而静态方法则没有这个参数,总而言之,对象方法、类方法、静态方法都可以通过“类名.方法名”的方式来调用,区别在于方法的第一个参数到底是普通对象还是类对象,还是没有接受消息的对象。静态方法通常可以直接写成一个独立的函数,因为它并没有跟特定的对象绑定。

# 倒计时
import time

class CountDownClock:
    """倒计时"""
    def __init(self, hour, minute, second):
        """
        初始化方法
        
        """
        self.hour = hour
        self.minute = minute
        self.second = second
        
    def show(self):
        """显示时间"""
        return f'{self.hour:0>2d}:{self.minute:0>2d}:{self.second:0>2d}'
    
    def is_over(self):
        """判断倒计时是否结束"""
        return self.hour == 0 and self.minute == 0 and self.second == 0
    
    def run(self):
        "倒计时"
        if not self.is_over():
            self.second -= 1
            if self.second < 0:
                self.minute -= 1
                self.second = 59
                if self.minute < 0:
                    self.hour -= 1
                    self.minute = 59
clock = CountDownClock(1, 0, 1)
print(clock.show())
while not clock.is_over:
    print(clock.show())
    time.sleep(1)
    clock.run()
print('倒计时结束,时间到!') 

注意:

# __repr__()方法
"""
通常情况下,我们经常直接输出类的实例化对象,例如:
class CLanguage:
    pass
clangs = CLanguage()
print(clangs)
程序运行结果为:
<__main__.CLanguage object at 0x000001A7275221D0>
通常情况下,直接输出某个实例化对象,本意往往是想了解该对象的基本信息,
例如该对象有哪些属性,他们的值各是多少等等,但是在默认情况下,
我们得到的信息只会是”类命+object at+内存地址“,对我们了解实例化对象帮助不大

而我们可以通过”重写类__repr__()方法“就可以自定义输出实例化对象时的信息了,
事实上,当我们输出某个实例化对象时,其调用的就是该对象的__repr__()方法,输出的时该方法的返回值

其实上面的print(clangs)等同于执行print(clangs.__repr__()),程序的输出是一样的(地址可能不同)
和__init__(self)的性质一样,python中的每个类都包含__repr__()方法, 因为object类   
包含__repr__()方法,而python中所有类都直接或间接继承自object类

默认情况下,__repr__()会返回和调用者有关的”类名+object at+内存地址“信息,当然,我们可以通过在类中重写这个方法,
从而实现当输出实例化对象时,输出我们想要的信息

例如:
class CLanguage:
    def __init__(self):
       self.name = 'C语言'
       self.add = "http://c.biancheng.net"
    def __repr__(self):
        return f'CLanguage name={self.name}, add={self.add}'
    
clangs = CLanguage()
print(clangs)
程序运行结果为:
CLanguage name=C语言, add=http://c.biancheng.net
由此可见,__repr__() 方法是类的实例化对象用来做“自我介绍”的方法,
默认情况下,它会返回当前对象的“类名+object at+内存地址”,而如果对该方法进行重写,可以为其制作自定义的自我描述信息
"""
# 扑克游戏, 里面有那些类?对应的对象有哪些属性和方法
# 名词一般代表的时类和属性,动词是方法
import random
"""
类:牌,扑克,玩家
牌:属性:花色/点数
	方法:显示牌面
扑克:属性:转54张牌的列表
	方法:洗牌,发牌
玩家:属性:id , 昵称:手牌(列表)
	方法:摸牌、打牌、整理手牌
"""
# 经验:符号常量总是优于字面常量!!!
# 通过将变量名大写告诉别人不要改它,表示常量
# space:黑桃  heart: 红心  club:梅花  diamond:方块
SPADE, HEART, CLUB, DIAMODN = range(4)

# 牌类
class Card:

    def __init__(self, suite, face):
        self.suite = suite
        self.face = face

    def __repr__(self):    # 返回你想要看到的自定义的格式
        return self.show()

    # less than --> __lt__ ---> <
    # great than --__gt__ ---> >
    # equal to --> __eq__ --> ==
    # great equal --> __ge__ --> >=
    # less equal --> __le__ --> <=
    def __lt__(self, other):
        if self.suite != other.suite:
            return self.suite < other.suite
        face1 = 14 if self.face == 1 else self.face
        face2 = 14 if other.face == 1 else other.face
        return self.face < other.face

    def show(self):
        """显示牌面"""
        suites = ('♠', '♥', '♣', '♦')
        faces = ('', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K')
        return f'{suites[self.suite]}{faces[self.face]}'


class Poker:
    """扑克"""

    def __init__(self):
        self.cards = [Card(suite, face)
                      for suite in range(4)
                      for face in range(1, 14)]
        self.index = 0

    # 洗牌,随机乱序
    def shuffle(self):
        """洗牌"""
        self.index = 0
        random.shuffle(self.cards)

    # 判断是否还有牌
    def has_more(self):
        """有没有牌可以发出"""
        return self.index < len(self.cards)

    # 发牌
    def deal(self):
        """发牌"""
        card = self.cards[self.index]
        self.index += 1
        return card


class Player:
    """玩家"""
    def __init__(self, nickname):
        """
        初始化方法
        :param nickname: 昵称
        """
        self.nickname = nickname
        self.cards = []

    def get_card(self, card):
        """摸牌"""
        self.cards.append(card)
    # 整理手牌第一种方法
    def arrange(self):
        """整理手牌"""
        # 第一种:列表的sort方法可以传入Key参数,来指定根据什么比较元素的大小
        # self.cards.sort(key=lambda x: x.face)   # 比较的是牌的点数
        # self.cards.sort(key=lambda x: x.suite)   # 比较的是牌的花色
        self.cards.sort()


poker = Poker()
poker.shuffle()
names = ('妲己', '狄仁杰', '赵云', '孙悟空')  # 玩家昵称
players = [Player(name) for name in names]
for _ in range(13):
    for player in players:
        card = poker.deal()
        player.get_card(card)

for player in players:
    player.arrange()
    print(player.nickname, end=':')
    print(player.cards)

2.继承

继承:通过已有的类创建新的类,子类会得到父类的继承信息,父类提供继承信息(基类、超类),公共的部分放在父类中,特有的部分写在子类中,子类通过继承父类,得到那些公共的部分

单一继承:一个类只能有一个父亲,建议大家一个类只有一个父亲

# 学生:姓名/年龄/年级;吃饭/玩耍/学习
# 老师:姓名/年龄/职称;吃饭/玩耍/授课
class Person:   # 父类

    def __init__(self, name, age):
        """初始化方法
        :param name: 姓名
        :param age: 年龄
        :param grade: 年级
        """
        self.name = name
        self.age = age

    def eat(self):
        """吃饭"""
        print(f'{self.name}正在吃饭.')

    def play(self):
        """玩耍"""
        print(f'{self.name}正在玩耍.')


# 子类:得到继承信息的(衍生类)
# python语言允许多重继承,一个类可以有多个父类
class Student(Person):    # 子类(父类)
    """学生"""

    def __init__(self, name, age, grade):
        """初始化方法
        :param name: 姓名
        :param age: 年龄
        :param grade: 年级
        """
        super().__init__(name, age)   # 继承的固定写法
        self.grade = grade

    def study(self, course_name):
        """学习
        :param course_name: 课程名称
        """
        print(f'{self.name}正在学习{course_name}.')


# 单一继承:一个类只能有一个父类,建议大家一个类只有一个父类
# 公共的部分放在父类中,特有的部分写在子类中,子类通过继承父类,得到那些公共的部分,继承也是一种复用代码的方式
class Teacher(Person):    # 继承:通过已有的类创建新的类 ,子类会得到父类的继承信息,父类提供继承信息的(基类、超类)

    def __init__(self, name, age, title):
        """
        初始化方法
        :param name: 老师名字
        :param age: 年龄
        :param title: 职称
        """
        super().__init__(name, age)
        self.title = title

    def teach(self, course_name):
        """授课
        :param course_name: 课程名称
        """
        print(f'{self.name}正在上课{course_name}.')


student = Student('王大锤', 18, '大一')
teacher = Teacher('络昊', 41, '教授')
student.play()
teacher.teach('python程序设计')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值