经验之二

1.类方法使用实例

class My(object):
    def __init__(self):
        self.__pri = 30

    @classmethod
    def get_pro(cls, instance):
        return instance.__pri


obj = My()
print(My.get_pro(obj))     类直接调用

30                         代码简单不做解释

私有属性别名访问法: 需指定包含此属性的类名才可获得
collections.abc 中的 Sequence 实现了 index 和 count 方法
需要则直接继承

可能更喜欢自己实现, 下面列举了自己实现的 index 和 count 方法
class Test(object):
    def __init__(self, number):
        self.number = number

    def index(self, value):
        for index, i in enumerate(self.number):
            if i == value:
                return index
        return 'value not exist'

    def count(self, value):
        d = {}
        d[value] = 0
        if value not in self.number:
            return 0
        for i in self.number:
            if i == value:
                d[value] += 1
        return d[value]


obj = Test([1, 2, 3, 4, 5])
print(obj.index(1))
print(obj.index(10))
print(obj.count(7))
print(obj.count(2))

0
value not exist
0
1

2.防止父类属性被修改

@property 可以为现有的实例属性添加新的功能
之前使用 setattr 方法实现禁止实例化对象属性值修改
现在使用 @property 和 @属性名.setter实现

class Father(object):
    def __init__(self, number):
        self._values = number


class Child(Father):
    def __init__(self, number):
        super().__init__(number)

    @property
    def values(self):
        return self._values

    @values.setter
    def values(self, number):
        if hasattr(self, '_values'):
            raise AttributeError('Can not set attribute')
        self._values = number


obj = Child(100)      这里注意名称对应
obj.values = 10       赋值操作会调用@values.setter
print(obj.values)     

AttributeError: Can not set attribute

3.原生 setattr 方法的工作方式

class Test(object):
    def __init__(self):
        self.grade = 0

    def __getattr__(self, name):
        value = 'hello'
        setattr(self, name, value)
        return value


obj = Test()        当找不到实例化对象的属性时就会调用__getattr__方法
print(obj.data)     原生 setattr 实现属性赋值
print(obj.grade)
print(obj.__dict__) 显示对象属性的 key, value值

hello
0                   属性赋值后则不会再次调用 __getattr__方法
{'grade': 0, 'data': 'hello'}

4.其他描述符方法
上述 __getattr__ 方法只调用了一次,若实现的是 __getattrbute__ 方法, 那么每次在对象上调用 hasattr 或 getattr 函数,此方法都会执行

hasattr 函数可以判断对象是否有某属性,此函数会先在实例字典中查找,再调用 __getattr__ 方法

访问属性时,必然会调用 __getattrbute__ 方法
若此方法会返回其他属性值,那么就会造成无限循环
解决办法是使用 super继承  (setattr方法设置属性值时也是如此)

代码如下

class Test(object):
    def __init__(self, data):
        self._data = data

    def __getattribute__(self, name):
      # return self._data[name]   会无限循环递归
        data_dict = super().__getattribute__('_data')
        return data_dict[name]


obj = Test({'like': 'you'})
print(obj.like)

you

5.用copyreg实现可靠的pickle操作

定义一个游戏类,有等级、生命等属性

import pickle

class Game(object):
    def __init__(self):
        self.level = 0
        self.lives = 3
       

state = Game()
state.lives -= 1
with open('test.txt', 'wb') as f:
    pickle.dump(state, f)           二进制存储并序列化

with open('test.txt', 'rb') as f:
    res = pickle.load(f)            反序列化,显示其实例字典
print(res.__dict__)

{'level': 0, 'lives': 2}

但是,游戏都会更新,假如我们现在需要添加一个 points 分数属性
直接在类中添加后,读取旧的保存文档会发现没有成功加入

class Game(object):
    def __init__(self, level=0, lives=3, points=5):
        self.level = level
        self.lives = lives
        self.points = points


with open('test.txt', 'rb') as f:       直接读取,并未重新存档
    res = pickle.load(f)
print(res.__dict__)

{'level': 0, 'lives': 2}               新属性未添加

解决办法–定义一个辅助函数

class Game(object):
    def __init__(self, level=0, lives=3, points=5):
        self.level = level
        self.lives = lives
        self.points = points


def pick_game(game_state):
    kwargs = game_state.__dict__
    return unpick_game, (kwargs,)       元组存储


def unpick_game(kwargs):                辅助函数
    return Game(**kwargs)


copyreg.pickle(Game, pick_game)          绑定
with open('test.txt', 'rb') as f:
    res = pickle.load(f)
print(res.__dict__)

{'level': 0, 'lives': 2, 'points': 5}

原因: 辅助函数会直接调用 Game 构造器, 使得反序列化后的实例其属性完备;
      若有参数缺失,对应属性则会获得相应默认值

6.一些捷径
First

堆队列
这些元素会按照优先级从高到低的顺序弹出(数值小则优先级高)

import heapq

a = []
heapq.heappush(a, 3)
heapq.heappush(a, 7)
heapq.heappush(a, 5)
print(heapq.heappop(a), heapq.heappop(a), heapq.heappop(a))

3 5 7

Second

bisect 模块采用二分搜索算法,其复杂度是对数级别
而 index 方法是线性级别,此算法会快很多

7.在重视精度的场合,使用 decimal

此类默认提供28个小数位
还有一个内置函数,使开发者自定义精度及舍入方式


假设一个用户打电话耗时3分10秒,每分钟1.3元,每次通话至少0.01元

from decimal import Decimal
rate = Decimal('1.30')
seconds = Decimal(3 * 60 + 10)
cost = seconds * rate / Decimal('60')
print(cost)

4.116666666666666666666666667



现在指定精度为0.01,话费不足0.01按0.01算

from decimal import Decimal, ROUND_UP
rate = Decimal('0.5')
seconds = Decimal('1')
cost = seconds * rate / Decimal('60')
round = cost.quantize(Decimal('0.01'), rounding=ROUND_UP)
print(round)           
                        不指定时结果小于0.01会被忽略
0.01                    指定精度0.01            
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值