日拱一卒之Python3:类方法

1.__slots__用法

Python允许在定义class的时候,定义一个特殊的“__slots__”变量,来限制该class能添加的属性。在如下示例中,我们可以对自定义的Solution函数类用 __slots__ 添加 age 、name、color 属性后再调用类内函数。

class Solution():
    __slots__ =  'age','color','name'
    def __init__(self,age,name,color):
        self.age = age
        self.name = name
        self.color=color

    def some_info(self):
        print ( self.age,self.name,self.color)

正确的输入会顺利地返回类内函数的调用结果:

另一方面也就是说,一旦在实例化的过程中,输入参数超过了__slots__下添加的参数量限制就会返回报错(这里的哥哥是第四个参数,没在__slots__中有所涵盖):

可以把__slots__这个方法实现的功能理解为:将自由度更高的函数类对象,在“参数输入”书写限制的这个维度上和普通函数对象(也即不加入*args,**kargs参数的函数)等同了起来。

2.__lt__的用法

参考文章「__lt__,__gt__等“富比较”方法用途探析」,该方法是基类object提供一系列可以用于实现同类对象进行“比较”的方法,可以用于同类对象的不同实例进行比较。他们也是实例方法,以 “ object.lt(self, other) ”为例,其中self是指对象自身,other是参与比较的另一对象,返回值最好为bool值,也可以是任意值。

使用例参考题目「力扣_1792_最大通过率平均数」中前置的函数类定义代码:

class Entry:
    __slots__ = 'p', 't'

    def __init__(self, p: int, t: int):
        self.p = p
        self.t = t

    def __lt__(self, b: 'Entry') -> bool:
        return (self.t-self.p) * b.t * (b.t+1) > (b.t-b.p) * self.t * (self.t+1)

符号“ * ”与C++中的算符用法一样,支持查看对象地址的功能,故执行下述代码得到的返回如图:

'''输入参量c=[[1,2],[3,5],[2,2],[2,9]]...'''

h = [Entry(*c) for c in classes]
print(h,'\n','-----',h[0].p,'-----')

 

附注:富方法的使用方式,和C++编程方式类似

这些特殊方法除了直接调用(object.lt)外,当用运算符进行对象比较时也会被调用,运算符号与方法名称的对应关系如下:

x<y 调用 x.__lt__(y),

x<=y 调用 x.__le__(y),

x==y 调用 x.__eq__(y),

x!=y 调用 x.__ne__(y),

x>y 调用 x.__gt__(y),

x>=y 调用 x.__ge__(y),

另外值得一提得是,比较运算符之间没有其他隐含关系,例如 (x<y or x==y) 为真并不意味着 x<=y,具体要看实现的方法(因为__lt__等属性都是可以重写的)。

 

3.位运算性质一则

参考题目「力扣_89_格雷编码」,

  1. “ 1<<n ”在十进制表示下是“ 2的n次幂 ”
  2. “ ^ ”是取反符号,python中可以用 int("1101",2) bin(13) 两个内置函数来互相表出,想要快速理解其原理可以参照视频「位运算(第07题)交替位二进制数_哔哩哔哩_bilibili」;
  3. 本题写法的逻辑对应于“ 每次只有一个位发生变动:0 -> 1 或 1 -> 0 ”。
class Solution:
    def grayCode(self, n: int) -> List[int]:
        ans = [0] * (1 << n)
        for i in range(1 << n):
            ans[i] = (i >> 1) ^ i
        return ans

4.“动态规划+中心扩散”算法思想

参考题目「力扣_5_最长回文子串」,对这种四状态矩阵的题型印象比较深,类似复杂度的题目还有「力扣_123_买卖股票的最佳时机 III」、「力扣_1237_找出给定方程的正整数解」,突破理解桎梏的实用意义较大。

 附注:官解答案ver2

可以发现,所有的状态在转移的时候的可能性都是唯一的。也就是说,我们可以从每一种边界情况开始「扩展」,也可以得出所有的状态对应的答案。

边界情况即为子串长度为 1 或 2 的情况。我们枚举每一种边界情况,并从对应的子串开始不断地向两边扩展。如果两边的字母相同,我们就可以继续扩展,例如从P(i+1,j−1) 扩展到 P(i,j);如果两边的字母不同,我们就可以停止扩展,因为在这之后的子串都不能是回文串了。

「边界情况」对应的子串实际上就是我们「扩展」出的回文串的「回文中心」。方法二的本质即为:我们枚举所有的「回文中心」并尝试「扩展」,直到无法扩展为止,此时的回文串长度即为此「回文中心」下的最长回文串长度。我们对所有的长度求出最大值,即可得到最终的答案。

#官解ver2:动态规划+中心扩散,执行用时:67.34%,内存消耗:92.86%
#通过观察进一步建立"中心扩散关系":所有的状态在转移的时候的可能性都是唯一的。
#也即我们可以从每一种边界情况开始「扩展」,也可以得出所有的状态对应的答案
class Solution:
    def expandAroundCenter(self, s, left, right):
        while left >= 0 and right < len(s) and s[left] == s[right]:
            left -= 1
            right += 1
        return left + 1, right - 1

    def longestPalindrome(self, s: str) -> str:
        start, end = 0, 0
        for i in range(len(s)):
            left1, right1 = self.expandAroundCenter(s, i, i)
            left2, right2 = self.expandAroundCenter(s, i, i + 1)
            if right1 - left1 > end - start:
                start, end = left1, right1
            if right2 - left2 > end - start:
                start, end = left2, right2
        return s[start: end + 1]

✌,今天的“假把式”努力也告一段落了!对于算法的理解又加深了一点,接下来希望开发工作也可以这样推进,之后会把主要精力投放到平台开发的日志中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值